stream与InputStream和outputStream不同,是用于对集合迭代器的增强,使之能够完成更高效率的聚合操作(过滤,排序,统计分组),或者大批量的数据操作. 此外与stream与lambada表达式节后后编码效率大大提高,并且可读性更强
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
再学习stream之前,需要对Lambda表达式有一定的了解。
下面这个例子可以解释Stream可以做什么:
上面的例子中,获取一些带颜色塑料球作为数据源,首先过滤掉红色的、把它们融化成随机的三角形。再过滤器并删除小的三角形。最后计算出剩余图形的周长。
如上图,对于流的处理,主要有三种关键性操作:分别是流的创建、中间操作(intermediate operation)以及最终操作(terminal operation)。
用更简洁的话来说,就是将集合中的元素放在流水线上,并在每一步添加条件,筛选部分元素,最后留下的就是你想要的元素。
对于流的处理,主要有三种关键性操作:分别是流的创建、中间操作(intermediate operation)以及最终操作(terminal operation)。
流创建:就是stream()方法中间操作:筛选、排序这类操作最终操作:取出、打印这些操作下面会对这三类操作做具体的介绍
将Collection切换为管道源很简单,调用stream
heros.stream();但是数组没有stream方法,需要使用
Arrays.stream(hs);或者
Stream.of(hs);这里不要和I/O操作中的InputStream、OutputStream搞混了,两个不是同一个概念。
每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒”操作,并不会真正进行遍历。 中间操作比较多,主要分两类 对元素进行筛选 和 转换为其他形式的流
对元素进行筛选:
filter 匹配 distinct 去除重复(根据equals判断) //注意:Object里的equals判断的是不是同一个对象,下面是Object中equals()的源码:
public boolean equals(Object obj) { return this == obj; }但是String中的equals判断的是字符串内容是否一样(当然如果是同一个字符串对象的话,返回的也是true)
sorted 自然排序 sorted(Comparator) 指定排序 limit 保留 skip 忽略
转换为其他形式的流:
mapToDouble 转换为double的流 类似的还有mapToInt(),mapToLong()
map 转换为任意类型的流
package lambda; import java.util.ArrayList; import java.util.List; import java.util.Random; import charactor.Hero; public class TestAggregate { public static void main(String[] args) { Random r = new Random(); List<Hero> heros = new ArrayList<Hero>(); for (int i = 0; i < 5; i++) { heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100))); } //制造一个重复数据 heros.add(heros.get(0)); System.out.println("初始化集合后的数据 (最后一个数据重复):"); System.out.println(heros); System.out.println("满足条件hp>100&&damage<50的数据"); heros .stream() .filter(h->h.hp>100&&h.damage<50) .forEach(h->System.out.print(h)); System.out.println("去除重复的数据,去除标准是看equals"); heros .stream() .distinct() .forEach(h->System.out.print(h)); System.out.println("按照血量排序"); heros .stream() .sorted((h1,h2)->h1.hp>=h2.hp?1:-1) .forEach(h->System.out.print(h)); System.out.println("保留3个"); heros .stream() .limit(3) .forEach(h->System.out.print(h)); System.out.println("忽略前3个"); heros .stream() .skip(3) .forEach(h->System.out.print(h)); System.out.println("转换为double的Stream"); heros .stream() //这里虽然获取的是血量 //但是操作的还是对象 .mapToDouble(Hero::getHp) .forEach(h->System.out.println(h)); System.out.println("转换任意类型的Stream"); heros .stream() .map((h)-> h.name + " - " + h.hp + " - " + h.damage) .forEach(h->System.out.println(h)); } }再看一个实例
List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis"); Stream s = strings.stream() .filter(string -> string.length()<= 6) .map(String::length) .sorted() .limit(3) .distinct();下图是Stream对象的变化过程
Stream的中间操作得到的结果还是一个Stream,那么如何把一个Stream转换成我们需要的类型呢?比如计算出流中元素的个数、将流装换成集合等。这就需要最终操作(terminal operation)
最终操作会消耗流,产生一个最终结果。也就是说,在最终操作之后,不能再次使用流,也不能在使用任何中间操作,否则将抛出异常。 常见的结束操作如下:
forEach() 遍历每个元素 collect() toArray() 转换为数组 min(Comparator) 取最小的元素 max(Comparator) 取最大的元素 count() 用来统计流中的元素个数 findFirst() 第一个元素
下面是一个使用collect的例子
List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis","Hollis666", "Hello", "HelloWorld", "Hollis"); strings = strings .stream() .filter(string -> string.startsWith("Hollis")) .collect(Collectors.toList()); //找出以“Hollis”开头的元素 System.out.println(strings); //Hollis, HollisChuang, Hollis666, HollisJava中的Stream就像数据库的查询功能,能够帮助我们写出更加高效的代码