一文带你掌握java的stream流
背景
有经验的java开发者肯定对stream流不陌生,那么stream流到底是一个什么东西呢?在我看来,stream流和for循环一样都是用于处理集合数据的工具,它们的功能是完全相同的。那已经有了for循环,为啥还要弄出一个stream流呢?
主要原因还是因为相比for循环,使用stream流的开发效率高,而且代码的可读性更高。下面我们就来通过一些例子来感受下stream流的简洁和优雅。
stream流 VS for循环
skip
比如我们这里有8个学生,我们希望跳过前4个学生,我们看下使用stream流和for循环各自如何实现:
/*** skip: 跳过前n个元素*/
@Test
public void test_skip() {List<Student> students = getStudents();students.stream().skip(3).forEach(System.out::println);System.out.println("----------下面使用for循环实现同样的功能------------");for (int i = 3; i < students.size(); i++) {System.out.println(students.get(i));}
}
我们可以看到使用stream的代码明显要比for循环更简洁一些,而且代码的可读性更高。其中stream流的skip方法就是起到跳过前n个元素的作用。
limit
假设我们希望只取根据年龄大小排序后的前3个年龄最大的学生,我们看下使用stream流和for循环各自如何实现:
/*** limit: 取前n个元素*/
@Test
public void test_limit() {List<Student> students = getStudents();students.stream().sorted(Comparator.comparing(Student::getAge).reversed()).limit(3).forEach(System.out::println);System.out.println("----------下面使用for循环实现同样的功能------------");students.sort(Comparator.comparing(Student::getAge).reversed());for (int i = 0; i < 3; i++) {System.out.println(students.get(i));}
}
可以看到stream流的代码相对来说还是要更简洁一些,而且代码的可读性更高,其中stream流的limit就是取前n个元素。
map
假设我们希望将所有学生的名字放到一个list集合中,我们分别看下使用stream流和for循环如何实现:
/*** map: 类型转换*/
@Test
public void test_map() {List<Student> students = getStudents();// 将所有学生的名字收集到一个list中List<String> names = students.stream().map(Student::getName).collect(Collectors.toList());System.out.println("----------下面使用for循环实现同样的功能------------");ArrayList<String> stuNames = new ArrayList<>();for (Student student : students) {stuNames.add(student.getName());}
}
可以看到,使用stream流一行代码就搞定了,而使用for循环用了3行代码,还是stream流更加简洁,而且代码可读性更高。
其中stream流的map方法的作用就是可以拿到集合中的对象重新处理后返回一个新的对象,而collect方法则是将前面map方法处理后的新对象放到一个新的list中。
flatmap
假设我们希望将所有学生的姓名和年龄都放到一个list中,我们看下使用stream流和for循环各自如何实现:
/*** flatmap: 将多个流合并成一个流* 如果这里使用map,那么将会得到一个List(list<object>), 因为每个元素都返回的是一个list,最终就导致外面的* 那个list中的每个元素都是list*/
@Test
public void test_flat_map() {List<Student> students = getStudents();List<Object> elements = students.stream().flatMap(student -> {List<Object> list = new ArrayList<>();list.add(student.getName());list.add(student.getAge());return list.stream();}).collect(Collectors.toList());System.out.println("----------下面使用for循环实现同样的功能------------");ArrayList<Object> elements2 = new ArrayList<>();for (Student student : students) {elements2.add(student.getName());elements2.add(student.getAge());}
}
这次是for循环更加简洁,而且代码可读性更高,相比之下stream流的写法可能会让初学者感到困惑。
如何学习stream流
初次接触stream流的小伙伴可能对stream流的用法不熟悉,不知道stream流的各种方法到底有什么用。
我对此的建议是:
- 多问问AI,让它给出一些stream例子和demo,然后让它给你出题目,你尝试下使用stream流将AI出的题目给做出来。
- 像我一样使用for循环来模拟stream流中某些方法的功能,这样能让你对stream流各个方法的作用有更加深刻的认识。
其实同样的方式也适合用来学习hashMap中一些让我们感到很困惑的方法,比如我就不知道hashMap的compute方法有什么用,然后我根据百度搜索到文章讲解,写出了下面的等价处理方式:
/*** compute: 处理map在存入时遇到同名key的情况*/@Testpublic void test_use_compute() {List<Revenue> revenues = getRevenues();HashMap<Integer, Integer> revenueMap = new HashMap<>();for (Revenue revenue : revenues) {revenueMap.compute(revenue.getYear(), (k, v) -> {if (v == null) {return revenue.getRevenue();} else {return v + revenue.getRevenue();}});}System.out.println(revenueMap);System.out.println("----------下面使用其他方式实现同样的功能------------");HashMap<Integer, Integer> revenueMap2 = new HashMap<>();for (Revenue revenue : revenues) {Integer year = revenue.getYear();if (revenueMap2.containsKey(year)) {revenueMap2.put(year, revenueMap2.get(year) + revenue.getRevenue());}else {revenueMap2.put(year, revenue.getRevenue());}}System.out.println(revenueMap2);}
经过这种对比后,我们会对这些看起来很高级的方法的作用有更深刻的认识,同时我们也会发现掌握这些“高级”方法其实作用不大,因为我们有很多种替代处理方式,我们在开发中使用自己熟悉的那种处理方式就行,并不是所有的JDK方法我们都会用到,没必要在这种事情上浪费时间。
stream流和for循环如何做选择
- 如果你对stream流不熟悉,那你选择for循环就行,没必要为了为了掌握stream流而给自己增加学习成本,实际上stream流所有能做的事情使用for循环都能做,甚至stream流不能做的事情for循环也能做,所以我们掌握for循环就已经够用了。
- 我们不用stream流不代表身边的同事不会用,有时候我们需要去阅读同事的代码,在他们的代码基础上做改造,如果他们用到了stream流,那我们就不得不学了,要不然你根本就看不懂他们写的代码,所以掌握常用的stream流方法还是有必要的。
- 对于简单的功能我们可以使用stream流实现,对于复杂的功能,或者stream中一些学习难度比较高的方法,我的建议是选择for循环,怎么简单就怎么来,如果使用stream流一些不常用的方法反而会增加同事阅读代码的难度。
文章中完整示例代码的地址
文章中完整示例代码的地址
最后的总结
这篇文章中我们讲解了什么是stream流,以及stream流有什么优势。在我看来,stream流的优势是简洁,开发效率高。
然后我们还通过同时使用stream流和for循环实现同样的功能来加深我们对stream流中一些常用方法作用的理解,另外还给出了学习stream流的建议,以及在开发中我们在stream流和for循环之间如何做选择。
觉得有收获的朋友可以点个赞,您的鼓励就是我最大的动力!