赞
踩
目录
比如有一个Person类的集合:List<Person> personList,可以通过stream()对集合中的元素进行操作,
下面的操作流程可以归纳为 过滤-映射-收集。
- List<Integer> personIdList = personList.stream()
- //选出年龄大于20的Person对象
- .filter(person -> person.getAge() > 20)
- //将Person对象映射成为它的属性id
- .map(Person::getId)
- //收集为List集合
- .collect(Collectors.toList());
上述代码获取到了,年龄大于20岁的人id集合。
- List<DTO> items = new ArrayList<>();
- List<String> collect = items.stream().map(DTO::getId).collect(Collectors.toList());
获取到了DTO中的id的一个list。
- List<vo> list = new ArrayList<>();
- Map<String, String> map = list.stream().collect(Collectors.toMap(vo::getxxx, vo::getxxx));
获得一个list里面的两个属性组成的map。
在 过滤-映射-收集 这个流程中:
过滤和映射属于中间操作,当操作结束时才会触发计算,可以高效地迭代大集合
收集属于结束操作,触发计算。
流操作可以分为 中间操作(惰性求值) 和 结束操作
中间操作指,操作过程中只记录操作而不做执行,直到执行结束操作,才会触发实际的操作,即惰性求值。
中间操作又分为:
无状态操作,元素处理不受之前元素影响,比如map()、filter()、skip()、peek()等
有状态操作,需要拿到所有元素才能进行,比如sorted()、limit()、distinct()等
结束操作是指,拿到所有元素后才能进行的操作。
结束操作又分为:
短路操作,遇到符合条件的元素后就可以终止,比如anyMatch()、findFirst()、findAny()等
非短路操作,需要处理所有元素,比如forEach()、collect()、max()、count()等。
1.将List<Person>映射成一个Map,key为Person的id属性,value为Person实体类
- Map<Integer, Person> PersonMap= personList.stream()
- .collect(Collectors.toMap(Person::getId, person -> person));
2.得到一个Map<Integer,List<Person>>集合,key为Person的age属性,value是按年龄分组后的Person对象集合:
- Map<Integer, List<Person>> personsMap = personList.stream()
- .collect(Collectors.groupingBy(Person::getAge));
3.统计所有人年龄的总和:
- int personAgeSum = personList.stream()
- //根据age属性转换成IntStream
- .mapToInt(Person::getAge)
- .sum();
4.选出List集合中创建时间最晚的数据(createtime属性为Date类型)
- UserInfo userInfoMax = userInfos.stream()
- .max(Comparator.comparing(UserInfo::getCreateTime))
- .get();
-
-
- 这里的max方法实际返回的是Optional<UserInfo>对象该对象可以通过orElse()方法设置对象UserInfo为null时的值:
5.将所有小写字母拼接起来
- String concat = Stream.of("a", "B", "c", "D", "e", "F")
- .filter(x -> x.compareTo("Z") > 0)
- .reduce("", String::concat);
filter 方法用于通过设置条件过滤出元素。以下代码片段使用filter 方法过滤出空字符串:
- List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
- // 获取空字符串的数量
- int count = (int) strings.stream().filter(string -> string.isEmpty()).count();
- UserInfo userInfoMax = userInfos.stream().max(Comparator.comparing(UserInfo::getCreateTime))
- .orElse(为null时的值); //这里如果max返回的对象为null(一般情况不会是),会取orElse()中的值
reduce方法的第一个参数是起始值,第二个参数是流中的元素,迭代流中的数据
也可以只传一个参数,即不指定起始值,这样会返回一个Optional对象
String concat = Stream.of("a", "B", "c", "D", "e", "F") .filter(x -> x.compareTo("Z") > 0) .reduce(String::concat) .orElse("");
6.迭代map
使用foreach迭代map:albumsByArtist是一个map集合
- Map<Artist, Integer> countOfAlbums = new HashMap<>();
- albumsByArtist.forEach((artist, albums) -> {
- countOfAlbums.put(artist, albums.size());
- });
7.使用map缓存
computeIfAbsent()方法接受一个 Lambda 表达式,当值不存在时使用 Lambda 表达式计算新值
Map<String, Artist> artistCache = new HashMap<>();
根据key值name从artistCache获取对应的value,如果没有则调用readArtistFromDB方法获取值
- public Artist getArtist(String name) {
- return artistCache.computeIfAbsent(name, this::readArtistFromDB);
- }
8.limit
limit 方法用于获取指定数量的流。以下代码片段使用 limit 方法打印出 10 条数据:
- Random random = new Random();
- random.ints().limit(10).forEach(System.out::println);
9.sorted
sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:
- Random random = new Random();
- random.ints().limit(10).sorted().forEach(System.out::println);
10.并行(parallel)程序
parallelStream 是流并行处理程序的代替方法。以下实例我们使用parallelStream 来输出空字符串的数量:
- List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
- // 获取空字符串的数量
- int count = (int) strings.parallelStream().filter(string -> string.isEmpty()).count();
11.Collectors
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors可用于返回列表或字符串:
- List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
- List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
- System.out.println("筛选列表: " + filtered);
- String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
- System.out.println("合并字符串: " + mergedString);
12.统计
另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。
- List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
- IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
- System.out.println("列表中最大的数 : " + stats.getMax());
- System.out.println("列表中最小的数 : " + stats.getMin());
- System.out.println("所有数之和 : " + stats.getSum());
- System.out.println("平均数 : " + stats.getAverage());
Stream 顾名思义,相当于批量处理数据的流水线。
在处理一般的数据量下,使用循环方式处理集合和通过stream方式处理集合的性能相差不大,但在数据里更大逻辑更复杂的情况下stream要更优。
而parallelStream并行流,利用多核处理器的优势,并行(同一时间发生)处理数据(这意味着所处理的数据,不应该和顺序相关,否则会因为并行得到错误的结果),能够显著的提高执行速度。
Java8函数式编程书中提到,影响并行流的因素包括:
1.数据大小,并行化处理会带来额外的开销,只有每个数据处理管道花费的时间足够多时才有意义
2.数据结构,分割数据源,即把原有集合分成若干个集合到管道中
3.装箱,处理基本类型要比处理装箱类型快,装箱类型可以使用mapToInt等方法
4.处理器核的数量
5.单元处理开销:处理单个元素的花费时间越长,并行操作带来的性能提升越明显
Stream处理过程简述:
首先将Collection转化为Stream,流上的每个结点都只会返回包含上一结点引用的中间结点,使结点们组成了一个双向链表结构,而不会立即进行任何数据处理。
每个中间操作都实现了Sink接口,实现了 makeSink()
方法用来返回自己的 Sink 实例,
只有当终止操作出现时,才开始将 Sink 实例化执行数据处理,
无状态操作的 Sink 接收到数据,会立即通知下游,有状态操作的 Sink 则会等要处理的数据处理完了才开始通知下游,
终止节点将数据收集起来后就完成了这次操作。
参考文章:
https://www.cnblogs.com/CarpenterLee/archive/2017/03/28/6637118.html
https://zhuanlan.zhihu.com/p/52579165
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。