Stream介绍
在JDK1.8,Collection 接口新增了 stream 方法,用于构建 Stream 对象,从而进行一系列对集合的操作。
- stream 是一个元素的序列,它支持串行与并行的聚合操作;
- stream 本身不存储值,它通过管道(AbstractPipeline)的方式获取值;
- stream 本质是函数式的,对流的操作会生成一个结果,不过并不会修改底层的数据源,集合可以作为流的底层数据源;
- stream 可以设置延迟查找特性,很多流操作(过滤、映射、排序等)都可以延迟实现;
- stream 由 数据源、零个或多个中间操作、终止操作 构成
- stream 的链式操作特性:若最后没有添加终止操作,中间所定义的操作都不会执行;当调用终止操作时,流即会输出结果
- stream 的特性
- 流每进行一次中间操作,都会生成一个全新的流;
- 不能对同一个流进行多次操作,否则会抛出异常;
- 流的所有中间操作在遇到终止操作时,即会对集合进行遍历,同时将中间操作的内容作用于遍历过程,因此流的操作最终只进行了一次遍历操作
stream 的常用方法
- map(Function<? super T, ? extends R> mapper):中间操作,
- 对 steam 中的可用元素进行指定的操作
- mapToInt(ToIntFunction<? super T> mapper):map 方法的原生特化版本,其他还有 mapToDouble 和 mapToLong
- flatMap(Function<? super T, ? extends Stream<? extends R>> mapper):
- 中间操作,将遍历的集合中的元素转化为 stream,然后将这些 stream 进行汇聚合并
- filter(Predicate<? super T> predicate):
- 中间操作,用于判断过滤指定元素
- limit(long maxSize):
- 短路中间操作,用于限定流中元素的个数
- skip(long n):
- 短路中间操作,用于跳过流中指定个数的元素
- findFirst():
- 短路终止操作,获取 stream 中第一个参数,返回一个 Optional(由于数据源中元素个数未知)
- sum():
- IntStream 中的方法,求和,元素个数为0则返回0
- min() / max() / ...:
- IntStream 中的方法,求最大最小值...,返回 OptionalInt
流的本质:内部迭代与外部迭代
- 外部迭代:集合的处理,集合关注的是数据与数据储存本身
- 内部迭代:流的处理,流关注的是对数据的计算
- 注意点:流的内部是存在短路运算的
举例
例子1
学生 A、B 只定义了name和age,图中A与B均使出影分身,分裂成A1、A2 与B1、B2,然后打印出来
public class StreamTest1 { public static void main(String[] args) { List<Student> list = new ArrayList<>(); list.add(new Student("A", 1)); list.add(new Student("B", 2)); list.stream().map(student -> { List<Student> innerList = new ArrayList<>(); innerList.add(new Student(student.getName() + "1", student.getAge())); innerList.add(new Student(student.getName() + "2", student.getAge())); return innerList; }).flatMap(List::stream).forEach(System.out::println); } }
例子2
给出一组字符串:"hello welcome", "hello world", "hello world hello", "hello welcome"
要求:切割空格得出所有英文单词,去重复后打印出来
public class StreamTest2 { public static void main(String[] args) { List<String> list = Arrays.asList("hello welcome", "hello world", "hello world hello", "hello welcome"); list.stream().map(word -> word.split(" ")).flatMap(Arrays::stream).distinct().forEach(System.out::println); } }