vue 做企业网站,番禺网站建设多少钱,高新快速建设网站找哪家,wordpress js失效jdk1.8 List集合Stream流式处理 一、介绍(为什么需要流Stream#xff0c;能解决什么问题#xff1f;)1.1 什么是 Stream#xff1f;1.2 常见的创建Stream方法1.3 常见的中间操作1.4 常见的终端操作 二、创建流Stream2.1 Collection的.stream()方法2.2 数组创建流2.3 静态工厂… jdk1.8 List集合Stream流式处理 一、介绍(为什么需要流Stream能解决什么问题)1.1 什么是 Stream1.2 常见的创建Stream方法1.3 常见的中间操作1.4 常见的终端操作 二、创建流Stream2.1 Collection的.stream()方法2.2 数组创建流2.3 静态工厂方法2.4 Stream.builder2.5 从文件创建流 三、中间操作3.1 过滤Filter3.2 映射Map3.3 映射flatMap3.4 排序Sorted3.5 distinct(去重含转Set去重)3.6 skip limit分页3.7 peek(循环)3.8 mapToInt、mapToDouble ... 四、终端操作4.0 foreach(常用于处理List、Map等数据)4.1 收集Collect4.1.1 转换为List4.1.2 转换为Set4.1.3 分组汇总Grouping4.1.4 toMap(转成Map)4.1.5 reducing 规约(此处只讨论简单使用重载方法待研究)4.1.6 计数Counting4.1.7 汇总求和Summing4.1.8 汇总对象IntSummaryStatistics)4.1.9 获取单个元素 maxBy、 minBy4.1.10 toCollection()4.1.11 mapping4.1.12 joining4.1.13 partitioningBy4.1.14 collectingAndThen 4.2. 自定义收集器4.3 归约Reduce4.4 查找元素 findFirst、findAny4.5 匹配 anyMatch、allMatch、noneMatch4.6 count max min 五、并行流六、总结6.1 Stream的优点6.2 Stream的缺点 一、介绍(为什么需要流Stream能解决什么问题)
Java 8 引入了一个新的抽象层——Stream API它允许你以声明性方式处理数据集合包括数组、集合等。Stream API 提供了一种高效且易于表达的方式来处理数据集合包括过滤、排序、映射和归约等操作。这种处理方式极大地提高了代码的可读性和可维护性同时也提升了处理大量数据的性能。
1.1 什么是 Stream
Stream流是 Java 8 引入的一个关键抽象概念它代表了一个来自数据源的元素队列并支持聚合操作。和迭代器Iterator不同Stream 不存储元素它们是源到聚合操作的中间桥梁其操作的执行是延迟的即只有在需要结果时才执行。 在日常编程中会经常进行数据(如List、数组)的处理在没有stram流时我们的一般操作方式显得比较臃肿不够优雅简洁。代码如下原写法 ListString list new ArrayList();Collections.addAll(list,赵子龙,关云长,黄忠,张良,张翼德);ArrayListString list1 new ArrayList();list.forEach(s - {if(s.startsWith(张)) {list1.add(s);}});list1.forEach(s - System.out.println(s));stream流式写法 ListString list new ArrayList();Collections.addAll(list,赵子龙,关云长,黄忠,张良,张翼德);list.stream().filter(p - p.startsWith(张)).forEach(System.out::println);这个例子也告诉我们Stream流写法更加简洁优雅。 流式操作三部曲如下图所示 如上图所示概括的讲可以将stream流操作分为3种类型
创建StreamStream中间操作终止Stream(终端操作)
每个Stream管道操作类型都包含若干API方法先列举下各个API方法的功能介绍。
1.2 常见的创建Stream方法
在Java中创建Stream的方法多种多样可以从各种数据源生成Stream。以下是一些常见的创建Stream的方法
方法类型示例代码描述集合转StreamListString list Arrays.asList(a, b, c);brStreamString stream list.stream();通过Collection接口如List、Set等的stream()方法创建Stream。数组转StreamString[] array {d, e, f};brStreamString stream Arrays.stream(array);通过Arrays类的stream(T[] array)静态方法将数组转换为Stream。Stream类静态方法StreamInteger stream Stream.of(1, 2, 3, 4, 5);使用Stream类的of(T... values)静态方法从一组值中创建Stream。无限流生成StreamDouble randomStream Stream.generate(Math::random);StreamInteger infiniteStream Stream.iterate(0, i - i 1);使用Stream类的generate(SupplierT s)和iterate(T seed, UnaryOperatorT f)静态方法生成无限流。generate接受一个供应器Supplier每次需要新值时调用其get()方法iterate接受一个初始值和一个函数每次迭代时将当前值作为参数传递给函数返回的结果作为下一次迭代的值。空StreamStreamString emptyStream Stream.empty();使用Stream类的empty()静态方法创建一个空的Stream。构建器Stream.BuilderString builder Stream.builder();brbuilder.add(Java);brbuilder.add(Python);brStreamString stream builder.build();使用Stream.Builder来构建复杂的Stream。首先创建一个Builder对象然后调用其add方法添加元素最后调用build方法生成Stream。
1.3 常见的中间操作
操作名称操作方法描述过滤filter(Predicate? super T predicate)通过给定的谓词predicate测试元素保留使谓词返回true的元素映射map(Function? super T, ? extends R mapper)将每个元素映射到其对应的转换结果上转换结果可以是一个新的类型扁平映射flatMap(Function? super T, ? extends Stream? extends R mapper)类似于map但每个元素都可以被映射成一个Stream然后所有这些Stream会被合并成一个Stream排序sorted() / sorted(Comparator? super T comparator)对流中的元素进行排序可以选择自然排序或自定义排序器截断limit(long maxSize)限制流中元素的数量使其不超过给定的最大值跳过skip(long n)跳过流中的前n个元素并行流.parallel()将顺序流转换为并行流以便并行处理串行流.sequential()将并行流转换回顺序流以便顺序处理去重distinct()返回一个由流中不同元素组成的流基于元素的equals和hashCode方法逐元素替换peek(Consumer? super T action)提供一个消费者函数该函数会在处理每个元素时执行但不影响流的内容
请注意尽管peek操作可以看作是一种中间操作因为它返回Stream本身但它主要用于调试目的并不改变流的内容或结构。
1.4 常见的终端操作
操作名称操作方法描述匹配操作anyMatch(Predicate? super T predicate)是否存在至少一个元素匹配给定的谓词allMatch(Predicate? super T predicate)是否所有元素都匹配给定的谓词noneMatch(Predicate? super T predicate)是否没有元素匹配给定的谓词查找操作findFirst()返回流中的第一个元素作为Optional如果流为空则返回Optional.empty()findAny()返回流中的任意元素作为Optional对于并行流行为可能不同归约操作reduce(BinaryOperatorT accumulator)通过给定的归约操作如求和、求积将流中的所有元素组合起来结果为Optionalreduce(T identity, BinaryOperatorT accumulator)类似于上一个但提供了一个初始值结果为T类型而非Optional收集操作collect(Collectors.toList()) / collect(Collectors.toSet()) 等将流中的元素收集到一个列表、集合或其他容器中Collectors类提供了多种收集器最大值/最小值max(Comparator? super T comparator) / min(Comparator? super T comparator)根据给定的比较器找到流中的最大或最小元素结果为Optional数组操作toArray(T[] generator) / toArray(IntFunctionT[] generator)将流中的元素收集到一个数组中需要提供一个数组生成器或类型信息计数操作count()返回流中的元素数量结果为long类型遍历操作forEach(Consumer? super T action)对流中的每个元素执行给定的操作这是一个终端操作因为它有副作用即执行操作归纳操作summaryStatistics()针对IntStream, LongStream, DoubleStream返回包含各种统计数据的对象如计数、平均值、最大值、最小值等
请注意forEach虽然是一个终端操作但它主要用于执行副作用即不返回结果的操作而不是为了获取结果。同样reduce、collect和max/min等操作既可以看作是中间操作因为它们可以在另一个流的上下文中使用尽管这在实际中并不常见也可以看作是终端操作因为它们会触发流的执行并返回一个结果。但是在典型的用法中我们更倾向于将它们视为终端操作。
二、创建流Stream
2.1 Collection的.stream()方法 public static void main(String[] args) {// 1.list创建流ListString list new ArrayList();Collections.addAll(list, 赵子龙, 关云长, 黄忠, 张良, 张翼德);// 创建一个Stream流StreamString stream list.stream();// 使用流进行操作stream.filter(p - p.startsWith(张)).forEach(System.out::println);// 2.map创建流(先转换成keySet或entrySet)MapObject, Object map new HashMap();map.put(张三, 1);map.put(李四, 8);map.put(王五, 5);// 2.1 keySetmap.keySet().stream().forEach(System.out::println);map.keySet().stream().forEach(p - System.out.println(p map.get(p)));// 2.2 entrySetmap.entrySet().stream().forEach(System.out::println);}示例中用list.stream()创建流用map装换成keySet或entrySet后用.stream()创建流。
2.2 数组创建流 int[] array {5,6,8,7,5,6,1,0};// 1.从整数数组创建IntStreamIntStream intStream Arrays.stream(array);String[] strArray {东邪,西毒,南帝,北丐,中神通};// 2.从字符串数组创建StreamStreamString stringStream Arrays.stream(strArray);示例中用Arrays.stream()创建流(IntStream 、Stream)为开发中最常用创建流的方式。
2.3 静态工厂方法
Stream.of(T… values)通过将一个可变参数的元素列表传递给Stream.of方法来创建一个包含这些元素的Stream流。这对于创建具有少量元素的流非常方便。 Stream.empty()使用Stream.empty()方法创建一个空的Stream流。 Stream.generate(Supplier s)通过提供一个Supplier函数来创建一个无限大小的Stream流该函数会生成元素。通常需要使用limit操作限制生成的元素数量。 Stream.iterate(T seed, UnaryOperator f)通过提供初始值seed和一个一元操作函数UnaryOperator来创建一个包含无限序列的Stream流。例如可以使用Stream.iterate(0, n - n 1)来创建一个自然数序列的Stream流。
Stream.of(T… values)创建流 // 1.String数组String[] strArr {东邪,西毒,南帝,北丐,中神通};StreamString strArrStream Stream.of(strArr);strArrStream.forEach(System.out::println);// 2.注意int类型数组会将数组仅当作一个处理如下图所示打印的是一个int[]的地址int[] intArr {5,6,8,7,5,6,1,0};Streamint[] intArrStram Stream.of(intArr);intArrStram.forEach(System.out::println);
打印如下
Stream.generate(Supplier s)创建流 // generate创建streamStreamInteger randomIntStream Stream.generate(() - new Random().nextInt(100));randomIntStream.limit(10).forEach(System.out::println);2.4 Stream.builder
Stream.builder创建StreamInteger // 1.逐个添加1到10的整数Stream.BuilderInteger builder Stream.builder();for (int i 0; i 10; i) {builder.accept(i);}StreamInteger builderIntStream builder.build();Stream.builder创建StreamLong // 2.斐波那契数列的前10个数字Stream.BuilderLong builder1 Stream.builder();long a 0; long b 1;int count 10;for (int i 0; i count; i) {builder1.accept(a);long next a b;a b;b next;}StreamLong longStream builder1.build();2.5 从文件创建流
使用Files.lines方法创建文本文件的流 // 逐行读取创建StreamString path names.txt;try {StreamString lines Files.lines(Paths.get(path));ListString names lines.collect(Collectors.toList());} catch (IOException e) {throw new RuntimeException(e);}三、中间操作
基础代码创建list ListUser userList new ArrayList();User user1 User.builder().name(曹操).age(12).desc(许昌).build();User user2 User.builder().name(刘备).age(22).desc(西蜀).build();User user3 User.builder().name(曹操).age(42).desc(许昌).build();User user4 User.builder().name(null).age(32).desc(许昌).build();userList.add(user1);userList.add(user2);userList.add(user3);userList.add(user4);3.1 过滤Filter
filter(Predicate? super T predicate) 方法接收一个谓词即返回布尔值的函数并返回一个包含所有匹配该谓词的元素的流。如下所示常规过滤可直接简单写复杂的过滤可抽取方法使代码更加清晰。
{...// 1.常规简单过滤ListUser overNList1 userList.stream().filter(p - p.getAge() 18).collect(Collectors.toList());// 2.复杂过滤时可抽取方法ListUser overNList2 userList.stream().filter(p - isOverN(p)).collect(Collectors.toList());...
}// 示例isOverNprivate static boolean isOverN(User p) {return p.getAge() 18;}
3.2 映射Map
map(Function? super T, ? extends R mapper) 方法将流中的每个元素映射到另一个对象并返回一个新的流。 // 1.装换成简单数据集合如StringListString names userList.stream().map(User::getName).collect(Collectors.toList());// 2.装换成其它对象集合ListAddress addressList userList.stream().map(p - Address.builder().content(p.getDesc()).build()).collect(Collectors.toList());// 3.mapToInt maxToDouble maxToLong等此类转换好处是可以获取如max、min、average、count等统计类数据long count userList.stream().mapToInt(User::getAge).count();System.out.println(count count);
3.3 映射flatMap
flatMap(Function? super T, ? extends Stream? extends R mapper) flatMap操作与map类似但它被设计用来处理那些将每个输入元素映射到多个输出元素的场景。flatMap首先应用一个函数来映射每个元素这个函数返回一个流而不是单个元素。然后flatMap将这些流“扁平化”成一个流。
ListString sentences Arrays.asList(apple,banana, cherry,date);
ListString words sentences.stream() .flatMap(sentence - Arrays.stream(sentence.split(,))) .collect(Collectors.toList());
// words: [apple, banana, cherry, date]适用于元素逐个拆分并组成新的集合。每个元素处理并返回一个新的Stream然后将多个Stream展开合并为了一个完整的新的Stream。
3.4 排序Sorted
sorted() 和 sorted(Comparator? super T comparator) 方法对流中的元素进行排序关于sorted的用法非常多。 // 0.默认规则排序 适用于基本类型ListString users Arrays.stream(new String[]{东邪, 西毒, 南帝, 北丐, 中神通}).sorted().collect(Collectors.toList());// 1.自定义排序规则ListUser users2 userList.stream().sorted((o1, o2) - o2.getAge().compareTo(o1.getAge())).collect(Collectors.toList());// 2.年龄排序 倒叙ListUser ageSortedList userList.stream().sorted(Comparator.comparing(User::getAge).reversed()).collect(Collectors.toList());// 3.姓名排序 忽略大小写ListUser nameSortedList userList.stream().sorted(Comparator.comparing(User::getName, String.CASE_INSENSITIVE_ORDER)).collect(Collectors.toList());// 4.先按年龄排序如果年龄相同则按姓名排序ListUser ageAndNameSortedList userList.stream().sorted(Comparator.comparing(User::getAge).thenComparing(User::getName, String.CASE_INSENSITIVE_ORDER)).collect(Collectors.toList());// 5.排序处理null值 nullsLast或nullsFirst// 6.null排在最前面其他非null对象根据age倒叙排列 Comparator.reverseOrder()ListUser nullLastSortedList userList.stream().sorted(Comparator.comparing(User::getAge, Comparator.nullsFirst(Comparator.reverseOrder()))).collect(Collectors.toList());nullLastSortedList.forEach(System.out::println);// 7.null排在最前面其他非null对象根据age正序排列 Comparator.naturalOrder()ListUser nullLastSortedList1 userList.stream().sorted(Comparator.comparing(User::getAge, Comparator.nullsFirst(Comparator.naturalOrder()))).collect(Collectors.toList());nullLastSortedList1.forEach(System.out::println);// 8.null排在最前面其他非null对象根据age正序排列,并将最终结果反转ListUser nullLastSortedList2 userList.stream().sorted(Comparator.comparing(User::getAge, Comparator.nullsFirst(Comparator.naturalOrder())).reversed()).collect(Collectors.toList());nullLastSortedList2.forEach(System.out::println);System.out.println();// 9.先根据age排序null排在最前面其他的倒序排列; null相同的按照level正序排列 level中为null的排前面; 其他的正序排列ListUser nullLastSortedList3 userList.stream().sorted(Comparator.comparing(User::getAge, Comparator.nullsFirst(Comparator.reverseOrder())).thenComparing(Comparator.comparing(User::getLevel, Comparator.nullsFirst(Comparator.naturalOrder())).reversed())).collect(Collectors.toList());nullLastSortedList3.forEach(System.out::println);System.out.println(///);// 10.先根据age排序null排在最前面其他的正序排列;ListUser nullLastSortedList4 userList.stream().sorted(Comparator.comparing(User::getAge, Comparator.nullsFirst(Integer::compareTo))).collect(Collectors.toList());nullLastSortedList4.forEach(System.out::println);// 11.先根据age排序null排在最前面其他的正序排列并将最终结果反转ListUser nullLastSortedList6 userList.stream().sorted(Comparator.comparing(User::getAge, Comparator.nullsFirst(Integer::compareTo).reversed())).collect(Collectors.toList());nullLastSortedList6.forEach(System.out::println);// 12.自定义复杂排序规则userList.stream().sorted(new ComparatorUser() {Overridepublic int compare(User o1, User o2) {Date o1OpTime DateUtil.parse(o1.getOpTime(), DateUtil.FULL_DAY_FORMAT);Date o2OpTime DateUtil.parse(o2.getOpTime(), DateUtil.FULL_DAY_FORMAT);// 正序
// return o1OpTime.compareTo(o2OpTime);// 倒叙return o2OpTime.compareTo(o1OpTime);}});
其中nullsLast同理。
3.5 distinct(去重含转Set去重)
distinct() 为基础数据简单去重操作, 后文会讲到通过 Collectors.toCollection结合TreeSet排序去重 // 1.基本类型简单去重ListString list Arrays.asList(new String[]{刘备, 张飞, 赵云, 刘备});ListString collect list.stream().distinct().collect(Collectors.toList());collect.forEach(System.out::println);// 终端操作去重// 2.toCollection()去重根据对象某个字段去重(去重规则取第一条数据可排序后再去重如下所示取年龄最小的对象)TreeSetUser nameSet userList.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toCollection(() - new TreeSet(Comparator.comparing(User::getName))));// 3.toCollection()去重自定义规则去重(同样可先排序再去重)TreeSetUser nameSet2 userList.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toCollection(() - new TreeSetUser(new ComparatorUser() {Overridepublic int compare(User o1, User o2) {return (o1.getName() o1.getLevel()).equals(o2.getName() o2.getLevel()) ? 0 : o1.getName().equals(null) ? 1 : -1 ;}})));nameSet.stream().forEach(System.out::println);
3.6 skip limit分页
skip(long n)和limit(long maxSize)搭配实现分页 int pageSize 3;int pageNo 2;// 实现分页功能ListUser users userList.stream().skip(pageSize * (pageNo - 1)).limit(pageSize).collect(Collectors.toList());users.stream().forEach(System.out::println);3.7 peek(循环)
peek(Consumer? super T action)实现中间操作的循环操作 // peek为中间操作不对元素进行操作可用于记录日志、或调试与foreach的区别是peek为中间操作(须有终端操作才会执行Consumer)ListUser users3 userList.stream().peek(p - Syste
## 3.8 takeWhilem.out.println(p.getName())).collect(Collectors.toList());3.8 mapToInt、mapToDouble … // mapToInt maxToDouble maxToLong等此类转换好处是可以获取如max、min、average、count等统计类数据long count userList.stream().mapToInt(User::getAge).count();System.out.println(count count);四、终端操作
4.0 foreach(常用于处理List、Map等数据) // 循环逐个元素userList.stream().forEach(System.out::println);4.1 收集Collect
collect操作接受一个Collector实例该实例封装了归约操作的性质比如如何添加元素、如何合并两个归约结果以及如何完成归约过程等。不过在实际使用中我们很少直接创建Collector实例而是使用Collectors工具类提供的静态方法这些方法返回了预定义的Collector实例。
以下是一些使用collect操作的常见示例
4.1.1 转换为List
将流中的元素收集到一个列表中可以使用Collectors.toList()。 // 1.不修改元素类型可做完若干中间操作后汇聚成listListUser users userList.stream().collect(Collectors.toList());// 2.转换成其他类型ListString names userList.stream().map(User::getName).collect(Collectors.toList());4.1.2 转换为Set
如果你想要去除流中的重复元素并将结果收集到一个集合中可以使用Collectors.toSet()。 // 1.转换成Set, 仅基本类型可使用SetString set Arrays.asList(new String[]{刘备, 张飞, 赵云, 刘备}).stream().collect(Collectors.toSet());set.stream().forEach(System.out::println);4.1.3 分组汇总Grouping
使用Collectors.groupingBy可以将流中的元素根据某些属性进行分组。 // 分组 单个字段可简写多字段组合如下所示MapString, ListUser groupList1 userList.stream().collect(Collectors.groupingBy(User::getName));MapString, ListUser groupList2 userList.stream().collect(Collectors.groupingBy(p - p.getName() p.getLevel()));
4.1.4 toMap(转成Map)
默认规定允许key为null不允许value为null, 推荐使用3.1写法 // 1.key不重复且value不为null的情况下可用如下简单写法(为了保险起见不推荐这种写法)MapString, User collect1 userList.stream().collect(Collectors.toMap(User::getName, p - p));// 2.处理key重复问题,重复时取最新的valueMapString, Integer collect2 userList.stream().collect(Collectors.toMap(User::getName, User::getLevel, (oldValue, newValue) - newValue));// 3.处理value为null问题// 3.1 方案一Optional设置orElse值如0空字符串等 (***推荐***),这种写法避免了key重复也可以避免value为null的情况MapString, Integer map3 userList.stream().collect(Collectors.toMap(User::getName, p - Optional.ofNullable(p.getLevel()).orElse(0), (oldV, newV) - newV));// 3.2 方案二规约转换,null值取最新的MapString, Integer collect userList.stream().collect(HashMap::new, (resultMap, item) - resultMap.put(item.getName(), item.getLevel()), HashMap::putAll);collect.entrySet().forEach(System.out::println);4.1.5 reducing 规约(此处只讨论简单使用重载方法待研究) // 1.不指定初始值返回OptionalOptionalInteger reduceSum userList.stream().map(User::getAge).collect(Collectors.reducing(Integer::sum));// 2.指定初始值返回intInteger reduceDefaultSum userList.stream().map(User::getAge).collect(Collectors.reducing(0, Integer::sum));// 3.也可规约汇总对象User reducingLevel userList.stream().collect(Collectors.reducing(new User(), (o1, o2) - User.builder().age(o1.getAge() o2.getAge()).level(o1.getLevel() o2.getLevel()).build()));
4.1.6 计数Counting
Collectors.counting()可以返回一个收集器它计算流中的元素数量。 // 计数与list.size()同效int size userList.size();Long count userList.stream().collect(Collectors.counting());4.1.7 汇总求和Summing // 获取单个字段的和summingIntInteger ageSum userList.stream().collect(Collectors.summingInt(User::getAge));4.1.8 汇总对象IntSummaryStatistics)
如果你有一个包含数值的流并想要计算这些数值的总和平均值最大值最小值等可以使用Collectors.summingInt()对于整数等方法。 // 统计对象 IntSummaryStatistics可根据此对象获取max、min...IntSummaryStatistics intSummaryStatistics userList.stream().collect(Collectors.summarizingInt(User::getAge));long sum1 intSummaryStatistics.getSum();long count1 intSummaryStatistics.getCount();int max intSummaryStatistics.getMax();int min intSummaryStatistics.getMin();double average intSummaryStatistics.getAverage();4.1.9 获取单个元素 maxBy、 minBy // 根据某个字段取最小值(最大值等)对应的元素 maxBy minBy返回Optional对象OptionalUser minUserOptinal userList.stream().collect(Collectors.minBy(Comparator.comparing(User::getAge)));User user minUserOptinal.orElse(null);User maxUser userList.stream().collect(Collectors.maxBy(Comparator.comparing(User::getAge))).orElse(new User());
4.1.10 toCollection()
.toCollection() 是一个收集器Collector它用于将流中的元素收集到一个指定的Collection类型中。这个收集器接受一个Supplier作为参数其中C是Collection的一个子类型这个Supplier用于提供一个新的、空的Collection实例流中的元素将被添加到这个实例中。 // toCollection 常与TreeSet去重使用// 1.简单转SetTreeSetUser userTreeSet userList.stream().collect(Collectors.toCollection(TreeSet::new));// 2.基本类型转SetTreeSetString nameTreeSet userList.stream().map(User::getName).collect(Collectors.toCollection(TreeSet::new));// 3.自定义不可重复(去重)规则TreeSetUser userDefineSet userList.stream().collect(Collectors.toCollection(() - new TreeSet(new ComparatorUser() {Overridepublic int compare(User o1, User o2) {return o1.getName().compareTo(o2.getName());}})));4.1.11 mapping
简单使用mapping // 1.与.map等效ListString names1 userList.stream().map(User::getName).collect(Collectors.toList());ListString names2 userList.stream().collect(Collectors.mapping(User::getName, Collectors.toList()));分组后转换list元素的类型复杂对象的属性转换和收集
// 2.与groupBy搭配使用分组后变换元素类型 User - AddressMapString, ListAddress collect userList.stream().collect(Collectors.groupingBy(User::getName, Collectors.mapping(p - {Address address new Address();address.setContent(p.getDesc());return address;}, Collectors.toList())));// 与groupBy和join结合使用 拼接字符串MapString, String map1 userList.stream().collect(Collectors.groupingBy(User::getName, Collectors.mapping(User::getDesc, Collectors.joining(,, [, ]))));map1.entrySet().stream().forEach(p - {System.out.println(p.getKey() : p.getValue());});4.1.12 joining // 常用于字符串拼接String str list.stream().collect(Collectors.joining(,, [, ]));System.out.println(str str);4.1.13 partitioningBy // partitioningBy 根据Predicate? super T predicate汇聚成含有两个元素的map// 其中一个key为Boolean.TRUE另一个为Boolean.FALSEvalue为满足条件的集合MapBoolean, ListUser collect1 userList.stream().collect(Collectors.partitioningBy(p - {return p.getAge() 18;}, Collectors.toList()));
4.1.14 collectingAndThen
该方法的作用可以简单地概括为“先收集再做一些操作”。 // 1.常用于去重后TreeSet转成List// 解析 通过Collectors.toCollection收集TreeSet排序去重然后通过collectingAndThen收集转成ListListUser userList5 userList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() - new TreeSet(Comparator.comparing(User::getName))), ArrayList::new));// 最终结果可以理解为如下操作TreeSetUser treeSet userList.stream().collect(Collectors.toCollection(() - new TreeSet(Comparator.comparing(User::getName))));ListUser users new ArrayList(treeSet);// 2.收集成TreeSetUser后转成ListAddress, 详细写法ListAddress addressList userList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() - new TreeSet(Comparator.comparing(User::getName))), p - {ListAddress list1 new ArrayList();p.stream().forEach(c - {Address build Address.builder().content(c.getDesc()).build();list1.add(build);});return list1;}));//3.简化流式写法如下userList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() - new TreeSet(Comparator.comparing(User::getName))), p - p.stream().collect(Collectors.mapping(c - Address.builder().content(c.getDesc()).build(), Collectors.toList()))));
4.2. 自定义收集器
你还可以使用Collectors.collectingAndThen()或Collector.of()来创建自定义的收集器。
ListString namesList names.stream().collect(Collectors.collectingAndThen(Collectors.toList(),Collections::unmodifiableList));上面的代码示例将流中的元素收集到一个列表中并立即将这个列表转换为不可修改的列表。
4.3 归约Reduce
reduce(BinaryOperatorT accumulator) 方法通过重复结合流中的元素将它们归约成一个值。 // 1.无初始值 注意orElse为Optional的方法(不推荐)Integer sumOrElse userList.stream().map(User::getAge).reduce(Integer::sum).orElse(0);// 2.有初始值这种形式的 reduce 接受一个初始值和一个 BiFunctionT, T, T (推荐)Integer sum userList.stream().map(User::getAge).reduce(0, Integer::sum);// 3.对象合并可累加、累乘等User reduce userList.stream().reduce(new User(), (o1, o2) - {return User.builder().age(o1.getAge() o1.getAge()).level(o1.getLevel() o2.getLevel()).money(o1.getMoney() o2.getMoney()).build();});推荐使用有初始值的 reduce因为它可以优雅地处理空流的情况并允许你指定一个明确的初始值(可不为0)。
reduce 操作非常灵活不仅可以用于求和、求积等简单单数据的聚合操作还可以实现更复杂的归约逻辑如字符串连接、对象合并(如案例3)等。
4.4 查找元素 findFirst、findAny // 1.可结合排序使用,获取第一个元素OptionalUser first userList.stream().findFirst();// 2.任意元素OptionalUser any userList.stream().findAny();4.5 匹配 anyMatch、allMatch、noneMatch // 1.anyMatch有一个满足条件就返回trueboolean anyMatch userList.stream().anyMatch(p - p.getAge() p.getLevel());// 2.allMatch所有元素都满足条件就返回trueboolean allMatch userList.stream().allMatch(p - p.getAge() p.getLevel());// 3.noneMatch 没有元素满足条件就返回trueboolean noneMatch userList.stream().noneMatch(p - p.getAge() p.getLevel());4.6 count max min // 1.获取流中元素的个数如果List,则与list.size()等效long count userList.stream().count();// 2.根据age字段获取age最大值对应的对象,返回Optional可用orElse规避nullUser user userList.stream().max(Comparator.comparing(User::getAge)).orElse(new User());// 3.同理根据level字段获取level最小值对应的对象User user6 userList.stream().min(Comparator.comparing(User::getLevel)).orElse(new User());
五、并行流
Java 8 引入了并行流的概念允许你以并行方式处理数据集合以利用多核处理器的优势。你可以通过调用 stream() 方法的并行版本 parallelStream() 来获取一个并行流。
ListString strings Arrays.asList(apple, banana, cherry, ...);
long count strings.parallelStream().filter(s - s.startsWith(a)).count();注意并行流可能会同时处理多个元素因此流中的操作必须是线程安全的。
六、总结
6.1 Stream的优点 代码更简洁、偏声明式的编码风格更容易体现出代码的逻辑意图逻辑间解耦一个stream中间处理逻辑无需关注上游与下游的内容只需要按约定实现自身逻辑即可效率高并行流场景效率会比迭代器逐个循环更高函数式接口延迟执行的特性中间管道操作不管有多少步骤都不会立即执行只有遇到终止操作的时候才会开始执行可以避免一些中间不必要的操作消耗 6.2 Stream的缺点
Stream也不全是优点在有些方面也有其弊端 调试不便代码调测debug不便需要时间适应程序员从历史写法切换到Stream时需要一定的学习、适应时间 以上即为java1.8版本Stream处理集合等数据的方法介绍篇幅较长仅供参考。