文:恕我直言,我怀疑你没怎么用过Stream流
注:中国传统文化,先仔细看,若有用,再点赞, 给自己一点思考的时间
注:微信搜索:CodeCow,关注这个非常 SAO 的程序员
我们是否一样 ?
想当年,小编在自学Java语言看书时,关于 “Stream流” 这一块的知识点可能都有点 “轻敌” ,觉得这块内容 “ so easy ”非常简单,一眼而过。
殊不知,捡了芝麻,丢了西瓜;并且在小编代码中,也从未有过“Stream流” 地位可言;却浑然不知,java8的一哥“Stream流”,在旁暗自嘲讽 “ 这TM是谁,太菜了 ” 。
就拿小编上篇文章《两年了,才知道如何实现多线程,哎 》来讲,也是一堆连环 for 循环的SAO操作,何曾想过Stream流的感受
java 8 一哥 ?
在Java 8中,得益于 Lambda 所带 来的 函数式编程,应运而生了一个全新的概念——Stream流,用于解决已有集合类库既有的弊端。
首先
关于Stream流上的操作,大体可以分为两种:
- 中间操作(Intermediate),其返回结果都是Stream,故可以多个中间操作叠加;
- 终止操作(Terminal),其返回结果是我们最终需要的数据,故只能有一个终止操作
其次
Stream流是一个来自数据源的元素队列,例如
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组 等。
再者
Stream流和以前的 Collection操作不同, Stream操作还有两个基础的特征:
- Pipelining:中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness) 和 短路( short-circuiting)。
- 内部迭代: 以前对集合遍历都是通过Iterator或者增强for的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式,流可以直接调用遍历方法。
最后
喽一眼Stream流的接口继承关系
[图片上传失败...(image-b7eb65-1596705940785)]
所以,当我们使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)→ 数据转换→执行操作获取想要的结果
但,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以 像链条一样排列,变成一个管道。
注意:“Stream流”其实是一个集合元素的函数模型,它并不是集合,也不是数据结构,其本身并不存储任何 元素(或其地址值)。
因此,Stream流的一哥地位,并非空穴来风
接下来,硬核SAO操作,别眨眼
[图片上传失败...(image-a750dd-1596705940785)]
为什么需要Stream流
常用的for循环它不香吗?为啥非得用Stream流?
举个简单的例子:
学生对象:
@Data
@AllArgsConstructor
public class Student {
@ApiModelProperty(value = "姓名")
private String name;
@ApiModelProperty(value = "年龄")
private Integer age;
@ApiModelProperty(value = "性别(1-男,2-女)")
private Integer sex;
}
学生对象集合
public class StreamDemo {
public static void main(String[] args) {
// 测试数据
List<Student> studentList = Lists.newArrayList();
studentList.add(new Student("CodeCow", 18, 1));
studentList.add(new Student("小明", 30, 1));
studentList.add(new Student("小猪", 40, 2));
studentList.add(new Student("小狗狗", 50, 2));
}
}
假如,现有需求:筛选所有姓小的同学,并且名字有三个字,最后对结果进行打印输出
小编很幸运,曾见过这样的SAO代码,可谓 “猛龙过江”,管你三七二十一,上来先整几个for循环再说;
public static void main(String[] args) {
//第一步:找出姓小的同学,放在list1
List<Student> list1 = Lists.newArrayList();
for (Student student : studentList) {
if (student.getName().startsWith("小")) {
list1.add(student);
}
}
//第二步:找出名字有三个字的同学,放在list2
List<Student> list2 = Lists.newArrayList();
for (Student student : list1) {
if (student.getName().length() == 3) {
list2.add(student);
}
}
//第三步:打印结果
for (Student student : list2) {
System.out.println(student);
}
}
接下来,我们Debug运行下,看下结果:
Student(name=小狗狗, age=50, sex=2)
卧CAO,学生倒是赛选出来了,但是,现在赛选 条件只有三个,当条件有几十个时,那几十个for循环,不累吗,那可以说是非常酸爽了……
再者,你将Java 8 的一哥——stream流,至于何地
[图片上传失败...(image-f0a1c5-1596705940785)]
体验哈Stream流的更优写法
大家肯定都知道Lambda吧,Java 8的Lambda让我们可以更加专注于做什么(What),而不是怎么做(How)
这点小编也在上篇文章《两年了,才知道如何实现多线程,哎 》中结合“线程 + 匿名内部类” 进行了对比说明。有空可以看下
现在,我们体会下Stream流的优雅:
public static void main(String[] args) {
studentList.stream()
.filter(i -> i.getName().startsWith("小"))//过滤出姓小的同学
.filter(i -> i.getName().length() == 3) //过滤出名字有三个字的同学
.forEach(System.out::println); //打印结果
}
再次Debug运行下,看下结果:
Student(name=小狗狗, age=50, sex=2)
不难发现,区区3行代码,运行结果也一样;同时,顺带解决了上面的SAO操作, 他不香吗?
总结下,为什么很香
- 第一点:可以清楚地知道我们要对一个数据集做何种操作,可读性贼强(就三行,读不明白 ?)
- 第二点:可以很轻松地获取并行化Stream流,不用自己编写多线程代码(阿牛上篇文章就是最好的证明!!)
- 第三点:可以让我们更加专注于业务逻辑 (还用考虑用几个for循环吗!!)。
简而言之,Stream,爱了,爱了
您也为这就是Stream流的全部吗,“No,No,No”
接下来,咋们看下Stream流 风SAO 集合
了解下Stream流更多SAO操作
需求1:获取姓小同学的集合
public static void main(String[] args) {
List<Student> list = studentList.stream()
.filter(i -> i.getName().startsWith("小"))
.collect(Collectors.toList());
}
结果为:
[
Student(name=小明, age=30, sex=1),
Student(name=小猪, age=40, sex=2),
Student(name=小狗狗, age=50, sex=2)
]
需求2:获取姓小的同学,并且年龄大于30的集合
public static void main(String[] args) {
List<Student> list = studentList.stream()
.filter(i -> i.getName().startsWith("小") && i.getAge() >30)
.collect(Collectors.toList());
}
结果为:
[
Student(name=小猪, age=40, sex=2),
Student(name=小狗狗, age=50, sex=2)
]
需求3:获取姓名为“小明”的同学,的集合
public static void main(String[] args) {
List<Student> list = studentList.stream()
.filter(i -> i.getName().equals("小明"))
.collect(Collectors.toList());
}
结果为:
[Student(name=小明, age=40, sex=1)]
需求4:获取所有同学姓名的集合
public static void main(String[] args) {
List<String> list = studentList.stream()
.map(Student::getName)
.collect(Collectors.toList());
}
结果为:
[CodeCow, 小明, 小猪, 小狗狗]
需求5:根据学生年龄进行升序排序
public static void main(String[] args) {
List<Student> list = studentList.stream()
.sorted(Comparator.comparing(Student::getAge))
.collect(Collectors.toList());
}
结果为:
[
Student(name=CodeCow, age=18, sex=1),
Student(name=小明, age=40, sex=1),
Student(name=小猪, age=50, sex=2),
Student(name=小狗狗, age=50, sex=2)
]
需求6:根据学生年龄进行降序排序
public static void main(String[] args) {
List<Student> list = studentList.stream()
.sorted(Comparator.comparing(Student::getAge).reversed())
.collect(Collectors.toList());
}
结果为:
[
Student(name=小猪, age=50, sex=2),
Student(name=小狗狗, age=50, sex=2),
Student(name=小明, age=40, sex=1),
Student(name=CodeCow, age=18, sex=1)
]
需求7:distinct 去重
public static void main(String[] args) {
List<Integer> integers = Lists.list(30, 40, 10, 20, 20, 10, 50, 20);
List<Integer> collect =
integers.stream().distinct().collect(Collectors.toList());
System.out.println(collect);//[30, 40, 10, 20, 50] 去重结果
}
需求8:找最小值 min,总数量 count
public static void main(String[] args) {
List<Integer> integers = Lists.list(30, 40, 10, 20, 20, 10, 50, 20);
Integer integer1 = integers.stream().min(Integer::compareTo).orElse(-1);
System.out.println(integer1); //10 最小值
long count = integers.stream().count();
System.out.println(count);//8 总数量
}
浅聊 Java 8 Stream 流,今就到这,下文见 _
后记
好啦,今就先聊到这里吧,本文仅仅是 抛砖引玉 而已,使用了 Java 8 Stream流 和大家聊了聊,打了个样;且并非Stream流所有特性,这只是其 冰山一角;下文见
★★ 好文推荐 ★★
- 两年了,才知道如何实现多线程 ,哎
- 答应我,别再if/else校验请求参数了可以吗
- 浅聊过滤器 + 拦截器 + JWT
- 微信小程序支付 + 公众号支付 (含源码)
- 微信公众号授权+获取用户信息+jwt登录 (含源码)
- 微信小程序授权+获取用户手机号+jwt登录 (含源码)
小声BB
- 中国传统文化,先仔细看,若有用,再点赞, 给自己一点思考的时间
- 更多幽默、风趣好文,尽在“ CodeCow ” , WX搜索 CodeCow,可以看看
《 Java如海,学习作舟,泛舟于海,方知Java之宽阔 》