【Lambda】java之lambda表达式&stream流式编程操作集合

打印 上一主题 下一主题

主题 548|帖子 548|积分 1644

1 stream流概念

简朴来讲,Stream流是一种用于处理数据集合的高级迭代器,它可以对集合中的元素进行各种操作,如过滤、映射、排序等。通过使用Stream API,我们可以以声明式的方式处理数据,而无需显式地编写循环和条件语句。
Stream流的操作分为两种,中心操作终端操作
1.1 中心操作

是指对每个元素独立进行操作,不依赖于其他元素的状态。它们不会改变流中的元素本身,而是创建一个新的Stream对象来表示转换后的效果。常见的无状态中心操作有map、filter、flatMap等。
1.1.1 无状态操作

无状态操作不会改变流中的元素,也不会改变流的状态;这些操作可以并行执行,因为它们不依赖于流中的其他元素。比方:


  • distinct:返回去重的Stream。
  • limit:限制从流中得到前n个数据,返回前n个元素数据构成的Stream流。
  • skip:跳过前n个数据,返回第n个元素背面数据构成的Stream。sorted:返回一个排序的Stream。
1.1.2 有状态操作

有状态操作会改变流的状态,或者依赖于流中的其他元素。这些操作不能并行执行,因为它们需要访问或修改流的状态。
比方:


  • filter:过滤流,过滤流中的元素,返回一个符合条件的Stream
  • map:转换流,将一种类型的流转换为别的一种流。(mapToInt、mapToLong、mapToDouble 返回int、long、double根本类型对应的Stream)
  • peek:主要用来检察流中元素的数据状态,该方法主要用于调试,方便debug检察Stream内进行处理的每个元素。仅在对流内元素进行操作时,peek才会被调用,当不对元素做任何操作时,peek自然也不会被调用了
  • flatMap:简朴的说,就是一个或多个流归并成一个新流。
1.2 终端操作

是对数据进行终极处理的操作,它们会消耗掉Stream并产生一个效果或者副作用(如输出到控制台)。一旦执行了终端操作,Stream就不能再被使用。常见的终端操作有collect、forEach、reduce等。
1.2.1 非短路操作

非短路操作会处理流中的全部元素,并返回一个效果。
如:


  • forEach:循环操作Stream中数据。
  • toArray:返回流中元素对应的数组对象。
  • reduce:聚合操作,用来做统计,将流中元素反复结合起来统计计算,得到一个值.。
  • collect:聚合操作,封装目标数据,将流转换为其他形式吸收,如:List、Set、Map、Array。
  • min、max、count:聚合操作,最小值,最大值,总数量。
1.2.2 短路操作

短路操作会在满意某个条件时提前竣事处理,并返回一个效果。比方:


  • anyMatch:短路操作,有一个符合条件返回true。
  • allMatch:全部数据都符合条件返回true。
  • noneMatch:全部数据都不符合条件返回true。
  • findFirst:短路操作,获取第一个元素。
  • findAny:短路操作,获取任一元素。
2 steam流的天生

2.1 方式一:数组转为stream流

  1. int [] arr = {1,2,3,4,5,6,7,8,9,10};      
  2. Arrays.stream(arr).forEach(System.out::println);
复制代码
2.2 方式二:集合转为steam流

  1. List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
  2. list.stream().forEach(System.out::println);
复制代码
2.3 方式三:Stream.builder创建stream流

Stream.builder创建stream流,允许你渐渐构建一个流
  1. Stream.Builder<Integer> builder = Stream.builder();
  2. // 添加元素到流中
  3. builder.add(1);
  4. builder.add(2);
  5. builder.add(3);
  6. // 构建流
  7. Stream<Integer> stream = builder.build();
  8. // 使用流
  9. stream.forEach(System.out::println);
复制代码
2.4 方式四:使用 Stream.of 方法

Stream.of 方法可以继承一系列元素并返回一个包含这些元素的流。
  1. Stream<String> words = Stream.of("apple", "banana", "orange");
  2. words.forEach(System.out::println);
复制代码
2.5 方式五:从文件创建流

可以使用 Files.lines 方法从文件中创建流。
  1. try (Stream<String> stream = Files.lines(Paths.get("file.txt"))) {
  2.     stream.forEach(System.out::println);
  3. } catch (IOException e) {
  4.     e.printStackTrace();
  5. }
复制代码
2.6 方式六:天生无穷流

可以使用 Stream.generate 或 Stream.iterate 方法来天生无穷流。
  1. Stream<Double> randomNumbers = Stream.generate(Math::random);
  2. randomNumbers.forEach(System.out::println);
  3. Stream<Integer> oddNumbers = Stream.iterate(1, n -> n + 2);
  4. oddNumbers.forEach(System.out::println);
复制代码
3 无状态的中心操作

3.1 distinct

返回一个去重的流,即去除重复的元素
  1. Stream<Integer> distinctStream = Stream.of(1, 2, 2, 3, 4, 4, 5).distinct();
  2. distinctStream.forEach(System.out::println);
  3. //输出结果:12345
复制代码
3.2 limit

限制从流中得到前n个数据,返回前n个元素数据构成的流
  1. Stream<Integer> limitedStream = Stream.of(1, 2, 3, 4, 5).limit(3);
  2. limitedStream.forEach(System.out::println);
  3. //输出结果:123
复制代码
3.3 skip

  1. Stream<Integer> skippedStream = Stream.of(1, 2, 3, 4, 5).skip(2);
  2. skippedStream.forEach(System.out::println);
  3. //输出结果:345
复制代码
3.4 sorted

  1. //正序排序从小到大
  2. Stream<Integer> sortedStream = Stream.of(5, 3, 1, 4, 2).sorted();
  3. sortedStream.forEach(System.out::println);
  4. //输出结果:12345
  5. //逆序排序从大到小,Comparator.reverseOrder() 创建了一个逆序比较器,然后传递给 sorted 方法,从而实现了逆序排序
  6. Stream<Integer> sortedStream = Stream.of(5, 3, 1, 4, 2).sorted(Comparator.reverseOrder());
  7. sortedStream.forEach(System.out::println);
  8. //输出结果:54321
复制代码
3.5 组合使用

这段代码首先去重,然后排序,跳过第一个元素,末了限制效果流只包含前三个元素
  1. Stream<Integer> stream = Stream.of(1, 2, 2, 3, 4, 4, 5)
  2.                 .distinct()
  3.                 .sorted()
  4.                 .skip(1)
  5.                 .limit(3);
  6. stream.forEach(System.out::println);
  7. //输出结果:234
复制代码
测试实体类:
  1. @Data
  2. public class Person {
  3.     private int id;
  4.     private String name; // 姓名
  5.     private int salary; // 薪资
  6.     private int age; // 年龄
  7.     private String sex; //性别
  8.     private String area; // 地区
  9.     private List<Person> employeeList; //下属
  10.     public Person() {
  11.     }
  12.     // 构造方法
  13.     public Person(String name, int salary, int age,String sex,String area) {
  14.         this.name = name;
  15.         this.salary = salary;
  16.         this.age = age;
  17.         this.sex = sex;
  18.         this.area = area;
  19.     }
  20.     // 构造方法
  21.     public Person(int id, String name, int salary, int age, String sex, String area) {
  22.         this.id = id;
  23.         this.name = name;
  24.         this.salary = salary;
  25.         this.age = age;
  26.         this.sex = sex;
  27.         this.area = area;
  28.     }
  29.     @Override
  30.     public String toString() {
  31.         return "Person{" +
  32.                 "name='" + name + '\'' +
  33.                 ", salary=" + salary +
  34.                 ", age=" + age +
  35.                 ", sex='" + sex + '\'' +
  36.                 ", area='" + area + '\'' +
  37.                 '}';
  38.     }
  39. }
复制代码
  1. // 创建一个List来存储Person对象
  2. List<Person> personList = new ArrayList<>();
  3. // 创建8个Person对象并添加到列表中
  4. personList.add(new Person(1, "Alice", 5000, 30, "Female", "New York"));
  5. personList.add(new Person(2, "Bob", 6000, 35, "Male", "Los Angeles"));
  6. personList.add(new Person(3, "Charlie", 5500, 28, "Male", "Chicago"));
  7. personList.add(new Person(4, "Diana", 7000, 40, "Female", "Miami"));
  8. personList.add(new Person(5, "Ethan", 4800, 25, "Male", "Houston"));
  9. personList.add(new Person(6, "Fiona", 5300, 32, "Female", "Seattle"));
  10. personList.add(new Person(7, "George", 6200, 38, "Male", "Boston"));
  11. personList.add(new Person(8, "Hannah", 5900, 29, "Female", "San Francisco"));
复制代码
4 有状态的中心操作

4.1 filter(重要)

  1. // 1. 筛选出所有女性
  2. List<Person> females = personList.stream()
  3.         .filter(person -> person.getSex().equalsIgnoreCase("female"))
  4.         .collect(Collectors.toList());
  5. System.out.println("女性列表: " + females);
  6. // 2. 筛选出薪资高于5000的人员
  7. List<Person> highSalary = personList.stream()
  8.         .filter(person -> person.getSalary() > 5000)
  9.         .collect(Collectors.toList());
  10. System.out.println("薪资高于5000的人员: " + highSalary);
  11. // 3. 筛选出年龄在30岁及以上的人员
  12. List<Person> ageAbove30 = personList.stream()
  13.         .filter(person -> person.getAge() >= 30)
  14.         .collect(Collectors.toList());
  15. System.out.println("年龄在30岁及以上的人员: " + ageAbove30);
  16. // 4. 筛选出居住在特定城市(例如"New York")的人员
  17. List<Person> livingInNewYork = personList.stream()
  18.         .filter(person -> person.getArea().equalsIgnoreCase("New York"))
  19.         .collect(Collectors.toList());
  20. System.out.println("居住在纽约的人员: " + livingInNewYork);
  21. // 5. 筛选出名字以"A"开头的人员
  22. List<Person> namesStartingWithA = personList.stream()
  23.         .filter(person -> person.getName().startsWith("A"))
  24.         .collect(Collectors.toList());
  25. System.out.println("名字以A开头的人员: " + namesStartingWithA);
复制代码
4.2 map(重要)

  1. // 1. 提取所有人的名字
  2. List<String> names = personList.stream()
  3.         .map(Person::getName)
  4.         .collect(Collectors.toList());
  5. System.out.println("所有人的名字: " + names);
  6. // 2. 提取所有人的薪资
  7. List<Integer> salaries = personList.stream()
  8.         .map(Person::getSalary)
  9.         .collect(Collectors.toList());
  10. System.out.println("所有人的薪资: " + salaries);
  11. // 3. 提取所有人的地区
  12. List<String> cities = personList.stream()
  13.         .map(Person::getArea)
  14.         .collect(Collectors.toList());
  15. System.out.println("所有人的城市: " + cities);
  16. // 4. 提取所有人的年龄,并加上10
  17. List<Integer> agesPlus10 = personList.stream()
  18.         .map(person -> person.getAge() + 10)
  19.         .collect(Collectors.toList());
  20. System.out.println("所有人的年龄加十: " + agesPlus10);
  21. // 5. 提取薪资信息并格式化为字符串
  22. List<String> salaryInfo = personList.stream()
  23.         .map(person -> person.getName() + "的薪资为: " + person.getSalary())
  24.         .collect(Collectors.toList());
  25. System.out.println("薪资信息: " + salaryInfo);
复制代码
4.3 flatMap

flatMap 是 Java Stream API 中的一个非常有用的方法,通常用于将多个流扁平化为一个流。在处理 Person 对象时,我们可以使用 flatMap 来进行一些复杂的数据布局操作。以下是一些示例,展示怎样在你的 personList 上使用 flatMap。
  1. List<String> flatMappedList = personList.stream()
  2.                                 .map(person -> person.getName()) // 将Person对象转换为名字
  3.                                 .flatMap(name -> Stream.of(name, name.toUpperCase())) // 将名字转换为名字和名字的大写形式
  4.                                 .collect(Collectors.toList());
复制代码
4.4 peek

  1. personList.stream()
  2.           .peek(person -> System.out.println("Before filter: " + person)) // 打印每个Person对象
  3.           .filter(person -> person.getAge() > 30) // 过滤年龄大于30的Person对象
  4.           .peek(person -> System.out.println("After filter: " + person)) // 打印过滤后的Person对象
  5.           .collect(Collectors.toList());
复制代码
4.5 组合使用

  1. // 使用Stream API处理personList
  2. List<String> combinedList = personList.stream()
  3.                                       .filter(person -> person.getAge() > 30) // 过滤年龄大于30的Person对象
  4.                                       .map(person -> person.getName()) // 将Person对象转换为名字
  5.                                       .flatMap(name -> Stream.of(name, name.toUpperCase())) // 将名字转换为名字和名字的大写形式
  6.                                       .peek(System.out::println) // 打印每个名字
  7.                                       .collect(Collectors.toList()); // 收集结果到一个List中
复制代码
5 非短路的终端操作

5.1 forEach

  1. personList.stream()
  2.           .forEach(person -> System.out.println(person.getName()));
  3. personList.stream()
  4.           .forEachOrdered(person -> System.out.println(person.getName()));
复制代码
5.2 toArray

  1. Object[] array = personList.stream().toArray();
复制代码
5.3 reduce(重要)

  1. // 1. 计算总薪资
  2. int totalSalary = personList.stream()
  3.         .map(Person::getSalary)
  4.         .reduce(0, Integer::sum);
  5. System.out.println("总薪资: " + totalSalary);
  6. // 2. 计算平均薪资
  7. Optional<Double> averageSalary = personList.stream()
  8.         .map(Person::getSalary)
  9.         .reduce((a, b) -> a + b)
  10.         .map(sum -> sum / (double) personList.size());
  11. System.out.println("平均薪资: " + averageSalary.orElse(0.0));
  12. // 3. 查找最高薪资
  13. Optional<Integer> maxSalary = personList.stream()
  14.         .map(Person::getSalary)
  15.         .reduce(Integer::max);
  16. System.out.println("最高薪资: " + maxSalary.orElse(0));
  17. // 4. 查找最低薪资
  18. Optional<Integer> minSalary = personList.stream()
  19.         .map(Person::getSalary)
  20.         .reduce(Integer::min);
  21. System.out.println("最低薪资: " + minSalary.orElse(0));
  22. // 5. 计算年龄之和
  23. int totalAge = personList.stream()
  24.         .map(Person::getAge)
  25.         .reduce(0, Integer::sum);
  26. System.out.println("总年龄: " + totalAge);
复制代码
5.4 collect(重要)

  1. //收集到 List集合
  2. List<String> names = personList.stream()
  3.         .map(Person::getName)
  4.         .collect(Collectors.toList());
  5. //收集到 Set集合
  6. Set<String> cities = personList.stream()
  7.         .map(Person::getArea)
  8.         .collect(Collectors.toSet());
  9. //收集到 Map集合
  10. Map<Integer, String> idToNameMap = personList.stream()
  11.         .collect(Collectors.toMap(Person::getId, Person::getName));
  12. Map<Integer, Person> idToPersonMap = personList.stream()
  13.         .collect(Collectors.toMap(Person::getId, v -> v));
  14. //收集到自定义集合
  15. List<Person> sortedList = personList.stream()
  16.         .sorted(Comparator.comparing(Person::getAge))
  17.         .collect(Collectors.toList());
  18. //使用 Collectors.joining 连接字符串
  19. String namesString = personList.stream()
  20.         .map(Person::getName)
  21.         .collect(Collectors.joining(", "));
  22. //Collectors.groupingBy
  23. Map<String, List<Person>> cityToPeopleMap = personList.stream()
  24.         .collect(Collectors.groupingBy(Person::getArea));
  25. //使用 Collectors.partitioningBy 分区
  26. Map<Boolean, List<Person>> isAdultMap = personList.stream()
  27.         .collect(Collectors.partitioningBy(person -> person.getAge() >= 18));
  28. //使用 Collectors.summarizingInt 计算统计信息
  29. IntSummaryStatistics salarySummary = personList.stream()
  30.         .collect(Collectors.summarizingInt(Person::getSalary));
  31. double average = salarySummary.getAverage();//平均值
  32. int max = salarySummary.getMax();//最大值
  33. long count = salarySummary.getCount();//计数
  34. int min = salarySummary.getMin();//最小值
  35. long sum = salarySummary.getSum();//求和
复制代码
5.5 min、max、count

  1. Optional<Person> maxSalaryPerson = personList.stream()
  2.                                              .max(Comparator.comparing(Person::getSalary));
  3. Optional<Person> minAgePerson = personList.stream()
  4.                                           .min(Comparator.comparing(Person::getAge));
  5. long count = personList.stream().count();
复制代码
5.6 组合使用

这段代码首先计算全部 Person 对象的工资总和,然后找到年龄最大的 Person 对象,末了将全部 Person 对象的名字收集到一个 List 中。
  1. int totalSalary = personList.stream()
  2.                             .mapToInt(Person::getSalary)
  3.                             .reduce(0, Integer::sum);
  4. Optional<Person> oldestPerson = personList.stream()
  5.                                          .max(Comparator.comparing(Person::getAge));
  6. List<String> names = personList.stream()
  7.                                .map(Person::getName)
  8.                                .collect(Collectors.toList());
复制代码
6 短路的终端操作

6.1 anyMatch

  1. boolean hasFemale = personList.stream()
  2.                               .anyMatch(person -> "Female".equals(person.getGender()));
复制代码
6.2 allMatch

  1. boolean allAdults = personList.stream()
  2.                               .allMatch(person -> person.getAge() >= 18);
复制代码
6.3 noneMatch

  1. boolean noRetired = personList.stream()
  2.                               .noneMatch(person -> person.getAge() >= 65);
复制代码
6.4 findFirst

  1. Optional<Person> firstPerson = personList.stream()
  2.                                          .findFirst();
复制代码
6.5 findAny

  1. Optional<Person> anyPerson = personList.stream()
  2.                                        .findAny();
复制代码
6.6 组合使用

这段代码首先检查是否存在女性,然后找到第一个成年人,末了将全部成年人的名字收集到一个 List 中。
  1. boolean hasFemale = personList.stream()
  2.                               .anyMatch(person -> "Female".equals(person.getGender()));
  3. Optional<Person> firstAdult = personList.stream()                                        .filter(person -> person.getAge() >= 18)                                        .findFirst();List<String> names = personList.stream()                               .filter(person -> person.getAge() >= 18)                               .map(Person::getName)                               .collect(Collectors.toList());
复制代码
7 并行流

并行流可以进步处理大数据集时的性能。Java Stream API 的并行处理是基于 Java 的 Fork/Join 框架实现的。Fork/Join 框架是 Java 7 引入的一种并行计算框架,它可以将一个大使命拆分成多个小使命,然后在多个处理器上并行执行这些小使命,末了将效果归并。
在 Stream API 中,并行流是通过 parallelStream() 方法创建的。当你调用 parallelStream() 方法时,Stream API 会创建一个 ForkJoinTask,并将其提交给 ForkJoinPool 执行。ForkJoinPool 是一个特别的线程池,它使用工作窃取算法来平衡使命执行,从而进步并行处理服从。
  1. String allNames = personList.parallelStream()
  2.     .map(Person::getName)
  3.     .collect(Collectors.joining(", "));
  4. System.out.println("All Names (Parallel): " + allNames);
复制代码
8 总结

Stream API 的主要特点包罗:

  • 简便性:Stream API 提供了一种简便的方式来处理集合数据,使得代码更加易读、易写。
  • 可读性:Stream API 的操作可以链式调用,使得代码更加清晰、易读。并行处理:Stream API 支持
  • 并行处理,可以充实利用多核处理器的能力。
  • 惰性求值:Stream API 的操作是惰性求值的,即只有在需要效果时才会执行操作。
  • 无状态操作:Stream API 的无状态操作不会改变流中的元素,也不会改变流的状态。
  • 有状态操作:Stream API 的有状态操作会改变流的状态,或者依赖于流中的其他元素。
  • 短路操作:Stream API 的短路操作会在满意某个条件时提前竣事处理,并返回一个效果。
  • 终端操作:Stream API 的终端操作会处理流中的全部元素,并返回一个效果。
   创作不易,不妨点赞、收藏、关注支持一下,各位的支持就是我创作的最大动力❤️
  


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

李优秀

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表