Java8中有两个非常有名的改进,一个是Lambda表达式,一个是Stream。而新增了stream流的特性,能够让用户以函数式的方式、更为简单的操纵集合等数据结构,并实现了用户无感知的并行计算。
Stream介绍
Stream是一个流,在Java.util.Stream包路径下,他的主要作用就是对集合数据进行查找过滤等操作。通俗解释就是一种高效且易用的数据处理方式。大数据领域也有一个Steam实时流计算框架,不过和这个可不一样。别搞混了。
Stream和Collection的区别就是:Collection只是负责存储数据,不对数据做其他处理,主要是和内存打交道。但是Stream主要是负责计算数据的,主要是和CPU打交道。
stream优点:
举个例子: 有一个List列表,我们需要获得年龄为70岁的前10个Person的姓名。
过程式的解决方案:
稍加思考,我们很快就写出了一个过程式的解决方案(伪代码):
List<Person> personList = fromDB(); // 获得List<Person>
int limit = 10; // 限制条件
List<String> nameList = new ArrayList(); // 收集的姓名集合
for(Person personItem : personList){
if(personItem.age == 70){ // 满足条件
nameList.add(personItem.name); // 加入姓名集合
if(nameList.size() >= 10){ // 判断是否超过限制
break;
}
}
}
return nameList;
函数式stream解决方案:
下面我们给出一种基于stream流的解决方案(伪代码):
List<Person> personList = fromDB(); // 获得List<Person>
List<String> nameList = personList.stream()
.filter(item->item.age == 70) // 过滤条件
.limit(10) // limit限制条件
.map(item->item.name) // 获得姓名
.collect(Collector.toList()); // 转化为list
return nameList;
两种方案的不同之处:
从函数式的角度上看,过程式的代码实现将收集元素、循环迭代、各种逻辑判断耦合在一起,暴露了太多细节。当未来需求变动和变得更加复杂的情况下,过程式的代码将变得难以理解和维护(需要控制台打印出 年龄为70岁的前10个Person中,姓王的Person的名称)。
函数式的解决方案解开了代码细节和业务逻辑的耦合,类似于sql语句,表达的是"要做什么"而不是"如何去做",使程序员可以更加专注于业务逻辑,写出易于理解和维护的代码。
Stream 特性:
无存储。Stream 不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java 容器或 I/O channel 等。
为函数式编程而生。对 Stream 的任何修改都不会修改背后的数据源,比如对 Stream 执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新 Stream。
惰式执行。Stream 上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
可消费性。Stream 只能被 " 消费 " 一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。
Stream操作步骤
Stream执行流程很简单,主要有三个:
1、创建一个Stream:从一个数据源,如集合、数组中获取流
2、使用Stream操作数据:一个操作的中间链,对数据源的数据进行操作
3、终止Stream:一个终止操作,执行中间操作链,并产生结果
要注意的是,对流的操作完成后需要进行关闭操作
创建Stream
public static void test1() {
List <Student> students =StudentData.getStudents();
//第一种:返回一个顺序流
Stream <Student> stream = students.stream();
//第二种:返回一个并行流
Stream <Student> stream1 = students.parallelStream();
}
//通过一个数组创建stream
public static void test2() {
//获取一个整形stream
int[]arr = {1, 34, 2, 54, 56, 34};
IntStream stream = Arrays.stream(arr);
}
//通过Stream.of
public static void test3() {
Stream <String> stringStream = Stream.of("1", "4", "34", "23");
Stream <Student> studentStream = Stream.of(
new Student(1, "小白", 23, 89.5),
newStudent(2, "小蔡", 22, 90.9)
);
}
//创建无限流
public static void test4() {
//每隔5个数取一个,从0开始,此时就会无限循环
Stream<Integer> iterate = Stream.iterate(0,t -> t + 5);
//取出一个随机数
Stream<Double> generate = Stream.generate(Math::random);
}