1.遍历/匹配(foreach/find/match)
Stream
也是支持类似集合的遍历和匹配元素的,只是Stream
中的元素是以Optional
类型存在的。Stream
的遍历、匹配非常简单。
| List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 7, 8, 9, 0, 100); |
| |
| Optional<Integer> first = list.stream().findFirst(); |
| log.info(first.get().toString()); |
| |
| |
| boolean b1 = list.stream().anyMatch(value -> value >= 100); |
| boolean b2 = list.stream().anyMatch(value -> value > 10); |
| log.info(String.valueOf(b1)); |
| log.info(String.valueOf(b2)); |
| |
| |
| list.stream().filter(value -> value > 4).forEach(System.out::print); |
| System.out.println(); |
| list.forEach(System.out::print); |
2.筛选(filter)
筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。
| |
| List<Integer> list = Arrays.asList(1, 3, 4, 5, 6, 7, 8, 9, 10, 20); |
| |
| ArrayList<Integer> arrayList1 = new ArrayList<>(); |
| list.stream().filter(value -> value > 4).forEach(value -> arrayList1.add(value)); |
| log.info(arrayList1.toString()); |
| |
| ArrayList<Integer> arrayList2 = new ArrayList<>(); |
| list.stream().filter(value -> value <= 4).forEach(arrayList2::add); |
| log.info(arrayList2.toString()); |
| |
| |
| List<User> userList1 = Arrays.asList( |
| new User(1, "xw", "男"), |
| new User(2, "zgx", "男"), |
| new User(3, "gg", "男"), |
| new User(4, "whb", "男"), |
| new User(5, "yda", "男"), |
| new User(6, "bhm", "女") |
| ); |
| |
| List<User> userList2 = new ArrayList<>(); |
| userList1.stream().filter(user -> user.getId() > 2).forEach(userList2::add); |
| log.info(userList2.toString()); |
| |
| userList1.stream().filter(user -> user.getName().equals("xw")).forEach(System.out::println); |
| |
| HashMap<String, Optional<User>> userHashMap = new HashMap<>(); |
| Optional<User> man = userList1.stream().filter(user -> user.getSex().equals("男")).findFirst(); |
| userHashMap.put("man", man); |
| log.info(userHashMap.toString()); |
3.聚合(max/min/count)
max
、min
、count
这些字眼你一定不陌生,没错,在mysql中我们常用它们进行数据统计。Java stream中也引入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作。
max、min、count
| |
| List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 89, 9, 0, 10, 20, 30); |
| |
| Optional<Integer> max = list.stream() |
| .max(Comparator.comparing(Integer::intValue)); |
| log.info(String.format("最大值是:%d", max.get())); |
| |
| Optional<Integer> min = list.stream() |
| .min(Comparator.comparing(value -> value.intValue())); |
| log.info(String.format("最小值是:%d", min.get())); |
| |
| Integer count1 = Math.toIntExact(list.stream().count()); |
| log.info(String.format("list总元素量1为:%d", count1)); |
| |
| Integer count2 = Math.toIntExact(list.stream().filter(value -> value > 5).count()); |
| log.info(String.format("list元素值大于5的个数:%d", count2)); |
| |
| |
| List<User> userList = Arrays.asList( |
| new User(1, "xw", "男", 22), |
| new User(2, "zgx", "男", 22), |
| new User(3, "whb", "男", 23), |
| new User(4, "gg", "男", 30), |
| new User(5, "yda", "男", 22), |
| new User(6, "bhm", "女", 22), |
| new User(7, "lwn", "女", 22) |
| ); |
| Optional<User> ageMax = userList.stream().max(Comparator.comparing(value -> value.getAge())); |
| log.info(String.format("年龄最大的是:%s", ageMax.get())); |
| |
| Optional<User> ageMin = userList.stream().filter(user -> user.getSex().equals("男")).min(Comparator.comparing(User::getAge)); |
| log.info(String.format("性别为男且年龄最小的:%s", ageMin.get())); |
| |
| Integer count3 = Math.toIntExact(userList.stream().filter(user -> user.getAge() > 22).count()); |
| log.info(String.format("年龄大于22的用户数量为:%d", count3)); |
4.映射(map/flatMap)
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map
和flatMap
:
map
:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap
:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
map
| |
| List<Integer> list1 = Arrays.asList(1, 3, 5, 6, 7, 8, 0, 10, 20, 22, 39); |
| List<Integer> collect1 = list1.stream().filter(value -> value > 7).collect(Collectors.toList()); |
| log.info(String.format("list1元素值大于7的有: %s", collect1)); |
| |
| List<String> list2 = Arrays.asList("xw", "sjdk", "sf", "jk", "hoksh", "shdfj", "jhgkj"); |
| List<String> collect2 = list2.stream().map(String::toUpperCase).collect(Collectors.toList()); |
| log.info(String.format("list2元素值全转大写,结果:%s", collect2)); |
| |
| List<User> userList1 = Arrays.asList( |
| new User(1, "xw", "男", 22), |
| new User(2, "zgx", "男", 22), |
| new User(3, "whb", "男", 23), |
| new User(4, "gg", "男", 30), |
| new User(5, "yda", "男", 22), |
| new User(6, "bhm", "女", 22), |
| new User(7, "lwn", "女", 22), |
| new User(8, "ksj", "女", 22) |
| ); |
| List<User> userList2 = userList1.stream() |
| .map(user -> { |
| if (user.getSex().equals("女")) { |
| user.setAge(user.getAge() - 2); |
| } |
| user.setName(user.getName().toUpperCase()); |
| return user; |
| }) |
| .filter(user -> user.getAge() > 19 && user.getSex().equals("女")) |
| .collect(Collectors.toList()); |
| log.info(String.format("修改结果为:%s", userList2)); |
flatMap
| |
| List<String> stringList = userList1.stream() |
| .flatMap(user -> { |
| Stream<String> stream = Arrays.stream(user.toString().split("=")); |
| return stream; |
| }) |
| .collect(Collectors.toList()); |
| log.info(String.format("flatMap处理前:%s", userList1)); |
| log.info(String.format("flatMap转换结果:%s", stringList)); |
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和
、求乘积
和求最值
操作。
| |
| List<Integer> list1 = Arrays.asList(1, 3, 5, 2, 1, 5, 89, 23, 89, 23, 34); |
| Integer sum = list1.stream().reduce(0, Integer::sum); |
| log.info(String.format("list1中各元素之和:%d", sum)); |
| |
| |
| List<Integer> list2 = Arrays.asList(1, 2, 4); |
| Optional<Integer> product = list2.stream().reduce((x, y) -> x * y); |
| log.info(String.format("list中2各元素之积:%d", product.get())); |
| |
| |
| Optional<Integer> max1 = list1.stream().reduce(Integer::max); |
| log.info(String.format("list1中的最大值是:%d", max1.get())); |
| |
| |
| Optional<Integer> min1 = list1.stream().reduce((x, y) -> x < y ? x : y); |
| log.info(String.format("list1中的最小值:%d", min1.get())); |
| List<User> userList1 = Arrays.asList( |
| new User(1, "xw", "男", 22), |
| new User(2, "zgx", "男", 22), |
| new User(3, "whb", "男", 23), |
| new User(4, "gg", "男", 30), |
| new User(5, "yda", "男", 22), |
| new User(6, "bhm", "女", 23), |
| new User(7, "lsn", "女", 22), |
| new User(8, "ksj", "女", 22) |
| ); |
| |
| Integer maxAge1 = userList1.stream().reduce(0, (maxAge, user) -> maxAge > user.getAge() ? maxAge : user.getAge(), Integer::max); |
| log.info(String.format("年龄最大是:%d", maxAge1)); |
| |
| Optional<Integer> max2 = userList1.stream().map(User::getAge).reduce(Integer::max); |
| Optional<Integer> max3 = userList1.stream().map(User::getAge).reduce((x, y) -> x > y ? x : y); |
| log.info(String.format("年龄最大是:%d", max2.get())); |
| log.info(String.format("年龄最大是:%d", max3.get())); |
| |
| Integer stringMaxLength = userList1.stream() |
| .filter(user -> user.getAge() > 22 && user.getAge() < 25) |
| .flatMap(user -> { |
| Stream<String> newStream = Arrays.stream(user.toString().split("=")); |
| return newStream; |
| }) |
| .collect(Collectors.toList()) |
| .stream().map(String::toUpperCase) |
| .reduce(0, (maxLength, string) -> maxLength > string.length() ? maxLength : string.length(), Integer::max); |
| |
| log.info(String.format("最大字符串长度为:%s", stringMaxLength)); |
6.收集(collect)
collect
,收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。
| collect主要依赖java.util.stream.Collectors类内置的静态方法。 |
6.1归集(toList/toSet/toMap)
因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList
、toSet
和toMap
比较常用,另外还有toCollection
、toConcurrentMap
等复杂一些的用法。
toList
| List<Integer> list1 = Arrays.asList(1, 2, 8, 0, 9, 0, 1, 23, 32, 37, 49, 48); |
| List<Integer> collect1 = list1.stream().filter(value -> value > 5).collect(Collectors.toList()); |
| log.info(String.format("list1中收集>5的结果为:%s", collect1)); |
toSet
| Set<Integer> collect2 = list1.stream().filter(value -> value < 5).collect(Collectors.toSet()); |
| log.info(String.format("list1中收集<5的结果为:%s", collect2)); |
| collect2.forEach(value -> {System.out.print(value + " "); |
toMap
| List<User> userList1 = Arrays.asList( |
| new User(1, "xww", "男", 22), |
| new User(2, "zgx", "男", 22), |
| new User(3, "whb", "男", 23), |
| new User(4, "gg", "男", 30), |
| new User(5, "yda", "男", 22), |
| new User(6, "bhm", "女", 23), |
| new User(7, "lsn", "女", 22), |
| new User(8, "ksj", "女", 22) |
| ); |
| |
| Map<String, User> userMap = userList1.stream() |
| .filter(user -> user.getSex().equals("女")) |
| .collect(Collectors.toMap(User::getName, user -> user)); |
| log.info(String.format("性别为女的用户转map:%s", userMap)); |
6.2 统计(count/averaging)
Collectors
提供了一系列用于数据统计的静态方法:
- 计数:
count
- 平均值:
averagingInt
、averagingLong
、averagingDouble
- 最值:
maxBy
、minBy
- 求和:
summingInt
、summingLong
、summingDouble
- 统计以上所有:
summarizingInt
、summarizingLong
、summarizingDouble
| List<Integer> list = Arrays.asList(1, 2, 3, 2, 5, 3, 9, 8, 7, 6, 29, 10, 22); |
| |
| |
| long count = list.stream().filter(value -> value > 10).count(); |
| log.info(String.format("list中元素>10的个数为:%d", count)); |
| |
| |
| Double average = list.stream().filter(value -> value > 1).collect(Collectors.averagingInt(Integer::intValue)); |
| log.info(String.format("list中元素>1的元素平均值为:%.2f", average)); |
| |
| List<User> userList1 = Arrays.asList( |
| new User(1, "xww", "女", 22), |
| new User(2, "zgx", "男", 22), |
| new User(3, "whb", "男", 23), |
| new User(4, "gg", "男", 30), |
| new User(5, "yda", "男", 22), |
| new User(6, "bhm", "女", 23), |
| new User(7, "lsn", "女", 22), |
| new User(8, "ksj", "女", 22) |
| ); |
| |
| Double averageAge = userList1.stream() |
| .filter(user -> user.getSex().equals("男")) |
| .map(User::getAge) |
| .collect(Collectors.averagingInt(Integer::intValue)); |
| log.info(String.format("男用户的平均年龄为:%d 岁", averageAge.intValue())); |
| |
| |
| int ageSum = userList1.stream() |
| .filter(user -> user.getSex().equals("女")) |
| .mapToInt(User::getAge) |
| .sum(); |
| log.info(String.format("女用户的年龄之和为:%d", ageSum)); |
| |
| |
| IntSummaryStatistics recording = userList1.stream() |
| .filter(user -> user.getSex().equals("男")) |
| .collect(Collectors.summarizingInt(User::getAge)); |
| log.info(String.format("记录所有男用户的年龄各项值,结果为:%s", recording)); |
6.3 分组(partitioningBy/groupingBy)
- 分区:将
stream
按条件分为两个Map
,比如员工按薪资是否高于8000分为两部分。
- 分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。
partitioningBy
| List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 20, 37, 49, 243, 30); |
| |
| |
| Map<Boolean, List<Integer>> collect1 = list.stream() |
| .collect(Collectors.partitioningBy(value -> value > 20)); |
| log.info(String.format("元素值是否大于20进行分组,结果为:%s", collect1)); |
| |
| collect1.forEach((key, value) -> { |
| log.info(String.format("元素值是否大于20进行分组,结果为:%s:%s", key, value)); |
| }); |
groupingBy
| List<User> userList = Arrays.asList( |
| new User(1, "xww", "女", 22), |
| new User(2, "zgx", "男", 21), |
| new User(3, "whb", "男", 23), |
| new User(4, "gg", "男", 30), |
| new User(5, "yda", "男", 22), |
| new User(6, "bhm", "女", 23), |
| new User(7, "lsn", "女", 22), |
| new User(8, "ksj", "女", 22) |
| ); |
| |
| |
| Map<String, List<User>> collect2 = userList.stream() |
| .collect(Collectors.groupingBy(User::getSex)); |
| log.info(String.format("根据性别对用户进行分组,结果为:%s", collect2)); |
| |
| collect2.forEach((key, user) -> { |
| log.info(String.format("根据性别对用户进行分组,结果为:%s:%s", key, user)); |
| }); |
6.4 接合(joining)
joining
可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。
| List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 20, 37, 49, 243, 30); |
| String collect = list.stream() |
| .map(Object::toString) |
| .collect(Collectors.joining("——")); |
| log.info(String.format("joining测试结果为:%s", collect)); |
7.排序(sorted)
sorted,中间操作。有两种排序:
- sorted():自然排序,流中元素需实现Comparable接口
- sorted(Comparator com):Comparator排序器自定义排序
| List<User> userList1 = Arrays.asList( |
| new User(1, "xw", "女", 22), |
| new User(2, "zgx", "男", 21), |
| new User(3, "whb", "男", 23), |
| new User(4, "gg", "男", 30), |
| new User(5, "yda", "男", 22), |
| new User(6, "bhm", "女", 23), |
| new User(7, "lsn", "女", 22), |
| new User(8, "ksj", "女", 22) |
| ); |
| |
| |
| List<User> userList2 = userList1.stream() |
| .sorted(Comparator.comparing(User::getAge)) |
| .collect(Collectors.toList()); |
| log.info(String.format("按照年龄排序,结果为:%s", userList2)); |
| |
| |
| List<String> userName1 = userList1.stream() |
| .sorted(Comparator.comparing(User::getAge)) |
| .map(User::getName) |
| .collect(Collectors.toList()); |
| log.info(String.format("根据年龄从小到大排序:%s", userName1)); |
| |
| |
| List<String> userName2 = userList1.stream() |
| .filter(user -> user.getSex().equals("男")) |
| .sorted(Comparator.comparing(User::getAge).reversed()) |
| .map(User::getName) |
| .collect(Collectors.toList()); |
| log.info(String.format("男用户根据年龄从大到小排序:%s", userName2)); |
8.提取/组合
流也可以进行合并
、去重
、限制
、跳过
等操作。
1.去重排序
| List<Integer> list = Arrays.asList(1, 2, 4, 4, 10, 9, 6, 8, 6, 2, 3, 7, 5); |
| List<Integer> collect = list |
| .stream() |
| .distinct() |
| .sorted(Comparator.comparing(Integer::intValue)) |
| .collect(Collectors.toList()); |
| collect.forEach(x -> System.out.print(x+" ")); |
存在重复数据的问题,这里使用stream流的衍生功能,去除一个对象中的部分元素的重复如下:
| List<User> userList = Arrays.asList( |
| new User(1, "xw", "女", 21), |
| new User(2, "zgx", "男", 21), |
| new User(3, "whb", "男", 23), |
| new User(4, "gag", "男", 30), |
| new User(4, "gbg", "男", 30), |
| new User(4, "gcg", "女", 30), |
| new User(5, "yda", "男", 22), |
| new User(6, "bhm", "女", 23), |
| new User(7, "lsn", "女", 22), |
| new User(8, "ksj", "女", 22) |
| ); |
| ArrayList<User> collect1 = userList.stream().collect(Collectors.collectingAndThen( |
| Collectors.toCollection(() -> new TreeSet<>( |
| Comparator.comparing( |
| User::getId))), ArrayList::new)); |
多个字段或者多个条件去重
| ArrayList<User> collect2 = userList.stream().collect(Collectors.collectingAndThen( |
| Collectors.toCollection(() -> new TreeSet<>( |
| Comparator.comparing(user->user.getName() + ";" + user.getId()))), ArrayList::new) |
以上使用到了collectingAndThen()根据属性进行去重的操作,进行结果集的收集,收集到结果集之后再进行下一步的处理。在这个去重操作中还用到了toCollection、TreeSet两个操作。
| public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,Function<R,RR> finisher) |
看源码中需要传的参数有两个,第一个参数是Collector的子类,所以Collectors类中的大多数方法都能使用,比如:toList(),toSet(),toMap()等,当然也包括collectingAndThen()。第二个参数是一个Function函数,也是去重的关键,用到的ArrayList::new调用到了ArrayList的有参构造。Function函数是R apply(T t),在第一个参数downstream放在第二个参数Function函数的参数里面,将结果设置为t。对于toCollection是一个通用的方法,满足treeSet收集集合,再传入需要根据某个属性进行比较的比较器,就能达到去重的效果。
2.限制长度(limit)
| List<Integer> list = Arrays.asList(1, 2, 7, 3, 2, 2, 3, 4, 5, 2, 5, 6, 7, 8, 9, 0, 12); |
| List<Integer> collect1 = list |
| .stream() |
| .distinct() |
| .sorted(Comparator.comparing(Integer::intValue)) |
| .limit(6) |
| .collect(Collectors.toList()); |
| collect1.forEach(x -> System.out.print(x + " ")); |
3.跳过(skip)
| |
| List<Integer> list = Arrays.asList(1, 2, 7, 3, 2, 2, 3, 4, 5, 2, 5, 6, 7, 8, 9, 0, 12); |
| List<Integer> collect2 = list |
| .stream() |
| .distinct() |
| .sorted(Comparator.comparing(Integer::intValue)) |
| .skip(3) |
| .limit(6) |
| .collect(Collectors.toList()); |
| collect2.forEach(x -> System.out.print(x + " ")); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?