Stream流式计算是一种基于数据流的计算模式,它可以对数据进行实时处理和分析,而不需要将所有数据存储在内存中。
Stream流式计算是将数据源中的数据分割成多个小的数据块,然后对每个小的数据块进行并行处理,最后将处理结果合并。这种方式可以大大提高程序的执行效率,因为每个小的数据块都可以在一个独立的线程中进行处理,而不需要等待整个数据集被处理完毕。
Stream流式计算的优点有很多,其中最重要的是它可以大大提高程序的执行效率。Stream采用了一种延迟计算的机制,只有在终止操作时才会触发计算,这种机制可以大大提高程序的执行效率,因为每个小的数据块都可以在一个独立的线程中进行处理,而不需要等待整个数据集被处理完毕。此外,Stream还提供了并行处理的支持,可以将数据分成多个块进行并行处理,从而充分利用多核处理器的性能优势,提高代码的执行速度。
"只有在终止操作时才会触发计算"的意思是,流并不会立即处理数据,而是当你进行终止操作(如收集结果到列表,或者输出到控制台等)时,才会开始进行计算。这种设计可以提高程序的效率,因为它避免了不必要的计算。
例如,在Java的Stream API中,你可以通过一些操作如filter, map, reduce等来转换和处理流中的数据,但这些操作并不会立即执行。只有当你调用一个终止操作如collect, forEach, toArray等时,流才会开始进行计算,并返回结果。
现在有一个问题:
给出用户类
package stream;
// 有参,无参构造,get/set/toString方法
public class User {
private int id;
private String name;
private int age;
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
// 有参,无参构造,get/set/toString方法过长就不给出了
}
问题类
package stream;
import java.util.Arrays;
import java.util.List;
/**
* 题目要求:一分钟内完成此题,只能用一行代码
* 现在有5个用户,筛选:
* 1、ID必须是偶数
* 2、年龄必须大于23岁
* 3、用户名转为大写字母
* 4、用户名字母倒着排序
* 5、只输出一个用户
*/
public class Test {
public static void main(String[] args) {
User u1 = new User(1,"a",21);
User u2 = new User(2,"b",22);
User u3 = new User(3,"c",23);
User u4 = new User(4,"d",24);
User u5 = new User(6,"e",25);
// --------------------- 答案 ---------------------
}
}
在揭晓答案之前,首先读者需要知道:
完成题目所给出的筛选要求其实并不难,难点在于限定要求,只能使用一行代码
因此,寻常的编程方法就已经不能完成题目要求了,我们需要引入新的编程方式:链式编程
链式编程是一种编程范式,特点是通过在每个方法调用后返回当前对象的引用,使得可以连续地调用多个方法。这种风格使得代码更加简洁、易读,并且可以减少中间变量的使用。
在许多编程语言中,我们可以使用点操作符(
.
)来实现链式编程。
Stream流式计算的思想式:数据+计算 分开,即,存储数据的操作应该与数据计算的操作分离,我们用List存储数据,用Stream流对数据进行计算
// 集合就是存储
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
// 计算交给Stream流
list.stream()
这样,我们将5个用户的数据存储起来,并交给Stream流进行计算
答案代码如下:
package stream;
import java.util.Arrays;
import java.util.List;
/**
* 题目要求:一分钟内完成此题,只能用一行代码
* 现在有5个用户,筛选:
* 1、ID必须是偶数
* 2、年龄必须大于23岁
* 3、用户名转为大写字母
* 4、用户名字母倒着排序
* 5、只输出一个用户
*/
public class Test {
public static void main(String[] args) {
User u1 = new User(1,"a",21);
User u2 = new User(2,"b",22);
User u3 = new User(3,"c",23);
User u4 = new User(4,"d",24);
User u5 = new User(6,"e",25);
// --------------------- 答案 ---------------------
// 集合就是存储
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
// 计算交给Stream流
// 将list转换为流,filter过滤,map进行数据转换,sort进行排序,limit进行分页,forEach
// 这一行代码,体现了Lambda表达式、链式编程、函数式接口、Stream流式计算,新时代程序员必须掌握的四大Java新特点!
list.stream().filter(u->{return u.getId()%2==0;}).filter(u->{return u.getAge()>23;}).map(u->{return u.getName().toUpperCase();}).sorted((uu1,uu2)->{return uu2.compareTo(uu1);}).limit(1).forEach(System.out::println);
}
}
上述看上去很长的代码,其实只是一行,因为使用了链式编程(我们又提到了链式编程),用(.)操作符将各项操作连起来。
同时,其中有很多陌生的方法与lambda表达式,这里就要联系上上一章节所讲的四大函数式接口了还记得上一章最后提到的吗,在新版本的框架底层中,函数式接口有大量的应用,因此我们查看源码,发现许多新框架下的方法的参数是函数式接口,因此函数式接口要一定要掌握!
以下是其中的方法的讲解:
forEach是一种循环结构,本质上也是一个函数式接口,可以使用lambda表达式简化,用于遍历数组或集合中的元素。它提供了一种简洁的方式来遍历数组或集合中的每一个元素,而不需要使用传统的for循环或者迭代器。
使用forEach可以简化代码,并且使代码更易读和易于维护。它可以自动地处理数组或集合的大小,无需手动控制循环的边界条件。此外,forEach还可以支持并行遍历,可以提高程序的性能。
在Stream中,filter是一种过滤器
Stream<T> filter(Predicate<? super T> predicate);
参数为 Predicate函数式接口,Predicate可以使用lambda表达式,因此可以在filter的参数出使用lambda表达式
在Stream中,map是将一个Stream类型的元素通过某种方式转换为另一个元素
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
参数为Function函数式接口
在Stream中,sorted方法可以对元素进行排序
sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
在Stream中,limit方法可以对输出元素进行分页,但因为在操作台上输出,因此分页也表示了在操作台上只展示多少个元素
limit(1)