Stream流基本介绍(摘抄菜鸟教程)

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

  1. +--------------------+ +------+ +------+ +---+ +-------+
  2. | stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
  3. +--------------------+ +------+ +------+ +---+ +-------+

以上的流程转换为 Java 代码为:

  1. List<Integer> transactionsIds =
  2. widgets.stream()
  3. .filter(b -> b.getColor() == RED)
  4. .sorted((x,y) -> x.getWeight() - y.getWeight())
  5. .mapToInt(Widget::getWeight)
  6. .sum();

什么是Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。

  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。

  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。

  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

JDK1.8对Stream对象的封装及方法的使用

首先下面的讲解都是基于一下Person对象

  1. //首先做一些测试数据,测试类使用Person
  2. class Person {
  3. int id;
  4. String name;
  5. String sex;
  6. @Override
  7. public String toString() {
  8. return "Person{" +
  9. "id=" + id +
  10. ", name='" + name + '\'' +
  11. ", sex='" + sex + '\'' +
  12. '}';
  13. }
  14. }

测试集合

  1. //用于测试的集合
  2. List<Person> personList = new ArrayList<>();
  3. for (int i = 0; i < 10; i++) {
  4. Person person = new Person();
  5. person.id = i;
  6. person.name = "测试数据" + i + "号";
  7. person.sex = i % 2 == 0 ? "男" : "女";
  8. personList.add(person);
  9. }

生成流对象

在 Java 8 中, 集合接口有两个方法来生成流:

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

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

  1. Stream<Person> stream = personList.stream();
  2. Stream<Person> personStream = personList.parallelStream();

forEach

  1. //forEach方法说明:迭代流中的每个数据,类似于for循环
  2. //测试forEach方法
  3. personList.stream().forEach(System.out::print);
  4. System.out.println();

map

  1. //测试map方法
  2. //map方法说明:用于映射每个元素到对应的结果
  3. List<Person> collect = personList.stream().map(person -> {
  4. String sex = person.sex;
  5. //把性别都变成男的
  6. person.sex = "男";
  7. return person;
  8. }
  9. ).collect(Collectors.toList());
  10. System.out.println(collect);

filter

  1. //filter
  2. //filter说明:用于通过设置的条件过滤出元素
  3. List<Person> collect1 = personList.stream().filter((person) -> {
  4. //过滤掉性别为男的
  5. String sex = person.sex;
  6. return sex=="女";
  7. }).collect(Collectors.toList());
  8. System.out.println(collect1);

limit

  1. //limit
  2. //limit说明:用于获取指定数量的流,注意返回的也是Stream对象
  3. //需求说明:只要2条数据,并且将person做成map
  4. List<HashMap<String, Object>> collect2 = personList.stream().limit(2)
  5. .filter(person -> person.id % 2 == 0)
  6. .map(person -> {
  7. // List<Map<String, Object>> maps = new ArrayList<>();
  8. HashMap<String, Object> map = new HashMap<>();
  9. map.put("sex", person.sex);
  10. map.put("id", person.id);
  11. map.put("name", person.name);
  12. // maps.add(map);
  13. return map;
  14. }).collect(Collectors.toList());
  15. System.out.println(collect2);

sorted

  1. //sorted
  2. //sorted:排序
  3. //按照id进行排序
  4. List<Person> collect3 = personList.stream().
  5. sorted((Person p1,Person p2)->{
  6. return p2.id - p1.id;
  7. }).collect(Collectors.toList());
  8. System.out.println(collect3);

完整实例及结果图

代码

  1. import java.util.*;
  2. import java.util.stream.Collectors;
  3. import java.util.stream.Stream;
  4. /**
  5. * @作者 five-five
  6. * @创建时间 2021/2/16
  7. * @warn 如果使用Stream对象不可在使用后,会马上关闭。如果一个Stream对象被多次调用会出现该错误
  8. * Exception in thread "main" java.lang.IllegalStateException:
  9. * stream has already been operated upon or closed
  10. *
  11. */
  12. public class TestStream01 {
  13. public static void main(String[] args) {
  14. //首先做一些测试数据,测试类使用Person
  15. class Person {
  16. int id;
  17. String name;
  18. String sex;
  19. @Override
  20. public String toString() {
  21. return "Person{" +
  22. "id=" + id +
  23. ", name='" + name + '\'' +
  24. ", sex='" + sex + '\'' +
  25. '}';
  26. }
  27. }
  28. //用于测试的集合
  29. List<Person> personList = new ArrayList<>();
  30. for (int i = 0; i < 10; i++) {
  31. Person person = new Person();
  32. person.id = i;
  33. person.name = "测试数据" + i + "号";
  34. person.sex = i % 2 == 0 ? "男" : "女";
  35. personList.add(person);
  36. }
  37. // Stream<Person> stream = personList.stream();
  38. // Stream<Person> personStream = personList.parallelStream();
  39. //System.out.println(personList);
  40. //开始进行流式操作
  41. //forEach方法说明:迭代流中的每个数据,类似于for循环
  42. //测试forEach方法
  43. personList.stream().forEach(System.out::print);
  44. System.out.println();
  45. //测试map方法
  46. //map方法说明:用于映射每个元素到对应的结果
  47. List<Person> collect = personList.stream().map(person -> {
  48. String sex = person.sex;
  49. //把性别都变成男的
  50. person.sex = "男";
  51. return person;
  52. }
  53. ).collect(Collectors.toList());
  54. System.out.println(collect);
  55. //filter
  56. //filter说明:用于通过设置的条件过滤出元素
  57. List<Person> collect1 = personList.stream().filter((person) -> {
  58. //过滤掉性别为男的
  59. String sex = person.sex;
  60. return sex=="女";
  61. }).collect(Collectors.toList());
  62. System.out.println(collect1);
  63. //limit
  64. //limit说明:用于获取指定数量的流,注意返回的也是Stream对象
  65. //需求说明:只要2条数据,并且将person做成map
  66. List<HashMap<String, Object>> collect2 = personList.stream().limit(2)
  67. .filter(person -> person.id % 2 == 0)
  68. .map(person -> {
  69. // List<Map<String, Object>> maps = new ArrayList<>();
  70. HashMap<String, Object> map = new HashMap<>();
  71. map.put("sex", person.sex);
  72. map.put("id", person.id);
  73. map.put("name", person.name);
  74. // maps.add(map);
  75. return map;
  76. }).collect(Collectors.toList());
  77. System.out.println(collect2);
  78. //sorted
  79. //sorted:排序
  80. //按照id进行排序
  81. List<Person> collect3 = personList.stream().
  82. sorted((Person p1,Person p2)->{
  83. return p2.id - p1.id;
  84. }).collect(Collectors.toList());
  85. System.out.println(collect3);
  86. }
  87. }

效果图

JDK1.8的Stream流的使用(提高对集合操作的便利性) - 图1