【Java8新特性】Stream API有哪些中间操作?看完你也可以吊打面试官!!
写在前面
在上一篇《【Java8新特性】面试官问我:Java8中创建Stream流有哪几种方式?》中,一名读者去面试被面试官暴虐!归根结底,那哥儿们还是对Java8的新特性不是很了解呀!那么,我们继续讲述Java8的新特性,旨在最终可以让每位读者在跳槽面试的过程中吊打面试官!!
Stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值” 。 Stream的中间操作是不会有任何结果数据输出的。
Stream的中间操作在整体上可以分为:筛选与切片、映射、排序。接下来,我们就分别对这些中间操作进行简要的说明。
筛选与切片
这里,我将与筛选和切片有关的操作整理成如下表格。
方法 | 描述 |
---|---|
filter(Predicate p) | 接收Lambda表达式,从流中排除某些元素 |
distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素 不足 n 个,则返回一个空流。与 limit(n) 互补 |
接下来,我们列举几个简单的示例,以便加深理解。
为了更好的测试程序,我先构造了一个对象数组,如下所示。
protected List<Employee> list = Arrays.asList(
new Employee("张三", 18, 9999.99),
new Employee("李四", 38, 5555.55),
new Employee("王五", 60, 6666.66),
new Employee("赵六", 8, 7777.77),
new Employee("田七", 58, 3333.33)
);
其中,Employee类的定义如下所示。
@Data
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Employee implements Serializable {
private static final long serialVersionUID = -9079722457749166858L;
private String name;
private Integer age;
private Double salary;
}
Employee类的定义比较简单,这里,我就不赘述了。之后的示例中,我们都是使用的Employee对象的集合进行操作。好了,我们开始具体的操作案例。
1.filter()方法
filter()方法主要是用于接收Lambda表达式,从流中排除某些元素,其在Stream接口中的源码如下所示。
Stream<T> filter(Predicate<? super T> predicate);
可以看到,在filter()方法中,需要传递Predicate接口的对象,Predicate接口又是个什么鬼呢?点进去看下源码。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
可以看到,Predicate是一个函数式接口,其中接口中定义的主要方法为test()方法,test()方法会接收一个泛型对象t,返回一个boolean类型的数据。
看到这里,相信大家明白了:filter()方法是根据Predicate接口的test()方法的返回结果来过滤数据的,如果test()方法的返回结果为true,符合规则;如果test()方法的返回结果为false,则不符合规则。
这里,我们可以使用下面的示例来简单的说明filter()方法的使用方式。
//内部迭代:在此过程中没有进行过迭代,由Stream api进行迭代
//中间操作:不会执行任何操作
Stream<Person> stream = list.stream().filter((e) -> {
System.out.println("Stream API 中间操作");
return e.getAge() > 30;
});
我们,在执行终止语句之后,一边迭代,一边打印,而我们并没有去迭代上面集合,其实这是内部迭代,由Stream API 完成。
下面我们来看看外部迭代,也就是我们人为得迭代。
//外部迭代
Iterator<Person> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
2.limit()方法
主要作用为:截断流,使其元素不超过给定数量。
先来看limit方法的定义,如下所示。
Stream<T> limit(long maxSize);
limit()方法在Stream接口中的定义比较简单,只需要传入一个long类型的数字即可。
我们可以按照如下所示的代码来使用limit()方法。
//过滤之后取2个值
list.stream().filter((e) -> e.getAge() >30 ).limit(2).forEach(System.out :: println);
在这里,我们可以配合其他得中间操作,并截断流,使我们可以取得相应个数得元素。而且在上面计算中,只要发现有2条符合条件得元素,则不会继续往下迭代数据,可以提高效率。
3.skip()方法
跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素 不足 n 个,则返回一个空流。与 limit(n) 互补。
源码定义如下所示。
Stream<T> skip(long n);
源码定义比较简单,同样只需要传入一个long类型的数字即可。其含义是跳过n个元素。
简单示例如下所示。
//跳过前2个值
list.stream().skip(2).forEach(System.out :: println);
4.distinct()方法
筛选,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素。
源码定义如下所示。
Stream<T> distinct();
旨在对流中的元素进行去重。
我们可以如下面的方式来使用disinct()方法。
list.stream().distinct().forEach(System.out :: println);
这里有一个需要注意的地方:distinct 需要实体中重写hashCode()和 equals()方法才可以使用。
映射
关于映射相关的方法如下表所示。
方法 | 描述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流 |
1.map()方法
接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。
先来看Java8中Stream接口对于map()方法的声明,如下所示。
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
我们可以按照如下方式使用map()方法。
//将流中每一个元素都映射到map的函数中,每个元素执行这个函数,再返回
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
list.stream().map((e) -> e.toUpperCase()).forEach(System.out::printf);
//获取Person中的每一个人得名字name,再返回一个集合
List<String> names = this.list.stream().map(Person :: getName).collect(Collectors.toList());
2.flatMap()
接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流。
先来看Java8中Stream接口对于flatMap()方法的声明,如下所示。
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
我们可以使用如下方式使用flatMap()方法,为了便于大家理解,这里,我就贴出了测试flatMap()方法的所有代码。
/**
* flatMap —— 接收一个函数作为参数,将流中的每个值都换成一个流,然后把所有流连接成一个流
*/
@Test
public void testFlatMap () {
StreamAPI_Test s = new StreamAPI_Test();
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
list.stream().flatMap((e) -> s.filterCharacter(e)).forEach(System.out::println);
//如果使用map则需要这样写
list.stream().map((e) -> s.filterCharacter(e)).forEach((e) -> {
e.forEach(System.out::println);
});
}
/**
* 将一个字符串转换为流
*/
public Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
其实map方法就相当于Collaction的add方法,如果add的是个集合得话就会变成二维数组,而flatMap 的话就相当于Collaction的addAll方法,参数如果是集合得话,只是将2个集合合并,而不是变成二维数组。
排序
关于排序相关的方法如下表所示。
方法 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
从上述表格可以看出:sorted有两种方法,一种是不传任何参数,叫自然排序,还有一种需要传Comparator 接口参数,叫做定制排序。
先来看Java8中Stream接口对于sorted()方法的声明,如下所示。
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
sorted()方法的定义比较简单,我就不再赘述了。
我们也可以按照如下方式来使用Stream的sorted()方法。
// 自然排序
List<Employee> persons = list.stream().sorted().collect(Collectors.toList());
//定制排序
List<Employee> persons1 = list.stream().sorted((e1, e2) -> {
if (e1.getAge() == e2.getAge()) {
return 0;
} else if (e1.getAge() > e2.getAge()) {
return 1;
} else {
return -1;
}
}).collect(Collectors.toList());
写在最后
如果觉得文章对你有点帮助,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习Java8新特性。
最后,附上Java8新特性核心知识图,祝大家在学习Java8新特性时少走弯路。
【Java8新特性】Stream API有哪些中间操作?看完你也可以吊打面试官!!的更多相关文章
- Java8 新特性 Stream() API
新特性里面为什么要加入流Steam() 集合是Java中使用最多的API,几乎每一个Java程序都会制造和处理集合.集合对于很多程序都是必须的,但是如果一个集合进行,分组,排序,筛选,过滤...这些操 ...
- java8新特性——Stream API
Java8中有两大最为重要得改变,其一时Lambda表达式,另外就是 Stream API了.在前面几篇中简单学习了Lambda表达式得语法,以及函数式接口.本文就来简单学习一下Stream API( ...
- Java8新特性 - Stream API
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找.过滤和映射数据等操作.使用Stream API对集合进行操作,就类似与使用SQL执行的数据库 ...
- Java8 新特性 Stream Api 之集合遍历
前言 随着java版本的不断更新迭代,java开发也可以变得甜甜的,最新版本都到java11了,但是后面版本也是不在提供商用支持,需要收费,但是java8 依然是持续免费更新使用的,后面版本也更新很快 ...
- 【Java8新特性】面试官:谈谈Java8中的Stream API有哪些终止操作?
写在前面 如果你出去面试,面试官问了你关于Java8 Stream API的一些问题,比如:Java8中创建Stream流有哪几种方式?(可以参见:<[Java8新特性]面试官问我:Java8中 ...
- Java8 新特性 Stream 非短路终端操作
非短路终端操作 Java8 新特性 Stream 练习实例 非短路终端操作,就是所有的元素都遍厉完,直到最后才结束.用来收集成自己想要的数据. 方法有: 遍厉 forEach 归约 reduce 最大 ...
- JDK1.8新特性——Stream API
JDK1.8新特性——Stream API 摘要:本文主要学习了JDK1.8的新特性中有关Stream API的使用. 部分内容来自以下博客: https://blog.csdn.net/icarus ...
- Java8 新特性 Stream 短路终端操作
短路终端操作 Java8 新特性 Stream 练习实例 传入一个谓词,返回传为boolean,如果符合条件,则直接结束流. 匹配所有 allMatch 任意匹配 anymMatch 不匹配 none ...
- Java8 新特性 Stream 无状态中间操作
无状态中间操作 Java8 新特性 Stream 练习实例 中间无状态操作,可以在单个对单个的数据进行处理.比如:filter(过滤)一个元素的时候,也可以判断,比如map(映射)... 过滤 fil ...
随机推荐
- GPTL—练习集—006树的遍历
#include<bits/stdc++.h> using namespace std; typedef int daTp;//datatype typedef struct BTNode ...
- Hadoop学习笔记(一)——安装与配置
操作系统:Ubuntu 15.04; Hadoop version: 2.6.4 参考文献: Ubuntu上搭建Hadoop环境(单机模式+伪分布模式)
- Semaphores
信号量和P,V原语的使用可归纳为三种情形: 把信号量视为加锁标志位,其目的是为了实现对某个唯一的共享数据的互斥访问,如各个进程间的某共享变量,数据库中的某个记录. 共享数据的值与信号量本身的值没有直接 ...
- 小老板,我300M的网,网速很慢怎么办?
首先考虑是不是DNS的问题: 我们先测试一下! 一.Google的DNS: 8.8.8.8 丢包严重 PASS但是扶墙的时候是必备的,如果有扶墙的需求的话可以备用. 二.百度DNS 180.76.76 ...
- P4720【模板】扩展卢卡斯,P2183 礼物
扩展卢卡斯定理 最近光做模板了 想了解卢卡斯定理的去这里,那题也有我的题解 然而这题和卢卡斯定理并没有太大关系(雾 但是,首先要会的是中国剩余定理和exgcd 卢卡斯定理用于求\(n,m\)大,但模数 ...
- Jenkins 介绍
持续集成: 持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成.每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证 ...
- TCP 可靠传输
TCP报文段首部 序号: TCP是面向字节流的.在一个TCP连接中传送的字节流中的每一个字节都按顺序编号.整个要传送的字节流的起始序号必须在连接建立时设置.首部中的序号字段值则指的是本报文段所发送的数 ...
- Python基础02 变量
Python中的变量有两个特点: 1. 无需声明 a = 1 2. 不与类型绑定 a = 1 a = 'hello world' 变量名只是内存中具体对象的一个引用(reference). 对于 a ...
- 高精度封装Bignum
还没有写完,目前只实现了加,乘,且不能作用于负数 \(update\ in 20.4.8 添加了高精除低精ddiv函数,比较大小comp函数\) #include <bits/stdc++.h& ...
- 2020 wannafly camp 补题 day1
题目可以从牛客上找到. 最简单的一个题应该是B B. 密码学 这个应该就是倒着推,题目给了你加密的顺序,所以我们逆推这个就可以得到每一次加密前的字符串. 1H. 最大公约数 题目大意就是给你一个范围1 ...