一、概述
Stream作为java8的新特性,基于lambda表达式,是对集合对象功能的增强,它专注于对集合对象进行各种高效、便利的聚合操作或者大批量的数据操作,提高了编程效率和代码可读性。
Stream的原理:将要处理的元素看做一种流,流在管道中传输,并且可以在管道的节点上处理,包括过滤筛选、去重、排序、聚合等。元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。
特点:
1. 只能遍历一次 我们可以把流想象成一条流水线,流水线的源头是我们的数据源(一个集合),数据源中的元素依次被输送到流水线上,我们可以在流水线上对元素进行各种操作。 一旦元素走到了流水线的另一头,那么这些元素就被“消费掉了”,我们无法再对这个流进行操作。当然,我们可以从数据源那里再获得一个新的流重新遍历一遍。
2. 采用内部迭代方式 若要对集合进行处理,则需我们手写处理代码,这就叫做外部迭代。 而要对流进行处理,我们只需告诉流我们需要什么结果,处理过程由流自行完成,这就称为内部迭代。
中间操作 | 无状态 | filter map flatMap peek |
有状态 | distinct sorted limit skip | |
结束操作 | 非短路操作 | forEach reduce collect max min count |
短路操作 | anyMatch allMatch noneMatch findFirst findAny |
无状态:指元素的处理不受之前元素的影响;
有状态:指该操作只有拿到所有元素之后才能继续下去。
非短路操作:指必须处理所有元素才能得到最终结果;
短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。
二、Stream流的具体用法
2.1 并行流
并行流就是一个把内容分成多个数据块,并用不不同的线程分别处理每个数据块的流。最后合并每个数据块的计算结果。 将一个顺序执行的流转变成一个并发的流只要调用 `parallel()` 方法 public static long parallelSum(long n){ return Stream.iterate(1L, i -> i +1).limit(n).parallel().reduce(0L,Long::sum); } 将一个并发流转成顺序的流只要调用 `sequential()` 方法 stream.parallel().filter(...).sequential().map(...).parallel().reduce();
并非使用多线程并行流处理数据的性能一定高于单线程顺序流的性能,因为性能受到多种因素的影响。 如何高效使用并发流的一些建议: 1. 如果不确定, 就自己测试。 2. 尽量使用基本类型的流 IntStream, LongStream, DoubleStream 3. 有些操作使用并发流的性能会比顺序流的性能更差,比如limit,findFirst,依赖元素顺序的操作在并发流中是极其消耗性能的。findAny的性能就会好很多,应为不依赖顺序。 4. 考虑流中计算的性能(Q)和操作的性能(N)的对比, Q表示单个处理所需的时间,N表示需要处理的数量,如果Q的值越大, 使用并发流的性能就会越高。 5. 数据量不大时使用并发流,性能得不到提升。 6. 考虑数据结构:并发流需要对数据进行分解,不同的数据结构被分解的性能时不一样的。
2.2 流的常用创建方法
**1. 集合**
这种数据源较为常用,通过stream()方法即可获取流对象:
List<String> list = new ArrayList<String>();
Stream<String> stream = list.stream();
**2. 数组**
通过Arrays类提供的静态函数stream()获取数组的流对象:
String[] names={"array","list","val","of","file","iterator","generate","Buffer","split"}
Stream<String> stream = Arrays.stream(names);
**3. 值**
直接将几个值变成流对象:
Stream<String> stream = Stream.of("array","list","val");
**4. 文件**
try(Stream lines = Files.lines(Paths.get(“文件路径名”),Charset.defaultCharset())){
//可对lines做一些操作
}catch(IOException e)
{}
**5. 迭代器**
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
**6. 无序流**
Stream<Integer> TestStream3 = Stream.generate(()-> new Random().nextInt(10));
**7. 字符串分割流**
Pattern pattern = Pattern.compile(",");
Stream<String> stringStream2 = pattern.splitAsStream("a,b,c,d");
下面我们来具体使用一下