您的位置:首页 > 编程语言 > Java开发

高效率!让java8的Stream对集合操作飞起来

2019-10-16 08:45 1896 查看

作者:坚持就是胜利

https://juejin.im/post/5d5e2616f265da03b638b28a


简介

java8 也出来好久了,接口默认方法,lambda 表达式,函数式接口,Date API 等特性还是有必要去了解一下。比如在项目中经常用到集合,遍历集合可以试下 lambda 表达式,经常还要对集合进行过滤和排序,Stream 就派上用场了。用习惯了,不得不说真的很好用。

Stream 作为 java8 的新特性,基于 lambda 表达式,是对集合对象功能的增强,它专注于对集合对象进行各种高效、便利的聚合操作或者大批量的数据操作,提高了编程效率和代码可读性。

Stream 的原理:将要处理的元素看做一种流,流在管道中传输,并且可以在管道的节点上处理,包括过滤筛选、去重、排序、聚合等。元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。
集合有两种方式生成流:

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

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

上图中是 Stream 类的类结构图,里面包含了大部分的中间和终止操作。

  • 中间操作主要有以下方法(此类型方法返回的都是 Stream):map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

  • 终止操作主要有以下方法:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

举例说明

首先为了说明 Stream 对对象集合的操作,新建一个 Student 类(学生类), 覆写了 equals() 和 hashCode() 方法

  1. public class Student {


  2. private Long id;


  3. private String name;


  4. private int age;


  5. private String address;


  6. public Student() {}


  7. public Student(Long id, String name, int age, String address) {

  8. this.id = id;

  9. this.name = name;

  10. this.age = age;

  11. this.address = address;

  12. }


  13. @Override

  14. public String toString() {

  15. return "Student{" +

  16. "id=" + id +

  17. ", + name + '\'' +

  18. ", age=" + age +

  19. ", address='" + address + '\'' +

  20. '}';

  21. }


  22. @Override

  23. public boolean equals(Object o) {

  24. if (this == o) return true;

  25. if (o == null || getClass() != o.getClass()) return false;

  26. Student student = (Student) o;

  27. return age == student.age &&

  28. Objects.equals(id, student.id) &&

  29. Objects.equals(name, student.name) &&

  30. Objects.equals(address, student.address);

  31. }


  32. @Override

  33. public int hashCode() {

  34. return Objects.hash(id, name, age, address);

  35. }


  36. public Long getId() {

  37. return id;

  38. }


  39. public void setId(Long id) {

  40. this.id = id;

  41. }


  42. public String getName() {

  43. return name;

  44. }


  45. public void setName(String name) {

  46. this.name = name;

  47. }


  48. public int getAge() {

  49. return age;

  50. }


  51. public void setAge(int age) {

  52. this.age = age;

  53. }


  54. public String getAddress() {

  55. return address;

  56. }


  57. public void setAddress(String address) {

  58. this.address = address;

  59. }


  60. }

  61. 复制代码

filter(筛选)

  1. public static void main(String [] args) {


  2. Student s1 = new Student(1L, "肖战", 15, "浙江");

  3. Student s2 = new Student(2L, "王一博", 15, "湖北");

  4. Student s3 = new Student(3L, "杨紫", 17, "北京");

  5. Student s4 = new Student(4L, "李现", 17, "浙江");

  6. List<Student> students = new ArrayList<>();

  7. students.add(s1);

  8. students.add(s2);

  9. students.add(s3);

  10. students.add(s4);


  11. List<Student> streamStudents = testFilter(students);

  12. streamStudents.forEach(System.out::println);

  13. }

  14. /**

  15. * 集合的筛选

  16. * @param students

  17. * @return

  18. */

  19. private static List<Student> testFilter(List<Student> students) {

  20. //筛选年龄大于15岁的学生

  21. // return students.stream().filter(s -> s.getAge()>15).collect(Collectors.toList());

  22. //筛选住在浙江省的学生

  23. return students.stream().filter(s ->"浙江".equals(s.getAddress())).collect(Collectors.toList());

  24. }

  25. 复制代码

运行结果:

这里我们创建了四个学生,经过 filter 的筛选,筛选出地址是浙江的学生集合。

map(转换)

  1. public static void main(String [] args) {


  2. Student s1 = new Student(1L, "肖战", 15, "浙江");

  3. Student s2 = new Student(2L, "王一博", 15, "湖北");

  4. Student s3 = new Student(3L, "杨紫", 17, "北京");

  5. Student s4 = new Student(4L, "李现", 17, "浙江");

  6. List<Student> students = new ArrayList<>();

  7. students.add(s1);

  8. students.add(s2);

  9. students.add(s3);

  10. students.add(s4);


  11. testMap(students);

  12. }


  13. /**

  14. * 集合转换

  15. * @param students

  16. * @return

  17. */

  18. private static void testMap(List<Student> students) {

  19. //在地址前面加上部分信息,只获取地址输出

  20. List<String> addresses = students.stream().map(s ->"住址:"+s.getAddress()).collect(Collectors.toList());

  21. addresses.forEach(a ->System.out.println(a));

  22. }

  23. 复制代码

运行结果

map 就是将对应的元素按照给定的方法进行转换。

distinct(去重)

  1. public static void main(String [] args) {


  2. testDistinct1();

  3. }


  4. /**

  5. * 集合去重(基本类型)

  6. */

  7. private static void testDistinct1() {

  8. //简单字符串的去重

  9. List<String> list = Arrays.asList("111","222","333","111","222");

  10. list.stream().distinct().forEach(System.out::println);

  11. }

  12. 复制代码

运行结果:

  1. public static void main(String [] args) {


  2. testDistinct2();

  3. }


  4. /**

  5. * 集合去重(引用对象)

  6. */

  7. private static void testDistinct2() {

  8. //引用对象的去重,引用对象要实现hashCode和equal方法,否则去重无效

  9. Student s1 = new Student(1L, "肖战", 15, "浙江");

  10. Student s2 = new Student(2L, "王一博", 15, "湖北");

  11. Student s3 = new Student(3L, "杨紫", 17, "北京");

  12. Student s4 = new Student(4L, "李现", 17, "浙江");

  13. Student s5 = new Student(1L, "肖战", 15, "浙江");

  14. List<Student> students = new ArrayList<>();

  15. students.add(s1);

  16. students.add(s2);

  17. students.add(s3);

  18. students.add(s4);

  19. students.add(s5);

  20. students.stream().distinct().forEach(System.out::println);

  21. }

  22. 复制代码

运行结果:

可以看出,两个重复的 “肖战” 同学进行了去重,这不仅因为使用了 distinct()方法,而且因为 Student 对象重写了 equals 和 hashCode()方法,否则去重是无效的。

sorted(排序)

  1. public static void main(String [] args) {


  2. testSort1();

  3. }


  4. /**

  5. * 集合排序(默认排序)

  6. */

  7. private static void testSort1() {

  8. List<String> list = Arrays.asList("333","222","111");

  9. list.stream().sorted().forEach(System.out::println);

  10. }

  11. 复制代码

运行结果:

  1. public static void main(String [] args) {


  2. testSort2();

  3. }


  4. /**

  5. * 集合排序(指定排序规则)

  6. */

  7. private static void testSort2() {

  8. Student s1 = new Student(1L, "肖战", 15, "浙江");

  9. Student s2 = new Student(2L, "王一博", 15, "湖北");

  10. Student s3 = new Student(3L, "杨紫", 17, "北京");

  11. Student s4 = new Student(4L, "李现", 17, "浙江");

  12. List<Student> students = new ArrayList<>();

  13. students.add(s1);

  14. students.add(s2);

  15. students.add(s3);

  16. students.add(s4);

  17. students.stream()

  18. .sorted((stu1,stu2) ->Long.compare(stu2.getId(), stu1.getId()))

  19. .sorted((stu1,stu2) -> Integer.compare(stu2.getAge(),stu1.getAge()))

  20. .forEach(System.out::println);

  21. }

  22. 复制代码

运行结果:

上面指定排序规则,先按照学生的 id 进行降序排序,再按照年龄进行降序排序

limit(限制返回个数)

  1. public static void main(String [] args) {


  2. testLimit();

  3. }


  4. /**

  5. * 集合limit,返回前几个元素

  6. */

  7. private static void testLimit() {

  8. List<String> list = Arrays.asList("333","222","111");

  9. list.stream().limit(2).forEach(System.out::println);

  10. }

  11. 复制代码

运行结果:

skip(删除元素)

  1. public static void main(String [] args) {


  2. testSkip();

  3. }


  4. /**

  5. * 集合skip,删除前n个元素

  6. */

  7. private static void testSkip() {

  8. List<String> list = Arrays.asList("333","222","111");

  9. list.stream().skip(2).forEach(System.out::println);

  10. }

  11. 复制代码

运行结果:

reduce(聚合)

  1. public static void main(String [] args) {

  2. testReduce();

  3. }

  4. /**

  5. * 集合reduce,将集合中每个元素聚合成一条数据

  6. */

  7. private static void testReduce() {

  8. List<String> list = Arrays.asList("欢","迎","你");

  9. String appendStr = list.stream().reduce("北京",(a,b) -> a+b);

  10. System.out.println(appendStr);

  11. }

  12. 复制代码

运行结果:

min(求最小值)

  1. public static void main(String [] args) {

  2. testMin();

  3. }


  4. /**

  5. * 求集合中元素的最小值

  6. */

  7. private static void testMin() {

  8. Student s1 = new Student(1L, "肖战", 14, "浙江");

  9. Student s2 = new Student(2L, "王一博", 15, "湖北");

  10. Student s3 = new Student(3L, "杨紫", 17, "北京");

  11. Student s4 = new Student(4L, "李现", 17, "浙江");

  12. List<Student> students = new ArrayList<>();

  13. students.add(s1);

  14. students.add(s2);

  15. students.add(s3);

  16. students.add(s4);

  17. Student minS = students.stream().min((stu1,stu2) ->Integer.compare(stu1.getAge(),stu2.getAge())).get();

  18. System.out.println(minS.toString());

  19. }

  20. 复制代码

运行结果:

上面是求所有学生中年龄最小的一个,max 同理,求最大值。

anyMatch/allMatch/noneMatch(匹配)

  1. public static void main(String [] args) {

  2. testMatch();

  3. }


  4. private static void testMatch() {

  5. Student s1 = new Student(1L, "肖战", 15, "浙江");

  6. Student s2 = new Student(2L, "王一博", 15, "湖北");

  7. Student s3 = new Student(3L, "杨紫", 17, "北京");

  8. Student s4 = new Student(4L, "李现", 17, "浙江");

  9. List<Student> students = new ArrayList<>();

  10. students.add(s1);

  11. students.add(s2);

  12. students.add(s3);

  13. students.add(s4);

  14. Boolean anyMatch = students.stream().anyMatch(s ->"湖北".equals(s.getAddress()));

  15. if (anyMatch) {

  16. System.out.println("有湖北人");

  17. }

  18. Boolean allMatch = students.stream().allMatch(s -> s.getAge()>=15);

  19. if (allMatch) {

  20. System.out.println("所有学生都满15周岁");

  21. }

  22. Boolean noneMatch = students.stream().noneMatch(s -> "杨洋".equals(s.getName()));

  23. if (noneMatch) {

  24. System.out.println("没有叫杨洋的同学");

  25. }

  26. }

  27. 复制代码

运行结果

  • anyMatch:Stream 中任意一个元素符合传入的 predicate,返回 true

  • allMatch:Stream 中全部元素符合传入的 predicate,返回 true

  • noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true

总结

上面介绍了 Stream 常用的一些方法,虽然对集合的遍历和操作可以用以前常规的方式,但是当业务逻辑复杂的时候,你会发现代码量很多,可读性很差,明明一行代码解决的事情,你却写了好几行。试试 lambda 表达式,试试 Stream,你会有不一样的体验。



有热门推荐👇


1.接私活必备的 10 个开源项目!

2.GitHub 上一个丧心病狂的开源项目!

3.程序员除了会CRUD之外,还要知道CQRS!

4.在浏览器输入 URL 回车之后发生了什么

5.2018年所有精华文章汇总,错过了血亏!



关注程序员私房菜

每天进步一点点



点赞是最大的支持 


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: