Stream API
-
流的概念:
- 是数据渠道,用于操作数据源所生成的元素序列。集合讲的是数据,流讲的是计算
- 注意
- Stream自己不会存储元素
- Stream不会改变源对象。相反,他们会返回一个持有结果的新的Stream
- Stream操作是延迟执行的。意味着他们会等到需要结果的时候才会执行。
-
步骤
- 创建Stream
- 中间操作
- 终止操作
-
创建stream
-
可以通过collection系列集合提供的stream()或parallelStream()方法获取,第一个是串行流,第二个是并行流。
List<String>list = new ArrayList<>(); Stream<String> stream = list.stream();
-
通过Arrays中的静态方法stream()获取数组流
List<String>list = new ArrayList<>(); Stream<String> stream = list.stream();
-
通过Stream类中的静态方法of()
Stream<String> stringStream = Stream.of("aa", "bb", "cc");
-
创建无限流
// 迭代 Stream<Integer> integerStream = Stream.iterate(0, (x) -> x + 2); // 生成 Stream<Double> doubleStream = Stream.generate(Math::random);
-
-
中间操作:
-
惰性求值:多个中间操作连接成一个流水线,除非流水线触发终止操作,否则中间操作不会执行任何处理。在终止操作时一次性全部处理。
-
筛选与切片操作:
-
Filter:接收lambda,从流中排除某些元素
-
内部迭代:
-
惰性求值:
-
filter(x -> x.getAge() > 10)
-
-
limit:截断流,使其元素不超过给定数量
-
内部会先找到满足条件的前n个值,内部迭代操作也仅仅在这几个值进行,我们称之为短路
employees.stream().filter(e->{ System.out.println("limit"); return e.getSalary() > 5000; }).limit(5).forEach(System.out::println);
-
-
skip:跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit互补
-
distinct:筛选,通过流所生成元素的hashcode( )和equals()去除重复元素
- 如果需要对Object进行去重,需要重写hashCode和equals方法
-
-
映射:
-
map(Function f):
- 接收Lambda,将元素转化为其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。
- map操作返回的依然是流。
- 经过map操作后的流的元素会变,根据map中Lambda的返回值变化。
-
mapToDouble(ToDoubleFunction f)
-
mapToInt(ToIntFunction f)
-
mapToLong(ToLongFunction f)
-
flatMap(Function f):接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
-
flatMap和Map的区别:
- 二者的区别类似于add和addAll的区别,前者如果使用list2.add(list),结果会是将整个list作为一个元素放进list2,而list2.addAll(list),是将list里面的每个元素拆分开,以元素的方式存进去。
public static Stream<Character> filterCharacter(String str){ List<Character>list = new ArrayList<>(); for(Character ch:str.toCharArray()){ list.add(ch); } return list.stream(); } @Test public void test6(){ List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee"); // 用map,返回Stream<Stream<Character>> Stream<Stream<Character>> streamStream = list.stream() .map(TestStreamAPI2::filterCharacter); // 用flatMap,返回Stream<Character> Stream<Character> characterStream = list.stream() .flatMap(TestStreamAPI2::filterCharacter); }
-
-
排序:
-
sorted():自然排序,按照对象指定的Comparable排序
-
sorted(Comparator comp):定制排序Comparator
employees.stream() .sorted((e1,e2)->{ if(e1.getAge()!=e2.getAge()){ return -e1.getAge()+e2.getAge(); }else return e1.getName().compareTo(e2.getName()); }).forEach(System.out::println);
-
-
-
终止操作
-
查找与匹配
-
allMatch():检查是否匹配所有元素,相当于全称量词
boolean b = employees.stream() .allMatch(e -> e.getStatus().equals(Status.BUSY));
-
anyMatch():是否存在一个匹配值,相当于存在量词
-
noneMatch():检查是否没有匹配的元素,相当于存在量词的非
-
findFirst():找到第一个元素,返回optional对象
-
Optional对象:一个容器类,为了避免空指针异常,当返回的值有可能为空时,就会封装进optional
-
orElse方法:如果当前容器封装的对象指针为空,可以搞一个替代的对象
Optional<Employee> first = employees.stream() .sorted(Comparator.comparingDouble(Employee::getSalary)) .findFirst(); first.orElse(new Employee());
-
-
findAny():找到任意一个元素
-
count:返回流中元素总数
long count = employees.stream().count();
-
min:返回流中最小值
Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compare); System.out.println(min.get());
-
max:返回流中的最大值
-
-
归约 reduce(T identity, Binaryoperator) / reduce(BinaryOperator) 可以将流中元素反复结合起来,得到一个值。
-
reduce(T identity, Binaryoperator) : 第一个参数为启始值,第二个参数为运算式
-
map-reduce 连用成为map-reduce模式:
Optional<Double> map-reduce = employees.stream() .map(Employee::getSalary) .reduce(Double::sum); System.out.println();
-
-
收集 collect-将流转换为其他形式。接收一个collector接口的实现,用于Stream中元素汇总方法
-
collect(Collector c )
// 使用list List<String> collect = employees.stream() .map(Employee::getName) .collect(Collectors.toList()); collect.forEach(System.out::println); // 使用set Set<String> set = employees.stream() .map(Employee::getName) .collect(Collectors.toSet()); set.forEach(System.out::println); // 使用构造 HashSet<String> stringHashSet = employees.stream() .map(Employee::getName) .collect(Collectors.toCollection(HashSet::new));
-
Collector.counting:收集总数
Long aLong = employees.stream().collect(Collectors.counting());
-
Collector.avg : 平均值
Double avg = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));
-
Collector.summing :总和
Double sum = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));
-
最大值:
Optional<Employee> max = employees.stream() .collect(Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary)));
-
最小值
Optional<Double> min = employees.stream().map(e -> e.getSalary()) .collect(Collectors.minBy(Double::compareTo)); // 或者 Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compareTo);
-
分组:
Map<Status, List<Employee>> statusListMap = employees.stream().collect(Collectors.groupingBy(Employee::getStatus));
-
多级分组
Map<Status, Map<String, List<Employee>>> statusMapMap = employees.stream() .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(e -> { if (e.getAge() > 50) return "老年"; else if (e.getAge() <= 50 && e.getAge() > 30) return "中年"; else return "青年"; })));
-
分区
Map<Boolean, List<Employee>> listMap = employees.stream() .collect(Collectors.partitioningBy(e -> e.getSalary() > 8000));
-
统计
DoubleSummaryStatistics collect = employees.stream() .collect(Collectors.summarizingDouble(Employee::getSalary)); System.out.println(collect.getAverage()); System.out.println(collect.getMax()); System.out.println(collect.getSum());
-
字符串连接
String collectStr = employees.stream().map(Employee::getName).collect(Collectors.joining(","));
-
-