Java 8 Stream讲解

Java 8 新特性 Stream流操作

我的理解

  1. 在Java8中API新增了一个新的抽象称为流Stream,可以让我们通过声明的方式处理流Stream。
  2. 我个人的理解是Stream流类似于SQL语句一样从数据库通过查询数据这种方式,将Java集合和表达进行抽象,以一种直观的方式展示出来。
  3. 这个API通过干净、简洁以及高效率的代码提高Java程序员对数据的处理效率。

什么是Stream

通过这个单词的字面意思,可以知道它是流的意思,它是一个来自数据源的元素队列,且它支持类似SQL语句的聚合操作

  • 元素 是某种类型的对象,形成一个队列,比如String类型的队列List<String>,此时的元素就是String类型的元素,Java中的Stream不会对元素进行修改和存储,而是根据你的需求进行计算,如过滤,映射,去除,查找,匹配,排序。
  • 数据源 它可以使集合、数组等,它是流的来源。
  • 聚合操作 如上述所说的过滤,映射,去除,查找,匹配,排序等操作,类似SQL语句。
  • 流水线(Pipelining) 所有中间操作都会回到流本身,打个比方,流水线中一批产品需要通过不同的检查筛选,第一道操作之后剩下的产品进入第二道操作,之后最后的操作执行后剩下的产品就是想要的优质品。将多个操作串联成一个管道,类似fluent style。这样的话好处是可以对操作进行优化。
  • 内部迭代 没有Stream流之前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 而Stream提供了内部迭代的方式, 通过访问者模式实现。

如何生成流

在Java8中,有两个方法对集合接口进行生成流:

  1. Stream() 创建串行流
  2. parallelStream() 创建并行流

filter

filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤空字符串:

List<String> str = Arrays.asList("S","t","","r","e","a","m");
System.out.println("未通过Stream流操作的str:" + str);
List<String> filter = str.stream().filter(s->!s.isEmpty()).collect(Collectors.toList());
System.out.println("通过Stream流操作的str:" + str);
System.out.println("通过Stream流操作返回的filter:" + filter);

该操作将str 中的空字符去除掉后将剩余的元素返回给filter中,并不会对原本的str进行操作。
输出结果

未通过Stream流操作的str:[S, t, , r, e, a, m]
通过Stream流操作的str:[S, t, , r, e, a, m]
通过Stream流操作返回的filter:[S, t, r, e, a, m]

进程已结束,退出代码为 0

forEach

在Stream中提供了forEach来迭代每个数据,以下代码使用forEach输出了从0到9中的10个随机数

Random random = new Random();
random.ints(0,10).limit(10).forEach(System.out::println);

定义一个Random对象,调用ints().limit(10)随机获取10个整数后进行输出。
输出结果

9
0
6
0
8
3
7
9
6
0

进程已结束,退出代码为 0


map

map 方法用于映射每个元素到对应的结果,以下代码使用map输出元素对应的平方数:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数并将重复的数据去除
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
System.out.println(squaresList);

通过map(i -> i*i )得到元素对应的平方数,并通过distinct()将重复的数据去除,最后通过collect()将数据返回。

输出结果:

[9, 4, 49, 25]

进程已结束,退出代码为 0

limit

limit 方法用于获取指定数量的流。 引用上面forEach代码片段使用 limit 方法打印出 10 条数据:

Random random = new Random();
random.ints(0,10).limit(10).forEach(System.out::println);

定义一个Random对象,调用ints().limit(10)随机获取10个整数后进行输出。
输出结果

9
0
6
0
8
3
7
9
6
0

进程已结束,退出代码为 0


sorted

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的数字进行排序:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().sorted().forEach(System.out::println);

通过调用stream().sorted()将numbers中的数据进行排序
输出结果

2
2
3
3
3
5
7

进程已结束,退出代码为 0

并行(parallel)程序

parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出去除空字符串后的结果:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
System.out.println("未通过Stream流操作的str:" + strings);
// 获取空字符串的数量
List<String> filter = strings.parallelStream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("通过Stream流操作的str:" + strings);
System.out.println("通过Stream流操作返回的filter:" + filter);

输出结果:

未通过Stream流操作的strings:[abc, , bc, efg, abcd, , jkl]
通过Stream流操作的strings:[abc, , bc, efg, abcd, , jkl]
通过Stream流操作返回的filter:[abc, bc, efg, abcd, jkl]

进程已结束,退出代码为 0

Collectors

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

List<String>strings = Arrays.asList("S", "", "t", "r", "e","a", "m","");
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);

先通过filter 将空字符串去除,然后使用Collectors中的joining()将其合并成一个字符串。

筛选列表: [S, t, r, e, a, m]
合并字符串: Stream

进程已结束,退出代码为 0

统计

用于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());

输出结果:

列表中最大的数 : 7
列表中最小的数 : 2
所有数之和 : 25
平均数 : 3.5714285714285716

进程已结束,退出代码为 0

以上例子参考菜鸟教程Java 8 Stream | 菜鸟教程加以修改

实际例子

统计学生的成绩,筛选出成绩大于60的学生,输出其名字和成绩(这里只是做例子所以名字直接使用数字代替,成绩使用random生成)

Random random = new Random();
List<Student> StuList = new ArrayList<Student>();
for(int i=0;i<20;i++) {
   Student s = new Student(String.valueOf(i),random.nextDouble()*100);
   StuList.add(s);
}
System.out.println("所有成绩:" + StuList.toString());
List<Student> collect = StuList.stream().filter(s -> s.grade > 60).collect(Collectors.toList());
System.out.println("筛选后的成绩:" + collect.toString());

先定义一个Random对象,用于生成成绩,通过循环创建20个Student类型的对象,名字使用循环的变量i进行代替,成绩通过random.nextDouble()进行生成,通过add()方法将对象添加进列表中,然后使用stream().filter()进行筛选出成绩大于60的学生并输出

所有成绩:[0 61.0, 1 59.4, 2 19.1, 3 2.2, 4 78.8, 5 69.7, 6 98.8, 7 3.1, 8 77.7, 9 35.9, 10 60.8, 11 95.4, 12 66.4, 13 76.9, 14 51.8, 15 87.0, 16 39.0, 17 80.7, 18 79.4, 19 81.0]
筛选后的成绩:[0 61.0, 4 78.8, 5 69.7, 6 98.8, 8 77.7, 10 60.8, 11 95.4, 12 66.4, 13 76.9, 15 87.0, 17 80.7, 18 79.4, 19 81.0]

进程已结束,退出代码为 0

总结

关于Stream流的内容就讲到这里了,通过Stream流我们可以写出更简洁高效的代码对这些数据进行处理,如过滤,映射,去除,查找,匹配,排序,不只是单一的操作,而是可以多个操作进行,得到我们所需要的数据,且不会对原数据进行操作,所以Stream流还是需要好好掌握的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值