怎样修改网站首页头部,wordpress文章形式图标,网页设计培训机构推荐,网络培训师目录
一、Stream API 函数式编程
1.1、Stream 简介
a#xff09;为什么引入 Stream#xff1f;Stream 的出现就是为了让关于集合的操作更加简单#xff1a;
b#xff09;Stream 的特性#xff1a;
c#xff09;对stream的操作分为为两类#xff0c;中间操作 和 结束…目录
一、Stream API 函数式编程
1.1、Stream 简介
a为什么引入 StreamStream 的出现就是为了让关于集合的操作更加简单
bStream 的特性
c对stream的操作分为为两类中间操作 和 结束操作 二者特点是
dStream 一般不需要我们去手动 new 一个出来而是通过以下两种方式获取
eStream 的本质
1.2、Stream 的使用
说明案例中操作的实体类
1.2.1、forEach() 遍历
1.2.2、filter() 过滤
1.2.3、distinct() 去重
1.2.4、sorted() 排序
1.2.5、map() 映射
1.2.6、flatMap() 展开映射
1.2.7、reduce() 聚合
1.2.8、collect() 转化
1.2.9、collect() 生成 Map
1.2.10、collect() 生成字符串 一、Stream API 函数式编程 1.1、Stream 简介
a为什么引入 StreamStream 的出现就是为了让关于集合的操作更加简单
代码简洁优雅函数式编程写出的代码简洁且意图明确使用stream接口让你从此告别for循环。简写并发执行Java函数式编程使得编写并行程序从未如此简单你需要的全部就是调用一下parallel()方法透明地并行处理你无需写任何多线程代码极大的提高编程效率和程序可读性。
bStream 的特性
无存储。stream不是一种数据结构它只是某种数据源的一个视图数据源可以是一个数组Java容器或I/O channel等。为函数式编程而生。对stream的任何修改都不会修改背后的数据源比如对stream执行过滤操作并不会删除被过滤的元素而是会产生一个不包含被过滤元素的新stream。惰式执行。stream上的操作并不会立即执行只有等到用户真正需要结果的时候才会执行。可消费性。stream只能被“消费”一次一旦遍历过就会失效就像容器的迭代器那样想要再次遍历必须重新生成。
c对stream的操作分为为两类中间操作 和 结束操作 二者特点是
中间操作总是会惰式执行调用中间操作只会生成一个标记了该操作的新stream仅此而已。例如concat() distinct() filter() flatMap() limit() map() peek() skip() sorted() parallel() sequential() unordered()结束操作会触发实际计算计算发生时会把所有中间操作积攒的操作以pipeline的方式执行这样可以减少迭代次数。计算完成之后stream就会失效。例如allMatch() anyMatch() collect() count() findAny() findFirst() forEach() forEachOrdered() max() min() noneMatch() reduce() toArray()
dStream 一般不需要我们去手动 new 一个出来而是通过以下两种方式获取
调用 Collection.stream() 或者 Collection.parallelStream() 方法并发调用 Arrays.stream(T[] array) 方法
eStream 的本质
函数式接口内部只有一个抽象方法同时也是 lambda 表达式的本质因此我们不需要记住函数接口的名字. 1.2、Stream 的使用
说明案例中操作的实体类
Data
AllArgsConstructor
class Student {private String name;private Integer score;private Integer grade;
}Data
AllArgsConstructor
class User {private String name;private Integer age;}Builder
class UserVO {private String name;private Integer age;private String other;}1.2.1、forEach() 遍历
aforEach 因该都不陌生也就是对每个元素进行遍历. List.of(a, ab, abc, abcd).stream().forEach(str - System.out.println(str));如果只是为了打印可以如下简写. List.of(a, ab, abc, abcd).stream().forEach(System.out::println);b两个冒号是啥意思
例如 String::length 的语法形式叫做方法引用method references这种语法用来替代某些特定形式Lambda表达式。如果Lambda表达式的全部内容就是调用一个已有的方法那么可以用方法引用来替代Lambda表达式。方法引用可以细分为四类
方法引用类别举例引用静态方法Integer::sum引用某个对象的方法list::add引用某个类的方法String::length引用构造方法HashMap::new Ps后面会引入更多这种的例子 1.2.2、filter() 过滤
用来过滤掉容器中的一些数据返回一个只符合条件的 Stream.
例如返回容器中长度大于 2 的字符串 List.of(a, ab, abc, abcd).stream().filter(str - str.length() 2).forEach(System.out::println);
上述代码就会输出abc abcd
1.2.3、distinct() 去重
distinct 的作用就是返回一个去重之后的 Stream List.of(a, ab, abc, abc).stream().distinct().forEach(System.out::println);
上述代码就会输出a ab abc 1.2.4、sorted() 排序
sorted 可以用来排序. 排序的方式有以下两种
自然排序StreamT sorted()
自定义比较器排序StreamT sorted(Comparator? super T comparator) ListInteger nums List.of(4, 1, 3, 2);//a) 输出 1 2 3 4nums.stream().sorted().forEach(num - System.out.print(num ));//b) 输出 4 3 2 1nums.stream().sorted((n1, n2) - n2 - n1).forEach(num - System.out.print(num ));1.2.5、map() 映射
通俗来讲就是对 stream 中的每一个元素按照某种操作之后进行转化转换前后元素个数不会变类型取决于转换之后的类型.
a例如大小写转化 //a) 小写转大写List.of(a, ab, abc, abcd).stream().map(str - str.toUpperCase()).forEach(str - System.out.println(str ));b例如从数据库拿到一组数据转化成所需要的 DO 或者 VO 类以下只是模拟 public void test5() {ListUserVO list List.of(new User(aaa, 20),new User(bbb, 19),new User(ccc, 31)) //从数据库中拿到数据.stream().map(this::map).toList();}public UserVO map(User user) {return UserVO.builder().name(user.getName()).age(user.getAge()).build();}上述代码中我们把从数据库中拿到的 ListUser模拟数据库数据转化成了 ListUserVO. 1.2.6、flatMap() 展开映射
通俗的讲 flatMap() 的作用就相当于把原 stream 中的所有集合中的元素都拿出来之后组和到一个 Stream 中展开. 转换前后元素的个数和类型都可能会改变。
例如Stream中两个 List 元素通过 flatMap 将这两个元素全部展开了. //将两个 List 变成了一个 ListStream.of(List.of(1, 2, 3), List.of(4, 5, 6)).flatMap(list - list.stream()).forEach(System.out::println); //输出 1 2 3 4 5 61.2.7、reduce() 聚合
reduce操作可以实现从一组元素中生成一个值sum()、max()、min()、count()等都是reduce操作将他们单独设为函数只是因为常用。reduce()的方法定义有三种重写形式
OptionalT reduce(BinaryOperatorT accumulator)T reduce(T identity, BinaryOperatorT accumulator)U U reduce(U identity, BiFunctionU,? super T,U accumulator, BinaryOperatorU combiner)
虽然函数定义越来越长但语义不曾改变多的参数只是为了指明初始值参数identity或者是指定并行执行时多个部分结果的合并方式参数combiner。
reduce()最常用的场景就是从一堆值中生成一个值。
例如找出长度最长的单词、求单词长度之和. //1.找出长度最长的单词OptionalString reduce List.of(a, ab, abc, abcd).stream().reduce((s1, s2) - s1.length() s2.length() ? s1 : s2);System.out.println(reduce.get());//2.求单词长度之和Integer num List.of(a, ab, abc, abcd).stream().reduce(0, //起始大小(sum, str) - sum str.length(), //组合方法(a, b) - a b //并行执行才会使用到(其他时候不会执行));System.out.println(num);1.2.8、collect() 转化
collect 用来将一个 stream 执行一个特定动作最后生成一个集合.
而这个特定动作就是 Collectors 收集器提供的方法.
例如将 Stream 转化成 List、Set、Map. StreamString stream Stream.of(a, ab, abc, abcd);//1.将 Stream 转换成 ListListString collect stream.collect(Collectors.toList());//2.将 Stream 转换成 SetSetString collect1 stream.collect(Collectors.toSet());//3.将 Stream 转换成 Map. Collectors.toMap(如何生成 key, 如何生成 value)MapString, Integer collect2 stream.collect(Collectors.toMap(Function.identity(), str - str.length()));//方法引用MapString, Integer collect3 stream.collect(Collectors.toMap(Function.identity(), String::length));有人可能疑惑了Function.identity() 是什么 Function.identity()返回一个输出跟输入一样的Lambda表达式对象等价于形如 p - p 形式的Lambda表达式. 那为什么不用 p - p 这种方式直接表示呢 这是因为在Java 7及之前要想在定义好的接口中加入新的抽象方法是很困难甚至不可能的因为所有实现了该接口的类都要重新实现......
上述代码能满足绝大多数需求但是如果我们要去指定生成一个接口具体的类型就可以按如下方式例如 ArrayList、HashSet StreamString stream Stream.of(a, ab, abc, abcd);//将 Stream 转换成 ArrayListArrayListString arrayList stream.collect(Collectors.toCollection(ArrayList::new));//将 Stream 转换成 HashSetHashSetString hashSet stream.collect(Collectors.toCollection(HashSet::new));1.2.9、collect() 生成 Map
使用 collect 生成 Map 处理前面讲到了的最基本的方式 Collectors.toMap() 收集器 生成 Map 以外还有两种方式 这里我把三种方式都罗列出来
使用 Collectors.toMap()生成的收集器用户需要指定如何生成 Map 的 key 和 value。使用 Collectors.partitioningBy()生成的收集器对元素进行二分区操作时用到。使用 Collectors.groupingBy()生成的收集器对元素做group操作时用到类似 sql 重点 group by 操作。
a先来看第一种toMap 的方式最直接例如将 学生列表 转化成 学生成绩 的 Map StreamStudent studentStream Stream.of(new Student(aaa, 80, 1),new Student(bbb, 78, 2),new Student(ccc, 96, 3));//用 Map 统计学生成绩MapStudent, Integer map studentStream.collect(Collectors.toMap(Function.identity(), Student::getScore));bpartitioningBy() 就是按照 满足/不满足 的逻辑进行划分. key 就是 boolean 类型true 和 false 就分别表示了 满足 和 不满足 的逻辑
例如将学生按照分数是否及格来划分 StreamStudent studentStream Stream.of(new Student(aaa, 80, 1),new Student(bbb, 58, 2),new Student(ccc, 96, 3));//统计成绩合格和不合格的学生MapBoolean, ListStudent map studentStream.collect(Collectors.partitioningBy(stu - stu.getScore() 60));上述代码中凡事 key 为 true 的对应对 value 就是 score 60 的学生 cgroupingBy() 就类似于 sql 语句中 group by 分组.
例如将 学生 按照班级进行分组那么 key 就是班级value 就是 学生列表 StreamStudent studentStream Stream.of(new Student(aaa, 80, 1),new Student(bbb, 58, 2),new Student(ccc, 96, 2),new Student(ddd, 67, 1));//按照 grade 年级进行分组MapInteger, ListStudent map studentStream.collect(Collectors.groupingBy(Student::getGrade));System.out.println(map);例如我们还想要将 学生 按照班级分组后再展示出每个班的学生数量或者是 最大值、最小值、求和、平均值这种计算如下代码 StreamStudent studentStream Stream.of(new Student(aaa, 80, 1),new Student(bbb, 58, 2),new Student(ccc, 96, 2),new Student(ddd, 67, 1));//先按照 grade 年级分组再统计每个年级的人数MapInteger, Long map studentStream.collect(Collectors.groupingBy(Student::getGrade, Collectors.counting()));Ps这种先将元素分组的收集器叫做上游收集器之后执行其他运算的收集器叫做下游收集器(downstream Collector)。 下游收集器还可以包含更下游的收集器例如我们将学生按照年级分组后不想直接得到一个学生列表而是一个学生的姓名列表就可以通过如下方式得到. StreamStudent studentStream Stream.of(new Student(aaa, 80, 1),new Student(bbb, 58, 2),new Student(ccc, 96, 2),new Student(ddd, 67, 1));//先按照 grade 年级分组再统计每个年纪的人名字MapInteger, ListString collect studentStream.collect(Collectors.groupingBy(Student::getGrade, //key: 按照名字分组Collectors.mapping(Student::getName, //value: 名字 (下游收集器)Collectors.toList() // 用 List 来收集这些 value (更下游的收集器))));1.2.10、collect() 生成字符串
Collectors.joining 有三种重载方式来拼接字符串如下 StreamString stream Stream.of(what, do, you, meaning);
// String collect1 stream.collect(Collectors.joining(,)); // whatdoyoumeaning
// String collect2 stream.collect(Collectors.joining(,)); // what,do,you,meaningString collect3 stream.collect(Collectors.joining(,, {, })); // {what,do,you,meaning}