帅帅的 林财钦_|

园龄:粉丝:关注:

jddk8 stream 使用

一、背景

以前的写法太过繁琐,距离Java 8发布已经过去了7、8年的时间,Java 19也发布了,Java8 的 Stream 流,加上 Lambda 表达式,可以让代码变短简洁。

二、实现

image

Stream可以由数组或集合创建,对流的操作分为两种:

  • 中间操作,每次返回一个新的流,可以有多个。

  • 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。

另外,Stream有几个特性:

  1. stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。

  2. stream不会改变数据源,通常情况下会产生一个新的集合或一个值。

  3. stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。

2 Stream的创建
Stream可以通过集合数组创建。

1、通过 Java.Util.Collection.Stream() 方法用集合创建流
image

**2、使用java.util.Arrays.stream(T[] array)方法用数组创建流
image

3、使用Stream的静态方法:of()、iterate()、generate()
image

输出结果:
image

stream和parallelStream的简单区分: stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数,两者的处理不同之处:

image

如果流中的数据量足够大,并行流可以加快处速度。
除了直接创建并行流,还可以通过parallel()把顺序流转换成并行流:

image

3 Stream的使用
在使用stream之前,先理解一个概念:Optional
image

案例使用的员工类
image

3.1 遍历/匹配(foreach/find/match)
Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。Stream的遍历、匹配非常简单。
image

image

3.2 筛选(filter)
筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。
image

image

image

3.3 聚合(max/min/count)
max、min、count这些字眼你一定不陌生,没错,在mysql中我们常用它们进行数据统计。Java stream中也引入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作。
image

image

image

image

image

3.4 映射(map/flatMap)
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:

map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

image

image

image

案例二:将员工的薪资全部增加1000。

点击查看代码
public class StreamTest {  
 public static void main(String[] args) {  
  List<Person> personList = new ArrayList<Person>();  
  personList.add(new Person("Tom", 8900, 23, "male", "New York"));  
  personList.add(new Person("Jack", 7000, 25, "male", "Washington"));  
  personList.add(new Person("Lily", 7800, 21, "female", "Washington"));  
  personList.add(new Person("Anni", 8200, 24, "female", "New York"));  
  personList.add(new Person("Owen", 9500, 25, "male", "New York"));  
  personList.add(new Person("Alisa", 7900, 26, "female", "New York"));  
  
  // 不改变原来员工集合的方式  
  List<Person> personListNew = personList.stream().map(person -> {  
   Person personNew = new Person(person.getName(), 0, 0, null, null);  
   personNew.setSalary(person.getSalary() + 10000);  
   return personNew;  
  }).collect(Collectors.toList());  
  System.out.println("一次改动前:" + personList.get(0).getName() + "-->" + personList.get(0).getSalary());  
  System.out.println("一次改动后:" + personListNew.get(0).getName() + "-->" + personListNew.get(0).getSalary());  
  
  // 改变原来员工集合的方式  
  List<Person> personListNew2 = personList.stream().map(person -> {  
   person.setSalary(person.getSalary() + 10000);  
   return person;  
  }).collect(Collectors.toList());  
  System.out.println("二次改动前:" + personList.get(0).getName() + "-->" + personListNew.get(0).getSalary());  
  System.out.println("二次改动后:" + personListNew2.get(0).getName() + "-->" + personListNew.get(0).getSalary());  
 }  
}  

image

image

3.5 归约(reduce)
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

案例一:求Integer集合的元素之和、乘积和最大值。

点击查看代码
public class StreamTest {  
 public static void main(String[] args) {  
  List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);  
  // 求和方式1  
  Optional<Integer> sum = list.stream().reduce((x, y) -> x + y);  
  // 求和方式2  
  Optional<Integer> sum2 = list.stream().reduce(Integer::sum);  
  // 求和方式3  
  Integer sum3 = list.stream().reduce(0, Integer::sum);  
    
  // 求乘积  
  Optional<Integer> product = list.stream().reduce((x, y) -> x * y);  
  
  // 求最大值方式1  
  Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);  
  // 求最大值写法2  
  Integer max2 = list.stream().reduce(1, Integer::max);  
  
  System.out.println("list求和:" + sum.get() + "," + sum2.get() + "," + sum3);  
  System.out.println("list求积:" + product.get());  
  System.out.println("list求和:" + max.get() + "," + max2);  
 }  
}  

image

案例二:求所有员工的工资之和和最高工资。

点击查看代码
public class StreamTest {  
 public static void main(String[] args) {  
  List<Person> personList = new ArrayList<Person>();  
  personList.add(new Person("Tom", 8900, 23, "male", "New York"));  
  personList.add(new Person("Jack", 7000, 25, "male", "Washington"));  
  personList.add(new Person("Lily", 7800, 21, "female", "Washington"));  
  personList.add(new Person("Anni", 8200, 24, "female", "New York"));  
  personList.add(new Person("Owen", 9500, 25, "male", "New York"));  
  personList.add(new Person("Alisa", 7900, 26, "female", "New York"));  
  
  // 求工资之和方式1:  
  Optional<Integer> sumSalary = personList.stream().map(Person::getSalary).reduce(Integer::sum);  
  // 求工资之和方式2:  
  Integer sumSalary2 = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(),  
    (sum1, sum2) -> sum1 + sum2);  
  // 求工资之和方式3:  
  Integer sumSalary3 = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(), Integer::sum);  
  
  // 求最高工资方式1:  
  Integer maxSalary = personList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(),  
    Integer::max);  
  // 求最高工资方式2:  
  Integer maxSalary2 = personList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(),  
    (max1, max2) -> max1 > max2 ? max1 : max2);  
  
  System.out.println("工资之和:" + sumSalary.get() + "," + sumSalary2 + "," + sumSalary3);  
  System.out.println("最高工资:" + maxSalary + "," + maxSalary2);  
 }  
}  

image

3.6 收集(collect)

collect,收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。

3.6.1 归集(toList/toSet/toMap)
因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂一些的用法。

下面用一个案例演示toList、toSet和toMap:

image

image

3.6.2 统计(count/averaging)
Collectors提供了一系列用于数据统计的静态方法:

计数:count

平均值:averagingInt、averagingLong、averagingDouble

最值:maxBy、minBy

求和:summingInt、summingLong、summingDouble

统计以上所有:summarizingInt、summarizingLong、summarizingDouble

image

image

3.6.3 分组(partitioningBy/groupingBy)
分区:将stream按条件分为两个Map,比如员工按薪资是否高于8000分为两部分。

分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。
image

案例:将员工按薪资是否高于8000分为两部分;将员工按性别和地区分组

点击查看代码
public class StreamTest {  
 public static void main(String[] args) {  
  List<Person> personList = new ArrayList<Person>();  
  personList.add(new Person("Tom", 8900, "male", "New York"));  
  personList.add(new Person("Jack", 7000, "male", "Washington"));  
  personList.add(new Person("Lily", 7800, "female", "Washington"));  
  personList.add(new Person("Anni", 8200, "female", "New York"));  
  personList.add(new Person("Owen", 9500, "male", "New York"));  
  personList.add(new Person("Alisa", 7900, "female", "New York"));  
  
  // 将员工按薪资是否高于8000分组  
        Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));  
        // 将员工按性别分组  
        Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));  
        // 将员工先按性别分组,再按地区分组  
        Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));  
        System.out.println("员工按薪资是否大于8000分组情况:" + part);  
        System.out.println("员工按性别分组情况:" + group);  
        System.out.println("员工按性别、地区:" + group2);  
 }  
}  

输出结果:

点击查看代码
员工按薪资是否大于8000分组情况:{false=[mutest.Person@2d98a335, mutest.Person@16b98e56, mutest.Person@7ef20235], true=[mutest.Person@27d6c5e0, mutest.Person@4f3f5b24, mutest.Person@15aeb7ab]}  
员工按性别分组情况:{female=[mutest.Person@16b98e56, mutest.Person@4f3f5b24, mutest.Person@7ef20235], male=[mutest.Person@27d6c5e0, mutest.Person@2d98a335, mutest.Person@15aeb7ab]}  
员工按性别、地区:{female={New York=[mutest.Person@4f3f5b24, mutest.Person@7ef20235], Washington=[mutest.Person@16b98e56]}, male={New York=[mutest.Person@27d6c5e0, mutest.Person@15aeb7ab], Washington=[mutest.Person@2d98a335]}}  

3.6.4 接合(joining)
joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。
image

3.6.5 归约(reducing)
Collectors类提供的reducing方法,相比于stream本身的reduce方法,增加了对自定义归约的支持。

点击查看代码
 public class StreamTest {  
 public static void main(String[] args) {  
  List<Person> personList = new ArrayList<Person>();  
  personList.add(new Person("Tom", 8900, 23, "male", "New York"));  
  personList.add(new Person("Jack", 7000, 25, "male", "Washington"));  
  personList.add(new Person("Lily", 7800, 21, "female", "Washington"));  
  
  // 每个员工减去起征点后的薪资之和(这个例子并不严谨,但一时没想到好的例子)  
  Integer sum = personList.stream().collect(Collectors.reducing(0, Person::getSalary, (i, j) -> (i + j - 5000)));  
  System.out.println("员工扣税薪资总和:" + sum);  
  
  // stream的reduce  
  Optional<Integer> sum2 = personList.stream().map(Person::getSalary).reduce(Integer::sum);  
  System.out.println("员工薪资总和:" + sum2.get());  
 }  
}  

image

3.7 排序(sorted)
sorted,中间操作。有两种排序:

sorted():自然排序,流中元素需实现Comparable接口

sorted(Comparator com):Comparator排序器自定义排序

案例:将员工按工资由高到低(工资一样则按年龄由大到小)排序

点击查看代码
public class StreamTest {  
 public static void main(String[] args) {  
  List<Person> personList = new ArrayList<Person>();  
  
  personList.add(new Person("Sherry", 9000, 24, "female", "New York"));  
  personList.add(new Person("Tom", 8900, 22, "male", "Washington"));  
  personList.add(new Person("Jack", 9000, 25, "male", "Washington"));  
  personList.add(new Person("Lily", 8800, 26, "male", "New York"));  
  personList.add(new Person("Alisa", 9000, 26, "female", "New York"));  
  
  // 按工资增序排序  
  List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)  
    .collect(Collectors.toList());  
  // 按工资倒序排序  
  List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())  
    .map(Person::getName).collect(Collectors.toList());  
  // 先按工资再按年龄自然排序(从小到大)  
  List<String> newList3 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())  
    .map(Person::getName).collect(Collectors.toList());  
  // 先按工资再按年龄自定义排序(从大到小)  
  List<String> newList4 = personList.stream().sorted((p1, p2) -> {  
   if (p1.getSalary() == p2.getSalary()) {  
    return p2.getAge() - p1.getAge();  
   } else {  
    return p2.getSalary() - p1.getSalary();  
   }  
  }).map(Person::getName).collect(Collectors.toList());  
  
  System.out.println("按工资自然排序:" + newList);  
  System.out.println("按工资降序排序:" + newList2);  
  System.out.println("先按工资再按年龄自然排序:" + newList3);  
  System.out.println("先按工资再按年龄自定义降序排序:" + newList4);  
 }  
}  

image

3.8 提取/组合
流也可以进行合并、去重、限制、跳过等操作。

image

image

image

点击查看代码
public class StreamTest {  
 public static void main(String[] args) {  
  String[] arr1 = { "a", "b", "c", "d" };  
  String[] arr2 = { "d", "e", "f", "g" };  
  
  Stream<String> stream1 = Stream.of(arr1);  
  Stream<String> stream2 = Stream.of(arr2);  
  // concat:合并两个流 distinct:去重  
  List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());  
  // limit:限制从流中获得前n个数据  
  List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());  
  // skip:跳过前n个数据  
  List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());  
  
  System.out.println("流合并:" + newList);  
  System.out.println("limit:" + collect);  
  System.out.println("skip:" + collect2);  
 }  
}  

image

三、遇到的报错

四、参考博客

https://mp.weixin.qq.com/s/Y6bsuy_wFQYyVSL4CGNIaw

本文作者:独而不孤

本文链接:https://www.cnblogs.com/lcaiqin/p/17757044.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   林财钦  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.

作曲 : Reol

作词 : Reol

fade away...do over again...

fade away...do over again...

歌い始めの一文字目 いつも迷ってる

歌い始めの一文字目 いつも迷ってる

どうせとりとめのないことだけど

伝わらなきゃもっと意味がない

どうしたってこんなに複雑なのに

どうしたってこんなに複雑なのに

噛み砕いてやらなきゃ伝わらない

ほら結局歌詞なんかどうだっていい

僕の音楽なんかこの世になくたっていいんだよ

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.

目の前 広がる現実世界がまた歪んだ

目の前 広がる現実世界がまた歪んだ

何度リセットしても

僕は僕以外の誰かには生まれ変われない

「そんなの知ってるよ」

気になるあの子の噂話も

シニカル標的は次の速報

麻痺しちゃってるこっからエスケープ

麻痺しちゃってるこっからエスケープ

遠く遠くまで行けるよ

安定なんてない 不安定な世界

安定なんてない 不安定な世界

安定なんてない きっと明日には忘れるよ

fade away...do over again...

fade away...do over again...

そうだ世界はどこかがいつも嘘くさい

そうだ世界はどこかがいつも嘘くさい

綺麗事だけじゃ大事な人たちすら守れない

くだらない 僕らみんなどこか狂ってるみたい

本当のことなんか全部神様も知らない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.