您的位置:首页 > 编程语言 > Java开发

[疯狂Java]集合:专门用于聚集操作的一次性集合——Stream(流)

2016-05-24 11:16 155 查看
1. Java 8新增的Stream特殊集合:

1) Stream,即流,和之前讲过的I/O流并非一种流,是一种特殊的有序、可重复集合,可以往流中放很多元素;

!!它不属于Collection、Map体系,但是Collection可以转化成Stream;

2) 它的特殊之处在于,流专门用于对集合中的元素进行聚集操作(聚集操作泛义上将就是诸如统计操作之类的操作,比如求平均值、最大值/最小值等操作);

3) 因为流这种结构进行聚集操作有独特的优势,其中最大的优势就是速度快!

4) 速度快也是用一定的代价换来的——寿命短,通常都是一次性的:比如一个已经放入元素的流,进行完一次球平均值或者找最大最小值的操作之后,流就被消耗掉了,就不能再使用了,要想在统计另外一个值就需要重新创建流、重新往流中放入元素,然后重新统计;

!!因此,Stream的运用场合通常是那种临时性、一次性的统计,不会频繁发生的那种统计,在实际应用中,这种情况经常发生,因此Java 8专门推出了Stream;

2. Stream简介:

1) Java 8的Stream有多种版本,其中最基础的根类就是Stream,其中可以存放任何类型的数据(模板类),但不过Java为了方便也实现了各种TypeStream,其中Type支持int、long、double等基本数据类型;

2) 构造Stream对象:

i. Java采用生产线模式设计Stream类,即必须先获取一个Stream对象的生产者,然后用这个生产者来生产Stream对象;

ii. 所有的Stream类都有一个静态工具方法builder,可以获得一个相应Stream类的生产者:static<T> Stream.Builder<T> builder();

iii. 生产者Builder有两个方法,一个是add,一个是build,先用add往"流"(此时的流只是一个半成品)中加入一个个元素,加完之后调用build方法完成“产品”返回最终成型的Stream流对象:

a. default Stream.Builder.Builder<T> add(T t); // 其返回的还是Builder本身,因此可以连续add了,例如builder.add(1).add(2).add(3)....

b. Stream<T> build(); // 最终生产出成型的Stream对象,连起来就可以这样子Stream s = builder.add(1).add(2).add(3).build();

iv. Collection接口提供了一个stream方法,可以用集合中的元素构造一个临时的Stream对象,因此这样也可以直接构造出一个流:default Stream Collection.stream();

3) 构造完Stream对象后就可以调用其各种聚集方法进行统计了;

3. Stream聚集操作:

1) 聚集操作有两类,一类是中间方法,另一类是末端方法:

i. 中间方法:进行一定的操作得到(返回)一个新的流(比如每个元素+1得到一个新的流),而这个新的流还可以继续进行其他聚集操作(没有被消耗);

ii. 末端方法:通常都是会计算出一个统计值的方法(比如求平均值、统计总共有多少个元素、求最大/最小值等),这些方法会消耗流,消耗完后流就不能再使用了,想要统计其它东西就必须要重新构造流了!!

2) 典型的中间方法:

i. Stream filter(Predicate predicate); // 滤掉流中“不”满足谓词条件的,即只保留满足谓词条件的元素,返回这个新的流

ii. TypeStream mapToType(ToTypeFunction mapper); // 将流转换成一种基本类型的流,其中type支持int、long、double这三种

!ToTypeFunction是一个函数式接口,用来定义每个元素如何转换成新流中的元素:

public interface ToLongFunction<T> {
type applyAsType(T value);
}
!!value必定是流中的迭代元素了;

!!示例:Stream s = ....; IntStream is = s.mapToIntStream(ele -> (String)ele.length()); // 将每个元素替换成其长度形成一个新的流

iii. Stream peek(Consumer action); // 观察流的内容,返回原来的流保持不变,action用来观察流中的每个元素,该方法主要用来调试,并不产生实际作用(比如输出流中的每个值)

iv. Stream distinct(); // 去重后得到一个新的流,去重使用equals方法做相等比较,该方法不要求先对流进行排序,可以直接乱序去重(而且其算法也不是先对流进行排序的),因此非常牛逼!

v. Stream sorted(); // 排序(默认从小到大)得到一个新的流

vi. Stream limit(long maxSize); // 规定最多允许访问多少个元素,比如一个流长度为5,而现在你limit(3),那么count计算数量时返回的就是3,即规定了操作的范围

3) 典型的末端方法:末端方法会消耗完整个流,调用完之后流宣布死亡,需要统计其它信息就得重新创建流了

i. void forEach(Consumer action); // 遍历

ii. Object[] toArray(); // 转换成相应的数组,如果是TypeStream那返回的就是Type[]了!

常规的统计方法:

i. find最小/最大值:

a. Stream版的:Optional Stream.min | max(Comparator comparator); // Optional<T>代表任意类型,任意类型比较大小必须要规定比较接口Comparator

b. TypeStream版的:type TypeStream.min | max(); // 简单很多

ii. 统计元素个数:long count();

iii. 检查是否包含符合谓词条件的元素:

a. boolean anyMatch(Predicate predicate); // 是否存在一个满足谓词条件的元素

b. boolean allMatch(Predicate predicate); // 是否全部元素都满足谓词条件

c. boolean noneMatch(Predicate predicate); // 是否全都不满足谓词条件

iv. 获取第一个元素:Optional findFirst();

4. 示例:

public class Test {
public static void main(String[] args) {

IntStream is = IntStream.builder().add(50).add(30).add(60).add(30).add(70).add(70).add(10).build();
is.filter(ele -> ele > 10).distinct().sorted().forEach(System.out::println);
}
}
!!Lambda表达式打印一个元素可以直接System.out::println,表示打印那个ele迭代元素,最最变态的简洁!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: