Java 8 中的 Stream 是对集合(Collection)对象功能的加强,它专一于对集合对象进行各类很是便利、高效的聚合操做(aggregate operation),或者大批量数据操做 (bulk data operation)。 它提供串行和并行两种模式进行汇聚操做,并发模式可以充分利用多核处理器的优点,使用fork/join并行方式来拆分任务和加速处理过程。数组
###前言安全
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次。 流的构成: 获取一个数据源(source)→ 数据转换 → 执行操做获取想要的结果。 每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(能够有屡次转换)。 转换操做是lazy(惰性求值,只能迭代一次): 只有在Terminal操做执行时,才会一次性执行。 Stream 里有个操做函数的集合,每次转换操做就是把转换函数放入这个集合中。 在 Terminal 操做的时候循环 Stream 对应的集合,而后对每一个元素执行全部的函数。
###构造流的几种常见方法数据结构
1. Individual values Stream stream = Stream.of("a", "b", "c"); 2. Arrays String [] strArray = new String[]{"a", "b", "c"}; stream = Stream.of(strArray); stream = Arrays.stream(strArray); 3. Collections List<String> list = Arrays.asList(strArray); stream = list.stream(); 文件生成流: Stream<String> stream = Files.lines(Paths.get("data.txt"));
###流转换为其它数据结构并发
1. Array String[] strArray1 = stream.toArray(String[]::new); 2. Collection List<String> list1 = stream.collect(Collectors.toList()); List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new)); Set set1 = stream.collect(Collectors.toSet()); Stack stack1 = stream.collect(Collectors.toCollection(Stack::new)); 3. String String str = stream.collect(Collectors.joining()).toString();
###流的操做dom
当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各种操做了。常见的操做能够归类以下。 中间操做: Intermediate(主要是打开流,作出某种程度的数据映射/过滤,而后返回一个新的流) map(mapToInt, flatMap)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered .filter(person -> person.getAge() == 20) 过滤器 .distinct() 去除重复元素,这个方法是经过类的 equals 方法来判断两个元素是否相等的 .sorted()(流中的元素的类实现了 Comparable 接口) / sorted((p1, p2) -> p1.getAge() - p2.getAge()) 排序 .sorted(Comparator.comparingInt(Person::getAge)) .limit(long n) 返回前 n 个元素 .skip(long n) 去除前 n 个元素 .map(T -> R) 将流中的每个元素 T 映射为 R(相似类型转换) .map(Person::getName) .flatMap(T -> Stream<R>) 将流中的每个元素 T(数组) 映射为一个流,再把每个流链接成为一个流 .flatMap(Arrays::stream) 结束操做: Terminal(流的最后一个操做) forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator boolean b = list.stream().anyMatch(person -> person.getAge() == 20); 判断是否有匹配条件的元素 .allMatch(T -> boolean) 是否全部元素都符合匹配条件 .reduce((T, T) -> T) 和 reduce(T, (T, T) -> T) 用于组合流中的元素,如求和,求积,求最大值等 .reduce(0, Integer::sum) reduce 第一个参数 0 表明起始值为 0 .count() 返回流中元素个数,结果为 long 类型 .collect() 收集方法 最经常使用的方法,把流中全部元素收集到一个 List Set Collection 中 toList() toSet() toCollection() toMap() joining() 链接字符串 counting() 计算总和
###数值流ide
Stream<Integer> 类型,而每一个 Integer 都要拆箱成一个原始类型再进行 sum 方法求和,这样大大影响了效率。 针对这个问题 Java 8 有良心地引入了数值流 IntStream, DoubleStream, LongStream。 三种对应的包装类型 Stream: IntStream、LongStream、DoubleStream IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println); IntStream.range(1, 3).forEach(System.out::println); 半开区间[) IntStream.rangeClosed(1, 3).forEach(System.out::println); 闭区间[] 流转换为数值流: mapToInt(T -> int) : return IntStream mapToDouble(T -> double) : return DoubleStream mapToLong(T -> long) : return LongStream 数值流转换为流: Stream<Integer> stream = intStream.boxed(); 数值流方法: sum() max() min() average()
###并行流(必须是线程安全的)函数
Stream.of(list).parallel();
###无限长度的流线程
generator: generator方法,返回一个无限长度的Stream,其元素由Supplier接口的提供。 在Supplier是一个函数接口,只封装了一个get()方法,其用来返回任何泛型的值。 - generate(Supplier<T> s):返回一个无限长度的Stream 示例: 1. Stream<Double> generateA = Stream.generate(new Supplier<Double>() { @Override public Double get() { return Math.random(); } }); 2. Stream<Double> generateB = Stream.generate(()->Math.random()); 3. Stream<Double> generateC = Stream.generate(Math::random); iterate iterate方法,其返回的也是一个无限长度的Stream。 与generate方法不一样的是,其是经过函数f迭代对给指定的元素种子而产生无限连续有序Stream, 其中包含的元素能够认为是:seed,f(seed),f(f(seed))无限循环。 - iterate(T seed, UnaryOperator<T> f) 示例: Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println); // 打印结果:1,2,3,4,5,6,7,8,9,10 上面示例,种子为1,也可认为该Stream的第一个元素, 经过f函数来产生第二个元素。 接着,第二个元素,做为产生第三个元素的种子,从而产生了第三个元素, 以此类推下去。 须要注意的是,该Stream也是无限长度的, 应该使用filter、limit等来截取Stream,不然会一直循环下去。