Java从8开始,不但引入了Lambda表达式,还引入了一个全新的流式API:Stream API。
它位于java.util.stream包中。
划重点:这个Stream不同于java.io的InputStream和OutputStream,
它代表的是任意Java对象的序列。
两者对比如下:
| java.io | java.util.stream |
---|
存储 | 顺序读写的byte或cha | 顺序输出的任意Java对象实例 |
用途 | 序列化至文件或网络 | 内存计算/业务逻辑 |
再次划重点:这个Stream和List也不一样,
List存储的每个元素都是已经存储在内存中的某个Java对象,
而Stream输出的元素可能并没有预先存储在内存中,
而是实时计算出来的。
换句话说,List的用途是操作一组已存在的Java对象,
而Stream实现的是惰性计算,两者对比如下:
| java.util.List | java.util.stream |
---|
元素 | 已分配并存储在内存 | 可能未分配,实时计算 |
用途 | 操作一组已存在的Java对象 | 惰性计算 |
惰性计算的特点是:一个Stream转换为另一个Stream时,
实际上只存储了转换规则,并没有任何计算发生。
传统方法从集合中获取元素
多次对集合进行循环遍历
如果希望对集合中的元素进行筛选过滤:
1.将集合 A 中 根据条件一,过滤拿到子集合 B
2.在将子集合B 根据条件二,过滤筛选拿到子集合 C
使用 Stream 流 可以简化
public class TestStream{
psvm{
List<String> list = new ArrayList<String>();
list.add("abc123");
list.add("aaa22");
list.add("bcd125");
list.add("abcd120");
list.add("bbb230");
Stream<Stream> stream = list.stream();
Stream<String> stream2 stream.filter(str -> str.contains("1") );
Stream<String> stream3 = stream2.filter(str -> str.length() <= 6);
stream3.forEach(str -> sout(str));
list.streanm().filer(str -> str.contains("1")).filter(str -> str.length() <= 6).forEach(str -> sout(str));
}
}
两种获取流对象的方法
ArrayList<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5, 6);
流对象的操作
流模型的操作有很多,大致上分为 api 方法 分为两部分:
1.延迟方法,返回值类型都是 Stream 接口本身(并没有终止,可以继续操作),因此可以支持链式操作
2.终结方法,返回值就不是 stream 接口本身了,因此不能使用 链式操作
count 和 forEach
不是终结的,基本都是延迟方法
public class TestForEach{
psvm{
Stream<String> stream = Stream.of("abc","aaa","abd","bdc");
stream.forEach(str -> {
if(str.contains("a"){
sout(str);
}
})
}
}
过滤 : Filter
通过 filter 方法将一个流转换成另外一个子集 流
Stream<T> filter(Predicate<? super T> predicate)
返回由与此给定谓词匹配的此流的元素组成的流
// 借助于 predicate 函数式接口当中的抽象方法 test(T t) 对数据进行过滤