Java 8 新特性之流—Stream 操作总结(持续更新)

2024-01-16 07:44

本文主要是介绍Java 8 新特性之流—Stream 操作总结(持续更新),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 一、生成流
    • 1.集合创建流
    • 2.数组创建流
    • 3.使用Stream.of() 创建流
  • 二、中间操作
    • 1.filter:用于通过设置的条件过滤出元素
    • 2.map:对每个元素执行某种操作并返回一个新的Stream
    • 3.flatMap:将多个Stream组合成一个Stream
    • 4.concat:合并两个流
    • 5.distinct:去除重复元素
    • 6.sorted:排序
    • 7.limit:截取Stream的前n个元素
    • 8.skip:跳过Stream的前n个元素
  • 三、终止操作
    • 1.forEach:遍历Stream中的每个元素
    • 2.count:统计元素的个数
    • 3.max&min:查找最大/最小元素
    • 4.reduce:对元素进行计算,得到值并返回
    • 5.allMatch&anyMatch&noneMatch:判断是否存在匹配条件的元素
    • 6.collect:将Stream中的元素聚合到一个新的集合中
    • 7.findFirst&findAny:返回Stream中的某个元素
    • 8.averagingInt&averagingLong&averagingDouble:求平均值
    • 9.summingInt&summingLong&summingDouble:求和
    • 10.joining:拼接
    • 11.groupingBy&partitioningBy:分组及分区
  • 四、常用场景
    • 1.list转map
    • 2.map转list
    • 3.求和&极值
    • 4.去重&拼接
    • 5.统计:和、数量、最大值、最小值、平均值
    • 6.某个值的数量
    • 7.根据订单号+订单行号进行分组
  • 总结


前言

在我们开发中,经常会对集合进行过滤映射去重排序聚合统计遍历归集分组拼接等常用操作,为了写出高效率、干净、简洁的代码,Java 8 API 提供了流 Stream API 来进行处理。


提示:以下是本篇文章正文内容,下面案例可供参考

一、生成流

1.集合创建流

List<String> list = Arrays.asList("a", "b", "c", "d", "e","", "f");
Stream<String> stream = list.stream(); 					// 创建一个串行流
Stream<String> parallelStream = list.parallelStream();  // 创建一个并行流

2.数组创建流

int[] array = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(array);

3.使用Stream.of() 创建流

Stream<String> stream = Stream.of("a", "b", "c");

二、中间操作

1.filter:用于通过设置的条件过滤出元素

  • 筛选出不是 c 的其他字符串,形成新的集合
List<String> list = Arrays.asList("a", "b", "c", "d");
List<String> result = list.stream()            // 转化为一个流.filter(line -> !"c".equals(line))     // 排除 "c".collect(Collectors.toList());         // 把输出流收集回List中
result.forEach(System.out::println);           // 输出 : a, b, d
  • 筛选出工资大于10000的非项目经理的职员
List<Employee> newList = list.stream().filter(item -> {return item.getSalary().compareTo(new BigDecimal(10000)) > 0 && !"项目经理".equals(item.getWorkType());}).collect(Collectors.toList());

2.map:对每个元素执行某种操作并返回一个新的Stream

  • 取出user对象中name集合,常用操作
List<String> names = users.stream().map(User::getName).collect(Collectors.toList());
  • 将字符串全部转为大写,执行的操作不需要返回
List<String> list1 = Arrays.asList("a", "b", "c", "d");
List<String> upper1 = list1.stream().map(String::toUpperCase)					// 第一种.collect(Collectors.toList());
List<String> upper2 = list1.stream().map(o -> o.toUpperCase(Locale.ENGLISH))	// 第二种,与第一种一样,第一种是简写.collect(Collectors.toList());
  • 将用户的年龄+1,并返回的是user对象,此时执行的操作是需要返回的,可以使用peek代替
User u1 = new User(); u1.setAge(1); u1.setName("n1");
User u2 = new User(); u2.setAge(2); u2.setName("n2");
List<User> users = new ArrayList<>(); users.add(u1); users.add(u2);
List<User> collect = users.stream().map(o -> {						// 这种有返回值的map操作可以使用peek来代替o.setAge(o.getAge() + 1);return o;					// 将修改的年龄重新赋值,并返回}).collect(Collectors.toList());
// 使用peek来代替返回
List<User> collect = users.stream().peek(o -> o.setAge(o.getAge() + 1)).collect(Collectors.toList());

3.flatMap:将多个Stream组合成一个Stream

List<String> list = Arrays.asList("a,b,c,d", "1,2,3,4");
List<String> listNew = list.stream().flatMap(s -> {// 将每个元素转换成一个streamString[] split = s.split(",");return Arrays.stream(split);}).collect(Collectors.toList());System.out.println(listNew);	// [a, b, c, d, 1, 2, 3, 4]

4.concat:合并两个流

String[] arr1 = { "a", "b", "c", "d" };
String[] arr2 = { "d", "e", "f", "g" };
//创建两个流
Stream<String> stream1 = Stream.of(arr1);
Stream<String> stream2 = Stream.of(arr2);
Stream<String> concatStream = Stream.concat(stream1, stream2);

5.distinct:去除重复元素

List<String> collect = list.stream().distinct().collect(Collectors.toList());
System.out.println(list);		// [a, b, c, d, d, e, f, g]
System.out.println(collect);	// [a, b, c, d, e, f, g]

6.sorted:排序

  • 按年龄升序排序(自然排序)
List<User> newList = users.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());
  • 按年龄降序排序(reversed)
List<User> newList2 = users.stream().sorted(Comparator.comparing(User::getAge).reversed()).collect(Collectors.toList());
  • 先按年龄排,再按工资排,升序(thenComparing)
List<User> newList3 = users.stream().sorted(Comparator.comparing(User::getAge).thenComparing(User::getSalary)).collect(Collectors.toList());
  • 自定义排序,先按工资排,再按年龄排(降序)
List<User> newList4 = users.stream().sorted((p1, p2) -> {if (p1.getSalary().equals(p2.getSalary())) {return p2.getAge() - p1.getAge();} else {return p2.getSalary() - p1.getSalary();}}).collect(Collectors.toList());

7.limit:截取Stream的前n个元素

List<String> collect = list.stream().limit(2).collect(Collectors.toList());

8.skip:跳过Stream的前n个元素

List<String> collect = list.stream().skip(2).collect(Collectors.toList());

三、终止操作

1.forEach:遍历Stream中的每个元素

users.forEach(o -> {o.setSalary(1);System.out.println(o);});
  • 遍历集合等价于 for 循环或增强 for 循环
IntStream.range(0, list.size()).forEach(i -> list.get(i).setOrderNum(i));
// 等价于
for (int i = 0; i < list.size(); i++) {list.get(i).setOrderNum(i);
}

2.count:统计元素的个数

long count = list.stream().map(User::getAge).count();

3.max&min:查找最大/最小元素

  • max:查找最大元素
Optional<User> max = list.stream().max(Comparator.comparing(User::getAge));
Optional<Integer> max = list.stream().map(User::getAge).max(Integer::compare);
  • min:查找最小元素
Optional<User> max = list.stream().min(Comparator.comparing(User::getAge));

4.reduce:对元素进行计算,得到值并返回

//求和1
Stream<Integer> stream1 = Stream.of(1,2,3,4);
System.out.println("sum:" + stream1.reduce(0, Integer::sum));//求和2
Stream<Integer> stream2 = Stream.of(1,2,3,4);
Optional<Integer> reduce = stream2.reduce(Integer::sum);
reduce.ifPresent(integer -> System.out.println("sum:" + integer));//求最大值
Stream<Integer> stream3 = Stream.of(1,2,3,4);
System.out.println("max:" + stream3.reduce(0, (a, b) -> (a >= b ? a : b)));

5.allMatch&anyMatch&noneMatch:判断是否存在匹配条件的元素

  • allMatch:若所有的元素都匹配条件,则结果为 true
Stream<Integer> stream1 = Stream.of(1,2,3,4);
System.out.println("result1:" + stream1.allMatch(i -> i > 0)); // 都大于0,true
  • anyMatch:只要有一个元素匹配条件,则结果为 true
Stream<Integer> stream2 = Stream.of(1,2,3,4);
System.out.println("result2:" + stream2.anyMatch(i -> i > 3)); // 有一个4大于3,true
  • noneMatch:若所有的元素都不匹配条件,则结果为 true
Stream<Integer> stream3 = Stream.of(1,2,3,4);
System.out.println("result3:" + stream3.noneMatch(i -> i > 3)); // 只有一个不匹配,false

6.collect:将Stream中的元素聚合到一个新的集合中

  • 归集collect(toList、toSet、toMap)
List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());Map<String, Person> map = list.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toMap(Person::getName, p -> p));

7.findFirst&findAny:返回Stream中的某个元素

  • findFirst:返回Stream中的第一个元素
Stream<Integer> stream1 = Stream.of(1,2,3,4);//获取第一个值
Optional<Integer> first = stream1.findFirst();
System.out.println("first:" + first.get());
  • findAny:返回Stream中的任意一个元素
Stream<Integer> stream2 = Stream.of(1,2,3,4);//获取任意一个值, 但是正常情况下一般会取第一个元素,在并行流的情况下会随机取一个元素
Optional<Integer> any = stream2.parallel().findAny();
System.out.println("any:" + any.get());

8.averagingInt&averagingLong&averagingDouble:求平均值

// 求平均年龄
Double average = list.stream().collect(Collectors.averagingInt(User::getAge));

9.summingInt&summingLong&summingDouble:求和

// 求年龄之和
Integer sum = list.stream().collect(Collectors.summingInt(User::getAge));// 推荐使用下面这种方式:.mapToInt + sum
Integer sum = list.stream().mapToInt(User::getAge).sum();

10.joining:拼接

List<String> list = Arrays.asList("1","2","3","4");// 以空字符拼接,输出 1234
String result1 = list.stream().collect(Collectors.joining());// 以“-”符号拼接,输出 1-2-3-4
String result2 = list.stream().collect(Collectors.joining("-"));// 传多个参数,输出 [1-2-3-4]
String result= list.stream().collect(Collectors.joining("-", "[", "]"));

11.groupingBy&partitioningBy:分组及分区

  • 将员工按性别分组
Map<String, List<User>> group = list.stream().collect(Collectors.groupingBy(User::getSex));
  • 多条件分组:将员工先按性别分组,再按地区分组
Map<String, Map<String, List<User>>> group2 = list.stream().collect(Collectors.groupingBy(User::getSex, Collectors.groupingBy(User::getArea)));
  • 将员工按薪资是否高于8000分为两个组
Map<Boolean, List<User>> part = list.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));

四、常用场景

1.list转map

场景1:将 user 集合转换成以 id 为 key,以 name 为 value 的 map

注意事项:(k1, k2) -> k2 避免键重复(会报错Duplicate key xxx) k1-取第一个数据;k2-取最后一条数据

其中 item -> item.getName() 如果没有其他操作(比如value为name_age需拼接),可以转化为 User::getName

Map<Integer, String> userMap = userList.stream().collect(Collectors.toMap(User::getId, item -> item.getName(), (k1, k2) -> k1));

场景2:将 user 集合转换成以 name_age 为 key,user对象为 value 的 map
key:name_age,value:user对象,其中 item -> item 可以也换为 Function.identity()

Map<String, User> userMap = userList.stream().collect(Collectors.toMap(item -> item.getName() + "_" + item.getAge(),item -> item, (k1, k2) -> k1));

2.map转list

场景3:在map里面构造数据 return什么数据就转成什么类型的list

List<Employee> collect = map.entrySet().stream().map(item -> {Employee employee = new Employee();employee.setId(item.getKey());employee.setEmpName(item.getValue());return employee;}).collect(Collectors.toList());

3.求和&极值

场景4:经常会用到 bigdecimal 进行求值操作

//Bigdecimal求和/极值:
BigDecimal sum = list.stream().map(Employee::getSalary).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal max = list.stream().map(Employee::getSalary).reduce(BigDecimal.ZERO, BigDecimal::max);//基本数据类型求和/极值:
Integer sum = list.stream().mapToInt(Employee::getId).sum();
Long sum = list.stream().mapToLong(Employee::getId).sum();
Double sum = list.stream().mapToDouble(Employee::getId).sum();

4.去重&拼接

场景5:对 list 进行去重 或 去重后按指定形式拼接返回

String userName = userList.stream().map(User::getName).distinct().collect(Collectors.joining(","));
List<String> collect = userList.stream().map(User::getName).distinct().collect(Collectors.toList());// 按多个字段去重
ArrayList<User> collect = userList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(p -> p.getName() + "_" + p.getAge()))), ArrayList::new));

5.统计:和、数量、最大值、最小值、平均值

场景6:对 list 中数据进行相关统计

IntSummaryStatistics collect = userList.stream().collect(Collectors.summarizingInt(User::getAge));
System.out.println("和:"     + collect.getSum());
System.out.println("数量:"   + collect.getCount());
System.out.println("最大值:" + collect.getMax());
System.out.println("最小值:" + collect.getMin());
System.out.println("平均值:" + collect.getAverage());// 平均值
OptionalDouble average = list.stream().mapToInt(Employee::getId).average();
average.getAsDouble();

6.某个值的数量

场景7:计算得到某个薪水的个数,如:5000元的有2个(5000, 2)

Map<Integer, Long> collect = userList.stream().collect(Collectors.groupingBy(User::getSalary, Collectors.counting()));

7.根据订单号+订单行号进行分组

场景8:根据订单号+订单行号分组后进行数据处理

// 按照 age 进行分组
Map<Integer, List<User>> collect = userList.stream().collect(Collectors.groupingBy(User::getAge));// 按照 age_salary 进行分组
Map<String, List<User>> collect = userList.stream().collect(Collectors.groupingBy(o -> o.getAge() + "_" + o.getSalary()));

总结

该有的迟早会有,过分强求也无谓。该失去的,也迟早会失去,正如人生百年,终有一死。倒不如珍惜眼前的平凡生活,享受生活带来的苦乐。

在这里插入图片描述

这篇关于Java 8 新特性之流—Stream 操作总结(持续更新)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/611800

相关文章

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

SpringBoot3.4配置校验新特性的用法详解

《SpringBoot3.4配置校验新特性的用法详解》SpringBoot3.4对配置校验支持进行了全面升级,这篇文章为大家详细介绍了一下它们的具体使用,文中的示例代码讲解详细,感兴趣的小伙伴可以参考... 目录基本用法示例定义配置类配置 application.yml注入使用嵌套对象与集合元素深度校验开发