Stream 流
Stream 类似于 生产流水线
特点
1:Stream 不会修改源数据
2:Stream 流的部分操作具有延时性
3:Stream 不能存储元素
4:Stream 流是单向的,不能重复操作
Stream 不是集合元素 JDK8中的一个新特性 被我们称为 流
也不是数据结构 不保存数据 它是有关算法和计算操作的 更像高级别版本的迭代器
Stream 单向 不可往复 数据只能遍历一次 就好比流水 从前面流过了 一去不复返
不同的地方在于 支持并行化操作
串行方式
一个一个依次执行
并行 并发
在一个时间段内 多个操作并发的执行
对一列元素进行操作的步骤
想使用
1:获取流的数据源
2:数据转换
3:按照要求得到结果
流的来源
集合 数组 转换为Stream流
将Stream中数据 收集到集合或者数组中
Stream 中的方法
延迟方法 : 返回值类型仍然是Stream接口自身类型的方法,因此支持链式调用。
Stream filter(Predicate p) 通过该方法 将一个流转换成另一个子集流 (按要求过滤)
参数是一个函数式接口 使用Lambda表达式 表达式完成的事情就是条件判断
Stream<T> limit(long n) 对流进行截取 只取前n个 ,截取的长度不能大于参数的长度,否则不进行操作
Stream<T> skip(long n) 跳过前n个元素 截取一个新流
<R> Stream<R> map(Function<T,R> lambda) 需要将流中元素 映射到另一个流中 使用map方法
参数是一个function函数式接口 public R apply(T t); 可以将当前流中的T类型数据 转换为R类型 的流
Lambda中就是完成转换功能的
终结方法 : 返回值类型不再是Stream接口自身类型的方法,
long count() 获取流中的个数 但是这个功能做完 该流程结束
forEach(Consumer lambda) 逐一遍历 (里面是并发元素谁先抢到谁就先出来 )
参数是函数式接口 会将每一个流元素交给该函数进行处理 交给Lambda表达式
接收一个Consumer接口函数,调用public void accept(T t)方法;
静态方法
of(…) 添加数据 形成一个管道
static Stream concat(Stream a,Stream b)
合并流
收集方法
将我们的 流 转换成 List集合
collect(Collectors.toList())
转换成Set集合
collect(Collectors.toSet())
Object[] toArray()
转换成指定数组
T[] toArray(len->new T[len])
获取流
Collection stream()方法
import java.util.*;
import java.util.stream.Stream;
public class Demo04GetStream {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// ...
Stream<String> stream1 = list.stream();
Set<String> set = new HashSet<>();
// ...
Stream<String> stream2 = set.stream();
Vector<String> vector = new Vector<>();
// ...
Stream<String> stream3 = vector.stream();
根据Map获取流
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public class Demo05GetStream {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
// ...
Stream<String> keyStream = map.keySet().stream();
Stream<String> valueStream = map.values().stream();
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
}
}
根据数组获取流
import java.util.stream.Stream;
public class Demo06GetStream {
public static void main(String[] args) {
String[] array = { "张无忌", "张翠山", "张三丰", "张一元" };
Stream<String> stream = Stream.of(array);
}
}
并发流:
转换为并发流
S parallel();
直接获取并发流
default Stream parallelStream() {…}
并发流原理介绍
对于并行流,其在底层实现中,是沿用了Java7提供的fork/join分解合并框架进行实现。fork根据cpu核数进行数
据分块,join对各个fork进行合并。实现过程如下所示:
假设现在的求和操作是运行在一台4核的机器上。
使用注意事项
对于并行流,一定不要陷入一个误区:并行一定比串行快。并行在不同的情况下它不一定是比串行快的。影响并行
流性能主要存在5个因素:
1)数据大小:输入数据的大小,直接影响了并行处理的性能。因为在并行内部实现中涉及到了fork/join操作,它
本身就存在性能上的开销。因此只有当数据量很大,使用并行处理才有意义。
2)源数据结构:fork时会对源数据进行分割,数据源的特性直接影响了fork的性能。
ArrayList、数组或IntStream.range,可分解性最佳,因为他们都支持随机读取,因此可以被任意分割。
HashSet、TreeSet,可分解性一般,其虽然可被分解,但因为其内部数据结构,很难被平均分解。
LinkedList、Streams.iterate、BufferedReader.lines,可分解性极差,因为他们长度未知,无法确定在哪里进行
分割。
3)装箱拆箱
尽量使用基本数据类型,避免装箱拆箱。
4)CPU核数
fork的产生数量是与可用CPU核数相关,可用的核数越多,获取的性能提升就会越大。
5)单元处理开销
花在流中每个元素的时间越长,并行操作带来的性能提升就会越明显。
收集Stream 结果:
Stream流提供collect方法:
<R,A> R collect(collector<? super T,A,R> collector)
参数:Collector
Collectors