一、说明
Stream是以声明的方式将源数据的元素形成队列并执行一系列运算和表达的抽象,元素流在管道中经过中间操作(返回Stream本身)的处理,最后由终止操作(返回特定类型)得到前面处理的结果
Stream支持Collection的子类如List或者Set,不支持Map类型;Stream自身不会存储元素,也不会改变数据源对象,同时操作是惰性的,只有在终止操作执行后,所有的中间操作才会一次执行
二、示例
- 1、创建
// Stream 的 of() 静态方法
Stream<String> streamOf = Stream.of("aa", "bb", "cc");
// Stream 的 Builder 构建模式
Stream<Object> streamBuild = Stream.builder().add("aa").add("bb").add("cc").build();
// Arrays 的 stream() 静态方法
Stream<String> streamArrays = Arrays.stream(new String[] { "aa", "bb", "cc" });
// Collection 接口提供的 stream() 默认方法
Stream<String> streamCollection = new ArrayList<String>().stream();
// Stream 的 iterate() 方法 无限流 迭代运算 (起始值,运算逻辑)
Stream<Integer> streamIterate = Stream.iterate(0, (x) -> x + 2);
// Stream 的 generate() 方法 无限流 随机生成
Stream<Double> streamGenerate = Stream.generate(() -> Math.random());
- 2、迭代
// 标准
stus.stream().forEach(item -> System.out.println(item));
// 限量 使流中元素个数不超过指定数量
stus.stream().limit(3).forEach(item -> System.out.println(item));
// 跳过 跳过前n个元素,若流中元素不足则返回一个空流
stus.stream().skip(4).forEach(System.out::println);
// 去重 通过hashCode()和equals()方法,实体类需要重写
stus.stream().distinct().forEach(System.out::println);
// 过滤 通过条件过滤数据
stus.stream().filter(item -> item.getAge() > 18).forEach(System.out::println);
List<Student> distStuList = stuList.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(item -> item.getId()))), ArrayList::new)
);
- 3、映射
// 映射(将对象转换为其他对象,如提取字段、构造为其他类型的对象等)
stus.stream().map(item -> item.getName()).forEach(item -> System.out.println(item));
// 扁平映射(相较于map()的将所有元素直接转换组成新的流;flatMap会将元素也转换成流,再将所有的元素流合并成一个流)
stus.stream().flatMap(item -> Arrays.stream(item.getName().split(""))).forEach(System.out::println);
- 4、排序
// 排序 默认,按照元素实现的Comparable中的compareo()方法,未实现将抛异常
stus.stream().map(Student::getName).sorted().forEach(System.out::println);
// 排序 自定义,实现Comparator接口的compare方法
stus.stream().sorted((c, n) -> c.getAge() - n.getAge()).forEach(System.out::println);
- 5、匹配
// 匹配 是否所有元素都匹配 断言
System.out.println(stus.stream().allMatch(item -> item.getAge() > 19));
// 匹配 是否至少有一个元素匹配
System.out.println(stus.stream().anyMatch(item -> item.getAge() > 19));
// 匹配 是否没有一个元素匹配
System.out.println(stus.stream().noneMatch(item -> item.getAge() > 19));
- 6、查找
// 查找 返回第一个元素
System.out.println(stus.stream().findFirst().get());
// 查找 返回任意一个元素
System.out.println(stus.stream().findAny().get());
- 7、最值
// 最大值对象 返回包含指定属性最大值元素的容器(取排序后最后一个,倒序的max实际为最小)
System.out.println(stus.stream().max((c, n) -> Integer.compare(c.getId(), n.getId())).get());
// 提取最大值 返回包含指定属性的最大值的容器
System.out.println(stus.stream().map(Student::getAge).max(Integer::compareTo).get());
// 最小值对象
System.out.println(stus.stream().min((c, n) -> Integer.compare(c.getAge(), n.getAge())).get());
- 8、运算
// 统计数量
Long count = stus.stream().count();
Long count = stus.stream().collect(Collectors.counting());
// 求平均值
Double avgAge = stus.stream().collect(Collectors.averagingDouble(Student::getAge)));
// 求和
Integer sumAge = stus.stream().collect(Collectors.summingInt(Student::getAge));
Integer sumAge = stus.stream().map(Student::getAge).reduce(Integer::sum).get()
// 求最大值
Integer maxAge = stus.stream().map(item -> item.getAge()).max((a, b) -> Integer.compare(a, b)).get();
Integer maxAge = stus.stream().max((a, b)-> Integer.compare(a.getAge(), b.getAge())).get().getAge();
Integer maxAge = stus.stream().collect(Collectors.maxBy((a, b) -> Integer.compare(a.getAge(), b.getAge()))).get().getAge();
// 求最小值
Integer maxAge = stus.stream().map(item -> item.getAge()).min((a, b) -> Integer.compare(a, b)).get();
// 计算方法总括函数 summarizingType 传入计算的属性,返回 TypeSummaryStatistics 实例,包含 Average、Count、Max、Sum 等计算方法
Double avgAge = stus.stream().collect(Collectors.summarizingInt(Student::getAge)).getAverage();
- 9、字段连接
// collect 方式
String namesJoin = stus.stream().map(Student::getName).collect(Collectors.joining());
String namesJoin = stus.stream().map(Student::getName).collect(Collectors.joining(", "));
// reduce 方式
String namesJoin = stus.stream().map(Student::getName).reduce((c, n) -> c + ", " + n);
String namesJoin = stus.stream().map(Student::getName).reduce("NamesJoin: ", (c, n) -> c + ", " + n);
- 10、转换分组
// List转为Map(根据ID映射同学的对象或同学的名字属性)
Map<Integer, Student> idStuMap = stus.stream().collect(Collectors.toMap(item -> item.getId(), item -> item));
Map<Integer, String> idNameMap = stus.stream().collect(Collectors.toMap(item -> item.getId(), item -> item.getName()));
// 自定义转换(定义为Collectors没有静态实现的数据结构)
HashSet<Student> stuSet = stus.stream().collect(Collectors.toCollection(HashSet::new));
// 指定字段的指定值的单一统计(统计指定省份的同学数量)
Long fromCount = stus.stream().filter( item -> item.getFrom() == "HuNan").count();
// 指定字段的所有值的分组统计(统计所有省份各自的同学数量)
Map<String, Long> fromCount = stus.stream().collect(Collectors.groupingBy(item -> item.getFrom(), Collectors.counting()));
// 指定字段的所有对象的分组 (根据省份分组同学的对象列表)
Map<String, List<Student>> fromStuMap = stus.stream().collect(Collectors.groupingBy(item -> item.getFrom()));
// 指定字段的所有对象的指定值的分组 (根据省份分组同学的ID列表)
Map<String, List<String>> fromStuIdMap = stus.stream().collect(Collectors.groupingBy(item -> item.getFrom(), Collectors.mapping(item -> item.getId(), Collectors.toList())));
// 指定字段分区 (分区的特点在于,结果集只分为指定的条件成立和不成立的两个组,如:大于18岁和小于等于18岁的两个组)
Map<Boolean, List<Student>> ageBoolMap = stus.stream().collect(Collectors.partitioningBy(item -> item.getAge() > 18));
// 多级分组 (根据多个字段内嵌式分组;如:先按班级分组,然后在班级内再按省份分组)
Map<Integer, Map<String, List<Student>>> clsFromStuMap = stus.stream().collect(Collectors.groupingBy(Student::getClsId(), Collectors.groupingBy((stu) -> stu.getFrom())));