转载

Java Stream流还可以这样玩

Java8 Stream

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

什么是Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。

  • 数据源流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。

  • 聚合操作类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。

  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

生成流

在 Java 8 中, 集合接口有两个方法来生成流:

  • stream()− 为集合创建串行流。

  • parallelStream()− 为集合创建并行流。

List<String> strings = Arrays.asList("AAA", "BBB", "CCC", "DDD");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
复制代码

常用方法

1.filter(T->Boolean)

筛选Boolean为true的数据

//筛选查询ID=20 的数据
List<CustomerVO> customerVOList = getArrayList();
List<CustomerVO> idList= customerVOList.stream().filter(customerVO -> customerVO.getId().equals(20)).collect(Collectors.toList());

复制代码

2.distinct()

去除重复元素,根据类的equals判断是否相同

//筛选ID大于0并且去重的数据
List<CustomerVO> customerDistinctList =customerVOList.stream().filter(t->t.getId().compareTo(0)==1).distinct().collect(Collectors.toList());

复制代码

3.map(T -> R)

将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流

//1.获取到customerVOList中的收货方
List<String> receiveNoList = customerVOList.stream().map(CustomerVO::getReceiveNo).collect(Collectors.toList());
//filter和map函数结合
List<String> receiveNoList2=customerVOList.stream().filter(customerVO -> customerVO.getId().equals(20)).map(CustomerVO::getReceiveNo).collect(Collectors.toList());

复制代码

4.anyMatch(T -> boolean)

流中是否有一个元素匹配给定的 T -> boolean 条件

//customerVOList是否存在一个 CustomerVO 对象的 id 等于 20:
boolean resultBool= customerVOList.stream().allMatch(person -> person.getId() == 20);
复制代码

5.anyMatch(T -> boolean)

//customerVOList是否 CustomerVO 对象的 id 都等于 20:
boolean resultBool= customerVOList.stream().allMatch(person -> person.getId() == 20);
复制代码

6. noneMatch(T -> boolean)

//customerVOList是否不存在 CustomerVO 对象的 id 等于 20:
boolean resultBool= customerVOList.stream().noneMatch(person -> person.getId() == 20);
复制代码

7. findAny() 和 findFirst()

  • findAny():找到其中一个元素 (使用 stream() 时找到的是第一个元素;使用 parallelStream() 并行时找到的是其中一个元素)

  • findFirst():找到第一个元素

  • 这两个方法返回的是一个 Optional 对象,它是一个容器类,能代表一个值存在或不存在

  • limit,findFirst, 因为这两个方法会考虑元素的顺序性,而并行本身就是违背顺序性的,也是因为如此 findAny 一般比 findFirst 的效率要高

//findFirst
Optional<CustomerVO> voOptional= customerVOList.stream().filter(cp->cp.getId().compareTo(0)==0).findFirst();
  if (voOptional.isPresent()){
   System.out.println(voOptional.get());
  }
//findAny  
Optional<CustomerVO> voOptional= customerVOList.stream().filter(cp->cp.getId().compareTo(0)==0).findAny();
  if (voOptional.isPresent()){
   System.out.println(voOptional.get());
  }
复制代码

8. flatMap(T -> Stream)

将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流

eg:1
//查询收货方
List<String> receiveNoList = customerVOList.stream().map(CustomerVO::getReceiveNo).collect(Collectors.toList());
//eg:2
List<String> list = new ArrayList<>();
list.add("aaa bbb ccc");
list.add("ddd eee fff");
list.add("ggg hhh iii");

list = list.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(toList());

复制代码

上面例子中,我们的目的是把 List 中每个字符串元素以" "分割开,变成一个新的 List。 首先 map 方法分割每个字符串元素,但此时流的类型为 Stream<String[ ]>,因为 split 方法返回的是 String[ ] 类型;所以我们需要使用 flatMap 方法,先使用Arrays::stream将每个 String[ ] 元素变成一个 Stream 流,然后 flatMap 会将每一个流连接成为一个流,最终返回我们需要的 Stream

9. limit(long n)

返回前n个元素

//返回前2个元素
list = customerVOList.stream()
            .limit(2)
            .collect(toList());

复制代码

10. skip(long n)

去除前n和元素

list = customerVOList.stream()
            .skip(2)
            .collect(toList());

复制代码

tips:

  • 用在 limit(n) 前面时,先去除前 m 个元素再返回剩余元素的前 n 个元素

  • limit(n) 用在 skip(m) 前面时,先返回前 n 个元素再在剩余的 n 个元素中去除 m 个元素

//skip/limit 获取List中低n->m的数据 [获取id 2到10之间的数据]
customerVOList.stream().sorted(Comparator.comparing(CustomerVO::getId).reversed()).skip(2).limit(10).collect(Collectors.toList());


复制代码

11.sorted() / sorted((T, T) -> int)

如果流中的元素的类实现了 Comparable 接口,即有自己的排序规则,那么可以直接调用 sorted() 方法对元素进行排序,如 Stream

反之, 需要调用 sorted((T, T) -> int) 实现 Comparator 接口

//根据ID大小进行比较
list = customerVOList.stream()
           .sorted((p1, p2) -> p1.getId() - p2.getId())
           .collect(toList())
//还以可以写成
customerVOList.stream().filter(cp->cp.getId().compareTo(0)==1).   sorted(Comparator.comparing(CustomerVO::getId).reversed().thenComparing(CustomerVO::getId)).collect(Collectors.toList());
    
//可以简化为
list = customerVOList.stream()
           .sorted(Comparator.comparingInt(CustomerVO::getId))
           .collect(toList());

复制代码

12. forEach()

//使用forEash调用方法
customerVOList.stream().forEach(cp->getSendNOLambda(cp.getSendNo(),cp.getReceiveNo()));

//当ID大于0循环输出
customerVOList.stream().filter(cp->cp.getId()>0).forEach(System.out::println);

private void getSendNOLambda(String sendNo,String receiveNo){
 System.out.println(sendNo+','+receiveNo);
}

复制代码

13.Map

//转换为Map[获取ID大于0的发货方和收货方转换为Map]
Map<String,String> stringMap=customerVOList.stream().filter(customerVO -> customerVO.getId()>0).collect(Collectors.toMap(CustomerVO::getSendNo,CustomerVO::getReceiveNo));

复制代码

14.toArray

//1.不带参数返回的是Object数组
  Object[] receiveNoArray= customerVOList.stream().filter(cp->cp.getId()>0).map(CustomerVO::getReceiveNo).toArray();

  String[] receiveArray= customerVOList.stream().filter(cp->cp.getId()>0).map(CustomerVO::getReceiveNo).toArray(String[]::new);

  CustomerVO[] customerVOArray= customerVOList.stream().filter(cp->cp.getId()>0).toArray(CustomerVO[]::new);

复制代码

15. groupingBy 分组

groupingBy 用于将数据分组,最终返回一个 Map 类型

//其中返回的 Map 键为 Integer 类型,值为 Map<T, List> 类型,即参数中 groupBy(...) 返回的类型
Map<Integer, List<CustomerVO>> map = list.stream().collect(groupingBy(CustomerVO::getId));

复制代码
// groupingBy(CustomerVO::getId) 等同于 groupingBy(CustomerVO::getId, toList())

复制代码

16. 取最值

maxBy,minBy 两个方法,需要一个 Comparator 接口作为参数

//1.最大值
Optional<CustomerVO> optional = customerVOList.stream().collect(maxBy(comparing(CustomerVO::getId)));
//2.最小值
Optional<CustomerVO> optiona2 = customerVOList.stream().collect(minBy(comparing(CustomerVO::getId)));
//优化
Optional<CustomerVO> optional = customerVOList.stream().max(comparing(CustomerVO::getId));

复制代码

17.汇总

//1.计算总数
long listCount = customerVOList.stream().collect(counting());
long listCount2 = customerVOList.stream().count();//推荐

//2.summingInt ,summingLong ,summingDouble
Integer sum = customerVOList.stream().collect(summingInt(CustomerVO::getMoney));
Integer sum2 = customerVOList.stream().mapToInt(CustomerVO::getMoney).sum();
//3.averagingInt,averagingLong,averagingDouble
Double average = customerVOList.stream().collect(averagingInt(CustomerVO::getMoney));
OptionalDouble average2 = customerVOList.stream().mapToInt(CustomerVO::getAge).getMoney();

复制代码

**推荐阅读 **

Java 8系列之Stream的基本语法详解

Java集合Stream类filter的使用

关注

如果你觉得我的文章对你有帮助话,欢迎点赞:+1: 关注:heart: 分享:busts_in_silhouette:! 如果本篇博客有任何错误,请批评指教,不胜感激! 点个在看,分享到朋友圈,对我真的很重要!!!

Java Stream流还可以这样玩
snailThink.png
原文  https://juejin.im/post/5f002b46f265da23062461ab
正文到此结束
Loading...