Java基础进阶

news/2025/1/15 8:45:14/

Stream流

引例
需求:按照下面要求完成集合的创建和遍历
创建一个集合,存储多个字符串元素
1. 把所有以“曹”开头的元素存储到新集合中
2. 把曹开头,长度为3的元素存储到新集合中

 List<String> list = List.of("曹操", "曹孟德", "曹子恒", "曹子建", "司马懿", "司马师", "司马昭", "曹丕");// 1. 把所有以“曹”开头的元素存储到新集合中List<String> list1 = new ArrayList<>();for (String s : list) {if(s.startsWith("曹")){list1.add(s);}}System.out.println(list1);// 2. 把曹开头,长度为3的元素存储到新集合中List<String> list2 = new ArrayList<>();for (String s : list1) {if(s.length() == 3){list2.add(s);}}System.out.println(list2);

输出结果:

[曹操, 曹孟德, 曹子恒, 曹子建, 曹丕]
[曹孟德, 曹子恒, 曹子建]

上面太麻烦了
用Stream流只需要一行代码:

list.stream().filter(name -> name.startsWith("曹")).filter(name -> name.length() == 3).forEach(name -> System.out.println(name));
  • stream流的作用:结合Lamada表达式,简化集合、数组的操作
  • 使用步骤:
    • 先得到一条stream流,并把数据放上去

      获取方式方法名说明
      单列集合default Stream<E> stream()Collection中的默认方法
      双列集合无法直接使用Stream流,需要通过keySet()或entrySet()转换成单列集合
      数组public static<T> Stream stream(T[] array)Arrays工具类中的静态方法
      一堆零散数据public static<T> Stream of(T…values)Stream接口中的静态方法
    • 利用stream流中的API进行各种操作:(过滤,转换,统计,打印等等)

      • 中间方法:过滤、转换。方法调用完毕之后还可以调用其他方法
      • 终结方法:统计、打印。最后一步,调用完毕之后不能调用其他方法。
    • 使用中间方法对流水线上的数据进行操作

    • 使用终结方法对流水线上的数据进行操作

		//单列集合Stream流List<String> list = List.of("aa", "bb", "cc", "dd");list.stream().forEach(s -> System.out.println(s));//双列集合Stream流Map<String, String> map = Map.of("aa", "11", "bb", "22", "cc", "33");map.entrySet().stream().forEach(m -> System.out.println(m));//数组Stream流int[] arr = {1,2,3,4,5};Arrays.stream(arr).forEach(a -> System.out.println(a));//零散数据Stream流Stream.of(11,12,13,14,15).forEach(s -> System.out.println(s));

注意:Stream接口中静态方法of的细节:方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组,但数组必须是引用数据类型的,如果传递基本数据类型,会把整个数组当做一个元素传到Steam流中

		int[] arr1 = {1,2,3,4,5};String[] arr2 = {"a", "b", "c", "d", "e"};Stream.of(arr1).forEach(s -> System.out.println(s)); //输出[I@7699a589Stream.of(arr2).forEach(s -> System.out.println(s)); //输出a b c d e
  • Stream流的终结方法
    名称说明
    void forEach(Consumer action)遍历
    long count()统计
    toArray()收集流中的数据,放到数组中
    collect(Collector collrctor)收集流中的数据,放到集合中

1. forEach

返回值是void,因此是终结方法,不能再在后面调用函数

  • Consumer的泛型:表示流中数据的类型

    • accept方法得形态integer:依次表示流里面的每一个数据
    • 方法体:对每一个数据要做的操作(打印)
    		List<Integer> list = List.of(1,2,3,4,5);list.stream().forEach(new Consumer<Integer>() {@Overridepublic void accept(Integer integer) {System.out.println(integer);}});
    

2. long

返回值是long类型的整数,因此是终结方法

long c = list.stream().count();
System.out.println(c);

3. toArray()

  • 空参:返回值是object类型
			System.out.println("---------------------");Object[] arr1 = list.stream().toArray();        System.out.println(Arrays.toString(arr1));////IntFunction的泛型:具体类型的数组//apply的形态:流中数据的个数,要和数组长度保持一致//apply函数返回值:具体类型的数组//toArray方法的参数的作用:负责创建一个指定类型的数组//方法底层会依次得到流里面每一个数据,并把数据放到数组中//方法返回值:装着流里面所有数组的数组String[] arr = list.stream().toArray(new IntFunction<String[]>() {@Overridepublic String[] apply(int value) {return new String[0];}});//简化成Lamada表达式形式:list.stream().toArray(value -> new String[value]);
  • 有参:返回值是任意类型
    toArray方法的参数的作用:负责创建一个指定类型的数组
    方法底层会依次得到流里面每一个数据,并把数据放到数组中
    方法返回值:装着流里面所有数组的数组

    		//IntFunction的泛型:具体类型的数组//apply的形态:流中数据的个数,要和数组长度保持一致//apply函数返回值:具体类型的数组//toArray方法的参数的作用:负责创建一个指定类型的数组//方法底层会依次得到流里面每一个数据,并把数据放到数组中//方法返回值:装着流里面所有数组的数组String[] arr = list.stream().toArray(new IntFunction<String[]>() {@Overridepublic String[] apply(int value) {return new String[0];}});//简化成Lamada表达式形式:list.stream().toArray(value -> new String[value]);
    

4. collect

 /*collect(Collector collector)            收集流中的数据,放到集合中 (List Set Map)注意点:如果我们要收集到Map集合当中,键不能重复,否则会报错*/ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌-男-15", "周芷若-女-14", "赵敏-女-13", "张强-男-20","张三丰-男-100", "张翠山-男-40", "张良-男-35", "王二麻子-男-37", "谢广坤-男-41");//收集List集合当中//需求://我要把所有的男性收集起来List<String> newList1 = list.stream().filter(s -> "男".equals(s.split("-")[1])) //把"男"放前面防止list为null时调用equals报错.collect(Collectors.toList());//System.out.println(newList1);//收集Set集合当中//需求://我要把所有的男性收集起来Set<String> newList2 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());//System.out.println(newList2);//收集Map集合当中//谁作为键,谁作为值.//我要把所有的男性收集起来//键:姓名。 值:年龄Map<String, Integer> map = list.stream().filter(s -> "男".equals(s.split("-")[1]))/**   toMap : 参数一表示键的生成规则*           参数二表示值的生成规则** 参数一:*       Function泛型一:表示流中每一个数据的类型*               泛型二:表示Map集合中键的数据类型**        方法apply形参:依次表示流里面的每一个数据*               方法体:生成键的代码*               返回值:已经生成的键*** 参数二:*        Function泛型一:表示流中每一个数据的类型*                泛型二:表示Map集合中值的数据类型**       方法apply形参:依次表示流里面的每一个数据*               方法体:生成值的代码*               返回值:已经生成的值** */.collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {//张无忌-男-15return s.split("-")[0];}},new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s.split("-")[2]);}}));Map<String, Integer> map2 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toMap(s -> s.split("-")[0],s -> Integer.parseInt(s.split("-")[2])));System.out.println(map2);

toMap的一些底层代码在这里插入图片描述

在这里插入图片描述

总结:
  1. Stream流的作用

    结合了Lambda表达式,简化集合、数组的操作

  2. Stream的使用步骤
    获取Stream流对象
    使用中间方法处理数据
    使用终结方法处理数据

  3. 如何获取Stream流对象
    单列集合:Collection中的默认方法stream
    双列集合:不能直接获取
    数组:Arrays工具类型中的静态方法stream
    一堆零散的数据:Stream接口中的静态方法of

  4. 常见方法
    中间方法:filter,limit,skip,distinct,concat,

    中间方法用法作用
    limitlimit(n)保留流中的前n个人
    skipskip(n)跳过流中的前n个人
    concatStream.concat(stream1, stream2)将两个流拼接在一起
    map比较复杂,看练习3转换流的类型

    终结方法:forEach,count,coIlect

练习

  1. 定义一个集合,并添加一些整数 1,2,3,4,5,6,7,8,9,10
    过滤奇数,只留下偶数。
    并将结果保存起来

     //1. 定义一个集合ArrayList<Integer> list = new ArrayList<>();//2.添加一些整数Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);//3.过滤奇数,只留下偶数//进行判断,如果是偶数,返回true 保留List<Integer> newList = list.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());//4.打印集合
    
  2. 创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄
    “zhangsan,23”
    “lisi,24”
    “wangwu,25”
    保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值

    //1.创建一个ArrayList集合ArrayList<String> list = new ArrayList<>();//2.添加以下字符串list.add("zhangsan,23");list.add("lisi,24");list.add("wangwu,25");//3.保留年龄大于等于24岁的人/*  list.stream().filter(s -> Integer.parseInt(s.split(",")[1]) >= 24).collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {return s.split(",")[0];}}, new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s.split(",")[1]);}}));*/Map<String, Integer> map = list.stream().filter(s -> Integer.parseInt(s.split(",")[1]) >= 24).collect(Collectors.toMap(s -> s.split(",")[0],s -> Integer.parseInt(s.split(",")[1])));System.out.println(map);
    
  3. 现在有两个ArrayList集合,分别存储6名男演员的名字和年龄以及6名女演员的名字和年龄。
    姓名和年龄中间用逗号隔开。
    比如:张三,23
    要求完成如下的操作:
    1,男演员只要名字为3个字的前两人
    2,女演员只要姓杨的,并且不要第一个
    3,把过滤后的男演员姓名和女演员姓名合并到一起
    4,将上一步的演员信息封装成Actor对象。
    5,将所有的演员对象都保存到List集合中。
    备注:演员类Actor,属性有:name,age

     男演员:  "蔡坤坤,24" , "叶齁咸,23", "刘不甜,22", "吴签,24", "谷嘉,30", "肖梁梁,27"女演员:  "赵小颖,35" , "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33"
    
//1.创建两个ArrayList集合ArrayList<String> manList = new ArrayList<>();ArrayList<String> womenList = new ArrayList<>();//2.添加数据Collections.addAll(manList, "蔡坤坤,24", "叶齁咸,23", "刘不甜,22", "吴签,24", "谷嘉,30", "肖梁梁,27");Collections.addAll(womenList, "赵小颖,35", "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33");//3.男演员只要名字为3个字的前两人Stream<String> stream1 = manList.stream().filter(s -> s.split(",")[0].length() == 3).limit(2);//4.女演员只要姓杨的,并且不要第一个Stream<String> stream2 = womenList.stream().filter(s -> s.split(",")[0].startsWith("杨")).skip(1);//5.把过滤后的男演员姓名和女演员姓名合并到一起//演员信息封装成Actor对象。//String -> Actor对象 (类型转换)/* Stream.concat(stream1,stream2).map(new Function<String, Actor>() {@Overridepublic Actor apply(String s) {//"赵小颖,35"String name = s.split(",")[0];int age = Integer.parseInt(s.split(",")[1]);return new Actor(name,age);}}).forEach(s-> System.out.println(s));*/List<Actor> list = Stream.concat(stream1, stream2).map(s -> new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1]))).collect(Collectors.toList());System.out.println(list);
public class Actor {private String name;private int age;public Actor() {}public Actor(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}public String toString() {return "Actor{name = " + name + ", age = " + age + "}";}
}

方法引用

含义:把已经有的方法拿过来用,当做函数式接口中抽象方法的方法体。
在这里插入图片描述

=>
在这里插入图片描述
方法引用格式:类名::函数名 例如Arrays.sort(arr, FunctionDemo1::subtraction);(见如下代码)
::是方法引用符

public class FunctionDemo1 {public static void main(String[] args) {//需求:创建一个数组,进行倒序排列Integer[] arr = {3, 5, 4, 1, 6, 2};//匿名内部类Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});//lambda表达式//因为第二个参数的类型Comparator是一个函数式接口Arrays.sort(arr, (Integer o1, Integer o2)->{return o2 - o1;});//lambda表达式简化格式Arrays.sort(arr, (o1, o2)->o2 - o1 );//方法引用//1.引用处需要是函数式接口//2.被引用的方法需要已经存在//3.被引用方法的形参和返回值需要跟抽象方法的形参和返回值保持一致//4.被引用方法的功能需要满足当前的要求//表示引用FunctionDemo1类里面的subtraction方法//把这个方法当做抽象方法的方法体Arrays.sort(arr, FunctionDemo1::subtraction);System.out.println(Arrays.toString(arr));}//可以是Java已经写好的,也可以是一些第三方的工具类public static int subtraction(int num1, int num2) {return num2 - num1;}
}
  • 方法引用的分类

    1. 引用静态方法

    2. 引用成员方法

    • 引用其他类的成员方法

    • 引厍本类的成员方法

    • 引用父类的成员方法

    1. 引用构造方法

    2. 其他调用方式

    • 使用类名引用成员方法

    • 引用数组的构造方法

引用静态方法

引用格式:类名::静态方法

/*方法引用(引用静态方法)格式类::方法名需求:集合中有以下数字,要求把他们都变成int类型"1","2","3","4","5"*///1.创建集合并添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list,"1","2","3","4","5");//2.把他们都变成int类型/* list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {int i = Integer.parseInt(s);return i;}}).forEach(s -> System.out.println(s));*///1.方法需要已经存在//2.方法的形参和返回值需要跟抽象方法的形参和返回值保持一致//3.方法的功能需要把形参的字符串转换成整数list.stream().map(Integer::parseInt).forEach(s-> System.out.println(s));

注:只有函数式接口才能使用引用方法

引用成员方法

格式:对象::成员方法

  • 其他类:其他类对象::方法名
  • 本类:this::方法名 (引用处不能是静态方法)
  • 父类:super::方法名(引用处不能是静态方法)
/*方法引用(引用成员方法)格式其他类:其他类对象::方法名本类:this::方法名(引用处不能是静态方法)父类:super::方法名(引用处不能是静态方法)需求:集合中有一些名字,按照要求过滤数据数据:"张无忌","周芷若","赵敏","张强","张三丰"要求:只要以张开头,而且名字是3个字的*///1.创建集合ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");//3.过滤数据(只要以张开头,而且名字是3个字的)//以前的方法list.stream().filter(s->s.startsWith("张")).filter(s->s.length() == 3).forEach(s-> System.out.println(s)); //引用方法//filter的Predicate是函数式接口,可以使用引用方法//可以先写如下代码,以便观察如何写引用方法list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张") && s.length() == 3;}}).forEach(s-> System.out.println(s));

其他类

//另外创建一个类
package com.itheima.a01myfunction;public class StringOperation {public boolean stringJudge(String s){return s.startsWith("张") && s.length() == 3;}
}
//修改为引用成员方法形式StringOperation so = new StringOperation();list.stream().filter(so::stringJudge).forEach(s-> System.out.println(s));

本类

public class FunctionDemo3  {public static void main(String[] args) {/*方法引用(引用成员方法)格式其他类:其他类对象::方法名本类:this::方法名(引用处不能是静态方法)父类:super::方法名(引用处不能是静态方法)需求:集合中有一些名字,按照要求过滤数据数据:"张无忌","周芷若","赵敏","张强","张三丰"要求:只要以张开头,而且名字是3个字的*///1.创建集合ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");//3.过滤数据(只要以张开头,而且名字是3个字的)//list.stream().filter(s->s.startsWith("张")).filter(s->s.length() == 3).forEach(s-> System.out.println(s));list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张") && s.length() == 3;}}).forEach(s-> System.out.println(s));//**静态方法中是没有this的,所以this::stringJudge会报错,需改为new FunctionDemo3()::stringJudgelist.stream().filter(new FunctionDemo3()::stringJudge).forEach(s-> System.out.println(s));}public boolean stringJudge(String s){return s.startsWith("张") && s.length() == 3;}
}

引用构造方法

目的:创建对象
格式:类名::new (例如:Student::new)

public class FunctionDemo4 {public static void main(String[] args) {/*方法引用(引用构造方法)格式类名::new目的:创建这个类的对象需求:集合里面存储姓名和年龄,要求封装成Student对象并收集到List集合中方法引用的规则:1.需要有函数式接口2.被引用的方法必须已经存在3.被引用方法的形参和返回值,需要跟抽象方法的形参返回值保持一致4.被引用方法的功能需要满足当前的需求*///1.创建集合对象ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "张无忌,15", "周芷若,14", "赵敏,13", "张强,20", "张三丰,100", "张翠山,40", "张良,35", "王二麻子,37", "谢广坤,41");//3.封装成Student对象并收集到List集合中//String --> Student/*  List<Student> newList = list.stream().map(new Function<String, Student>() {@Overridepublic Student apply(String s) {String[] arr = s.split(",");String name = arr[0];int age = Integer.parseInt(arr[1]);return new Student(name, age);}}).collect(Collectors.toList());System.out.println(newList);*/List<Student> newList2 = list.stream().map(Student::new).collect(Collectors.toList());System.out.println(newList2);}
}
public class Student {private String name;private int age;public Student() {}public Student(String str) {String[] arr = str.split(",");this.name = arr[0];this.age = Integer.parseInt(arr[1]);}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}

类名引用成员方法

格式:类名::成员方法
范例:String::subString

  • 方法引用的规则:
    1.需要有函数式接口
    2.被引用的方法必须已经存在

    3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。
    (所以下图中方法参数不一样也没关系,因为类名引用成员方法的参数规则比较特殊)在这里插入图片描述
    4.被引用方法的功能需要满足当前的需求

  • 抽象方法形参的详解:

    • 第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法
      在Stream流当中,第一个参数一般都表示流里面的每一个数据。
      假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法

    • 第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法

  • 局限性:
    不能引用所有类中的成员方法。
    是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法。
    (比如代码中抽象方法的第一个参数是String类型的,那么map中就只能引用String的方法String::toUpperCase)

/*方法引用(类名引用成员方法)格式类名::成员方法需求:集合里面一些字符串,要求变成大写后进行输出*///1.创建集合对象ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "aaa", "bbb", "ccc", "ddd");//3.变成大写后进行输出//map(String::toUpperCase)//拿着流里面的每一个数据,去调用String类中的toUpperCase方法,方法的返回值就是转换之后的结果。list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));//String --> String/* list.stream().map(new Function<String, String>() {@Overridepublic String apply(String s) {return s.toUpperCase();}}).forEach(s -> System.out.println(s));*/

引用数组的构造方法

格式:数据类型[]::new
范例:int[]::new

        方法引用(数组的构造方法)格式数据类型[]::new目的:创建一个指定类型的数组需求:集合中存储一些整数,收集到数组当中细节:数组的类型,需要跟流中数据的类型保持一致。//1.创建集合并添加元素ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 1, 2, 3, 4, 5);//2.收集到数组当中Integer[] arr2 = list.stream().toArray(Integer[]::new);//3.打印System.out.println(Arrays.toString(arr2));/*Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {@Overridepublic Integer[] apply(int value) {return new Integer[value];}});*/

练习

练习1
需求:
集合中存储一些字符串的数据,比如:张三,23。
收集到Student类型的数组当中

        //1.创建集合并添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌,15", "周芷若,14", "赵敏,13", "张强,20", "张三丰,100", "张翠山,40", "张良,35", "王二麻子,37", "谢广坤,41");//2.先把字符串变成Student对象,然后再把Student对象收集起来Student[] arr = list.stream().map(Student::new).toArray(Student[]::new);//打印数组System.out.println(Arrays.toString(arr));

练习2

/**   需求:*       创建集合添加学生对象*       学生对象属性:name,age*   要求:*       获取姓名并放到数组当中*       使用方法引用完成* *///1.创建集合ArrayList<Student> list = new ArrayList<>();//2.添加元素list.add(new Student("zhangsan",23));list.add(new Student("lisi",24));list.add(new Student("wangwu",25));//3.获取姓名并放到数组当中String[] arr = list.stream().map(Student::getName).toArray(String[]::new);/* String[] arr = list.stream().map(new Function<Student, String>() {@Overridepublic String apply(Student student) {return student.getName();}}).toArray(String[]::new);*/System.out.println(Arrays.toString(arr));
技巧:
1.现在有没有一个方法符合我当前的需求
2.如果有这样的方法,这个方法是否满足引用的规则静态   类名::方法名成员方法:如果流中数据类型与符合需求的方法属于同一类,用类名::方法名构造方法  类名::new

http://www.ppmy.cn/news/18953.html

相关文章

Dubbo 源码分析 – 自适应拓展原理

1.原理 我在上一篇文章中分析了 Dubbo 的 SPI 机制&#xff0c;Dubbo SPI 是 Dubbo 框架的核心。Dubbo 中的很多拓展都是通过 SPI 机制进行加载的&#xff0c;比如 Protocol、Cluster、LoadBalance 等。有时&#xff0c;有些拓展并非想在框架启动阶段被加载&#xff0c;而是希…

使用 AJAX+JSON 实现用户查询/添加功能

实现用户查询/添加功能1. 查询功能准备selectAllServlet&#xff1a;brand.html&#xff1a;2. 添加功能addBrand.html&#xff1a;表单&#xff1a;<script&#xff1a;addServlet&#xff1a;1. 查询功能 需求&#xff1a;在onload&#xff08;页面加载完成&#xff09;事…

YOLOv5/v7 引入 YOLOv8 的 C2f 模块

YOLOv8 项目地址&#xff1a;https://github.com/ultralytics/ultralytics YOLOv8 Ultralytics YOLOv8 是由 Ultralytics 开发的一个前沿的 SOTA 模型。它在以前成功的 YOLO 版本基础上&#xff0c;引入了新的功能和改进&#xff0c;进一步提升了其性能和灵活性。YOLOv8 基于快…

Ae 效果详解:发光

效果/风格化/发光Effects/Stylize/Glow发光 Glow效果可找到图像中的较亮部分&#xff0c;然后使那些像素和周围的像素变亮&#xff0c;以创建漫射的发光光环。可以创建两种颜色&#xff08;颜色 A 和颜色 B &#xff09;之间的渐变发光&#xff0c;并可通过复制发光效果以创建更…

ESP32设备驱动-LX1972可见光传感器驱动

LX1972可见光传感器驱动 1、LX1972介绍 LX1972 是一款低成本硅光传感器,其光谱响应非常接近人眼。专利电路在 520nm 处产生峰值光谱响应,IR 响应小于峰值响应的 5%,高于 900nm。 光电传感器是一个 PIN 二极管阵列,具有线性、准确和非常可重复的电流传递函数。 芯片上的…

【每日一题Day96】LC2303计算应缴税款总额 | 模拟

计算应缴税款总额【LC2303】 You are given a 0-indexed 2D integer array brackets where brackets[i] [upperi, percenti] means that the ith tax bracket has an upper bound of upperi and is taxed at a rate of percenti. The brackets are sorted by upper bound (i.e…

Allegro如何统计包含过孔长度的网络长度操作指导

Allegro如何统计包含过孔长度的网络长度操作指导 当需要统计网络长度的时候,可以通过element选择nets看到网络的长度,但是当网络换层了,并且需要统计到过孔的长度,类似下图 Allegro可以快速的统计网络的长度,并且包含过孔的长度 具体操作如下 选择Setup选择Constraint –…

UDS诊断系列介绍15-FIM模块功能介绍

本文框架1. 系列介绍1.1 FIM模块概述2. FIM相关概念2.1 FID概念2.2 FIM数据结构3. FIM模块作用过程4. Autosar系列文章快速链接1. 系列介绍 UDS&#xff08;Unified Diagnostic Services&#xff09;协议&#xff0c;即统一的诊断服务&#xff0c;是面向整车所有ECU的一种诊断…