快速入门的小栗子,遍历列表
List<Integer> list = Arrays.asList(1,2,3,4,5);
list.stream().forEach(System.out::println);//即可打印出1,2,3,4,5
Stream流是什么
- 我们可以把集合,数组想象成存储数据的容器,相当于存储原材料的仓库,而Stream则是对这些原材料加工的流水线,是对数据进行的加工。入门的例子中,list存储了数据,而Stream操作对数据进行了加工,即打印。
- 流不存储元素,流只是数据的加工者。
- 流不会改变源对象,返回的依然是Stream
- 流的操作是延迟执行的,有中止操作时才会执行
为什么用Stream流
集合类库主要依赖于外部迭代(external iteration)。Collection 实现 Iterable 接口,从而使得用户可以依次遍历集合的元素。流相比于for循环是内部迭代的,用户把对迭代的控制权交给类库,并向类库传递迭代时所需执行的代码,从而允许类库进行各种各样的优化(例如乱序执行、惰性求值和并行等等)。总的来说,内部迭代使得外部迭代中不可能实现的优化成为可能。
使用Stream流的步骤
- 和把大象装进冰箱的步骤一样多,都需要三步:
- 创建流:通过一个数据源,如集合,数组,来创建一个流
- 中间操作流: 中间操作链,对数据源的数据进行处理
- 结束流:一旦执行中止操作,就执行中间操作链,并产生结果。之后不会再被使用。
常用的API
- 创建流的API
- 通过集合创建流
- default Stream stream():返回一个顺序流
- default Stream parallelStream():返回一个并行流
List<Integer> list = Arrays.asList(1,2,3); Stream<Integer> stream1= list.stream(); Stream<Integer> stream2= list.parallelStream(); - 通过数组创建流,Arrays的静态方法stream()可以获取数组流
- static Stream stream(T[] array):返回一个流
- public static IntStream stream(int[] array)
- public static LongStream stream(long[] array)
- public static DoubleStream stream(double[] array)
//调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流 int[] arr = new int[]{1,2,3,4,5,6}; IntStream stream = Arrays.stream(arr); double[] d = new double[]{1.0,2.0}; DoubleStream doubleStream = Arrays.stream(d); Employee e1 = new Employee(1001,"Tom"); Employee e2 = new Employee(1002,"Jerry"); Employee[] arr1 = new Employee[]{e1,e2}; Stream<Employee> stream1 = Arrays.stream(arr1); - 通过Stream类的静态方法of()
- public static Stream of(T... values): 返回一个流
Stream<Integer> stream = Stream.of(1,2,3,4,5); - 创建无限流,使用静态方法Stream.iterate()和Stream.generate(),创建无限流。
- 迭代 public static Stream iterate(final T seed,final UnaryOperator f)
- 生成 public static Stream generate(Supplier s)
// 迭代 // public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) //遍历前10个偶数 Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println); // 生成 // public static<T> Stream<T> generate(Supplier<T> s) Stream.generate(Math::random).limit(10).forEach(System.out::println);
- 通过集合创建流
- 中间操作流的API 多个中间操作可以连接起来形成一个流水线,除非流水线上触发中止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,称为“惰性求值”
- 过滤filter(Predicate p) 删除不想要的元素
- 截断limit(long maxSize) 获取指定数量
- 去重distinct() 通过hashCode()和equals()去重
- 跳过元素skip(long n) ,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流
int[] arr={1,2,2,5,4,3};
//filter(Predicate p) 过滤元素
Arrays.stream(arr).filter(e->e>2).forEach(System.out::println);//[5,4,3]
//limit
Arrays.stream(arr).limit(3).forEach(System.out::println);//[1,2,2]
//distinct
Arrays.stream(arr).distinct().forEach(System.out::println);//[1,2,5,4,3]
//skip
Arrays.stream(arr).skip(2).forEach(System.out::println);//[2,5,4,3]
-
映射
- map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
- mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream
- mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream
- flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流
Stream<String> stringStream = Stream.of("abc"); stringStream.map(e->e.toUpperCase()).forEach(System.out::println);//[ABC] Stream.of("abc").map(s->s.split("")).forEach(System.out::println);//[Ljava.lang.String;@ffaaaf0 Stream.of("abc").map(s->s.split("")).flatMap(Arrays::stream).forEach(System.out::println);//[a,b,c] -
排序
- sorter() 产生一个新流,其中按自然顺序排序
- sorted(Comparator com) 产生一个新流,其中按比较器顺序排序
Stream.of(2,1,3,5,4).sorted().forEach(System.out::println);//1,2,3,4,5 Stream.of(2,1,3,5,4).sorted((o1,o2)->o2.compareTo(o1)).forEach(System.out::println);//5,4,3,2,1 -
结束流的API(流进行了终止操作后不能再次使用)
-
匹配与查找
| 方法 | 描述 | 例子 |
|---|---|---|
| allMatch(Predicate p) | 检查是否匹配所有元素 | boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18) |
| anyMatch(Predicate p) | 检查是否只匹配一个元素 | employees.stream().anyMatch(e -> e.getSalary() > 10000) |
| noneMatch(Predicate p) | 检查是否没有匹配所有元素 | employees.stream().noneMatch(e -> e.getName().startsWith("雷")) |
| findFirst() | 返回第一个元素 | Optional<Employee> employee = employees.stream().findFirst() |
| findAny() | 返回当前流中的任意元素 | Optional<Employee> employee1 = employees.parallelStream().findAny() |
| count() | 返回流中元素总数 | employees.stream().filter(e -> e.getSalary() > 5000).count() |
| max(Comparator c) | 返回流中最大值 | Optional<Double> maxSalary = salaryStream.max(Double::compare) |
| min(Comparator c) | 返回流中最小值 | Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())) |
| forEach(Consumer c) | 内部迭代 | employees.stream().forEach(System.out::println) |
List<Employee> employees = EmployeeData.getEmployees();
// allMatch(Predicate p)——检查是否匹配所有元素。
// 练习:是否所有的员工的年龄都大于18
boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
System.out.println(allMatch);
// anyMatch(Predicate p)——检查是否至少匹配一个元素。
// 练习:是否存在员工的工资大于 10000
boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000);
System.out.println(anyMatch);
// noneMatch(Predicate p)——检查是否没有匹配的元素。
// 练习:是否存在员工姓“雷”
boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));
System.out.println(noneMatch);
// findFirst——返回第一个元素
Optional<Employee> employee = employees.stream().findFirst();
System.out.println(employee);
// findAny——返回当前流中的任意元素
Optional<Employee> employee1 = employees.parallelStream().findAny();
System.out.println(employee1);
List<Employee> employees = EmployeeData.getEmployees();
// count——返回流中元素的总个数
long count = employees.stream().filter(e -> e.getSalary() > 5000).count();
System.out.println(count);
// max(Comparator c)——返回流中最大值
// 练习:返回最高的工资:
Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());
Optional<Double> maxSalary = salaryStream.max(Double::compare);
System.out.println(maxSalary);
// min(Comparator c)——返回流中最小值
// 练习:返回最低工资的员工
Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(employee);
System.out.println();
// forEach(Consumer c)——内部迭代
employees.stream().forEach(System.out::println);
//使用集合的遍历操作
employees.forEach(System.out::println);
- 归约
| 方法 | 描述 | 例子 |
|---|---|---|
| reduce(T iden,BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回T | list.stream().reduce(0, Integer::sum) |
| reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值,返回Optional<T> | Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2); |
// reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
// 练习1:计算1-10的自然数的和
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0, Integer::sum);
System.out.println(sum);
// reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
// 练习2:计算公司所有员工工资的总和
List<Employee> employees = EmployeeData.getEmployees();
Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
// Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
System.out.println(sumMoney.get());
- 收集
| 方法 | 描述 |
|---|---|
| collect(Collector c) | 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法 |
Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、 Map)。 另外, Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例, 具体方法与实例如下表:
| 方法 | 返回类型 | 作用 | 例子 |
|---|---|---|---|
| toList | List<T> | 把流中元素收集到List | List<Employee> emps = list.stream().collect(Collectors.toList()) |
| toSet | Set<T> | 把流中元素收集到Set | Set<Employee> emps = list.stream().collect(Collectors.toSet()) |
| toCollection | Collection<T> | 把流中元素收集到创建的集合 | Collection<Employee> emps = list.stream().collect(Collectors.toCollection(ArrayList::new)) |
| counting | Long | 计算流中元素个数 | long count = list.stream().collect(Collectors.counting()) |
| summingInt | Integer | 对流中元素的整数属性求和 | int total = list.stream().collect(Collectors.summingInt(Employee::getSalary)) |
| averageingInt | Double | 计算流中元素Integer属性的平均值 | double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary)) |
| summarizingInt | IntSummaryStatistics | 收集流中Integer属性的统计值。如平均值 | int SummaryStatistics=list.stream().collect(Collectors.summarizingInt(Employee::getSalary)) |
| joining | String | 连接流中每个字符串 | String str= list.stream().map(Employee::getName).collect(Collectors.joining()) |
| maxBy | Optional<T> | 根据比较器选择最大值 | Optionalmax=list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary))) |
| minBy | Optional<T> | 根据比较器选择最小值 | Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary))) |
| reducing | 归约产生的类型 | 从一个作为累加器的初始值开始, 利用BinaryOperator与流中元素逐 个结合,从而归约成单个值 | int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum)) |
| collectingAndThen | 转换函数返回的类型 | 包裹另一个收集器,对其结果转换函数 | int how=list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),List::size)) |
| groupingBy | Map<K,List<T>> | 根据某属性值对流分组,属性为K,结果为V | Map<Emp.Status,List<Emp>> map=list.stream().collect(Collectors.groupingBy(Employee::getStatus)) |
| partitioningBy | Map<Boolean,List<T>> | 根据true或false进行分区 | Map<Boolean,List<Emp>> vd=list.stream().collect(Collectors.partitioningBy(Employee::getManage)) |
// collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
// 练习1:查找工资大于6000的员工,结果返回为一个List或Set
List<Employee> employees = EmployeeData.getEmployees();
List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
employeeList.forEach(System.out::println);
System.out.println();
Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
employeeSet.forEach(System.out::println);