?查看之前的博客可以点击顶部的【分类专栏】
什么是 Stream?
Stream 是 JDK1.8 中处理集合的关键抽象概念。Lambda 和 Stream 是 JDK1.8 新增的函数式编程最优亮点的特性。它可以对集合进行查找、过滤、排序和映射数据等操作。类似于使用 SQL 执行数据库查询语句一样。Stream API 可以让程序员写出高效率、干净、简洁的代码。
说明:使用终止操作的关键字,是不允许再使用中间操作的关键字了。也就是说,如果使用了 forEach、collect、min、max等终止操作,则不能在后面使用 filter 等中间操作了。
?Stream 流有串行流 stream() 和并行流 parallelStream() 之分。并行流表示多线程的,效率高一点。
使用 Stream 流将List 转成 Set 集合
public class Test2 {
public static void main(String[] args) {
List<UserInfo> list = new ArrayList<>();
list.add(new UserInfo("张三",13));
list.add(new UserInfo("李四",14));
list.add(new UserInfo("王五",15));
list.add(new UserInfo("朱六",16));
list.add(new UserInfo("朱六",16));
//并行流,效率高一点
//list.parallelStream();
//创建一个串行流
Stream<UserInfo> stream = list.stream();
//转换成 Set 集合
Set<UserInfo> set = stream.collect(Collectors.toSet());
set.forEach(p ->{
System.out.println(p.toString());
});
}
static class UserInfo {
private String userName;
private Integer age;
public UserInfo(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
}
我们现在把 List 转成 Set 集合,在JDK1.8 之前,我们需要 for 循环,然后一个个的放入 Set 集合里。现在不需要了。直接以下使用方法即可:
Stream<UserInfo> stream = list.stream();
Set<UserInfo> set = stream.collect(Collectors.toSet());
set.forEach(p ->{
System.out.println(p.toString());
});
输出(注意两个朱六,因为是使用 new 的方式创建,它们的地址引用是不同的,因此是2个对象,hashCode 不一样):
UserInfo{userName='李四', age=14} UserInfo{userName='王五', age=15} UserInfo{userName='朱六', age=16} UserInfo{userName='张三', age=13} UserInfo{userName='朱六', age=16}
我们重写? UserInfo 实体的 equals 和 hashCode 方法:(IDEA 下按 Alt+INSERT,调出快捷键)
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserInfo userInfo = (UserInfo) o;
return Objects.equals(userName, userInfo.userName) &&
Objects.equals(age, userInfo.age);
}
@Override
public int hashCode() {
return Objects.hash(userName, age);
}
然后重新运行,输出:
UserInfo{userName='朱六', age=16} UserInfo{userName='张三', age=13} UserInfo{userName='李四', age=14} UserInfo{userName='王五', age=15}
使用 Stream 流将 List 集合转换成 Map
public class Test3 {
public static void main(String[] args) {
List<UserInfo> list = new ArrayList<>();
list.add(new UserInfo("张三", 13));
list.add(new UserInfo("李四", 14));
list.add(new UserInfo("王五", 15));
list.add(new UserInfo("朱六", 16));
//创建 Stream 流
Stream<UserInfo> stream = list.stream();
//转成 Map 集合,其中 key 为用户名,value 为实体
Map<String, UserInfo> map = stream.collect(Collectors.toMap(info -> info.getUserName(), info -> info));
map.forEach((BiConsumer) (p1, p2) -> {
System.out.println("key=" + p1 + ",value=" + p2);
});
}
static class UserInfo {
private String userName;
private Integer age;
public UserInfo(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
public String getUserName() {
return userName;
}
}
}
输出:
key=朱六,value=UserInfo{userName='朱六', age=16} key=李四,value=UserInfo{userName='李四', age=14} key=张三,value=UserInfo{userName='张三', age=13} key=王五,value=UserInfo{userName='王五', age=15}
使用 Stream 流查询最大、最小的元素
public class Test4 {
public static void main(String[] args) {
List<UserInfo> list = new ArrayList<>();
list.add(new UserInfo("张三", 13));
list.add(new UserInfo("李四", 14));
list.add(new UserInfo("王五", 15));
list.add(new UserInfo("朱六", 16));
//创建 Stream 流
Stream<UserInfo> stream = list.stream();
//最大的年龄
Optional<UserInfo> max = stream.max((m1,m2) -> m1.getAge() - m2.getAge());
System.out.println(max.get());
//最小的年龄
//创建 Stream 流
Stream<UserInfo> stream2 = list.stream();
Optional<UserInfo> min = stream2.min((m1,m2) -> m1.getAge() - m2.getAge());
System.out.println(min.get());
}
static class UserInfo {
private String userName;
private Integer age;
public UserInfo(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
public Integer getAge() {
return age;
}
}
}
注意:Stream 流使用一次后,就会释放资源,如果想要二次使用,需要重新创建。否则报错:
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
输出:
UserInfo{userName='朱六', age=16} UserInfo{userName='张三', age=13}
使用 Stream 的 Match 匹配
public class Test5 {
public static void main(String[] args) {
List<UserInfo> list = new ArrayList<>();
list.add(new UserInfo("张三", 13));
list.add(new UserInfo("李四", 14));
list.add(new UserInfo("王五", 15));
list.add(new UserInfo("朱六", 16));
//创建 Stream 流
Stream<UserInfo> stream = list.stream();
boolean flag = stream.anyMatch(m -> "张三".equals(m.getUserName()));
System.out.println(flag);
}
static class UserInfo {
private String userName;
private Integer age;
public UserInfo(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
public String getUserName() {
return userName;
}
}
}
anyMatch 是返回任何一条匹配的即可。
输出:
true
使用 Stream 过滤器 Filter
public class Test6 {
public static void main(String[] args) {
List<UserInfo> list = new ArrayList<>();
list.add(new UserInfo("张三", 13));
list.add(new UserInfo("李四", 14));
list.add(new UserInfo("王五", 15));
list.add(new UserInfo("朱六", 16));
list.add(new UserInfo("朱六", 20));
//创建 Stream 流
Stream<UserInfo> stream = list.stream();
//过滤名字是【朱六】,且年龄大于18岁的
stream.filter(m -> "朱六".equals(m.getUserName()) && m.getAge() > 18)
.forEach(m -> System.out.println(m));
}
static class UserInfo {
private String userName;
private Integer age;
public UserInfo(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
public String getUserName() {
return userName;
}
public Integer getAge() {
return age;
}
}
}
输出:
UserInfo{userName='朱六', age=20}
使用 Stream 流分页 limit
public class Test7 {
public static void main(String[] args) {
List<UserInfo> list = new ArrayList<>();
list.add(new UserInfo("张三", 13));
list.add(new UserInfo("李四", 14));
list.add(new UserInfo("王五", 15));
list.add(new UserInfo("朱六", 16));
list.add(new UserInfo("朱六", 20));
//创建 Stream 流
Stream<UserInfo> stream = list.stream();
//取出前2条
stream.limit(2).forEach(m -> System.out.println(m));
}
static class UserInfo {
private String userName;
private Integer age;
public UserInfo(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
}
输出:
UserInfo{userName='张三', age=13} UserInfo{userName='李四', age=14}
如果想从第3条开始获取呢?使用 skip 跳过,如下:
stream.skip(2).limit(3).forEach(m -> System.out.println(m));
输出:(如果 limit 的数字超过了 list 集合的长度,不会抛异常。)
UserInfo{userName='王五', age=15} UserInfo{userName='朱六', age=16} UserInfo{userName='朱六', age=20}
使用 Stream 排序 sort
按照年龄升序:
public class Test8 {
public static void main(String[] args) {
List<UserInfo> list = new ArrayList<>();
list.add(new UserInfo("张三", 13));
list.add(new UserInfo("李四", 14));
list.add(new UserInfo("王五", 15));
list.add(new UserInfo("朱六", 16));
list.add(new UserInfo("朱六", 20));
//创建 Stream 流
Stream<UserInfo> stream = list.stream();
stream.sorted((m1, m2) -> m1.getAge() - m2.getAge())
.forEach(k -> System.out.println(k));
}
static class UserInfo {
private String userName;
private Integer age;
public UserInfo(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
public Integer getAge() {
return age;
}
}
}
输出:
UserInfo{userName='张三', age=13} UserInfo{userName='李四', age=14} UserInfo{userName='王五', age=15} UserInfo{userName='朱六', age=16} UserInfo{userName='朱六', age=20}
如果需要降序排,则使用 m2 - m1 即可,如:
//创建 Stream 流
Stream<UserInfo> stream = list.stream();
stream.sorted((m1, m2) -> m2.getAge() - m1.getAge())
.forEach(k -> System.out.println(k));
输出:
UserInfo{userName='朱六', age=20} UserInfo{userName='朱六', age=16} UserInfo{userName='王五', age=15} UserInfo{userName='李四', age=14} UserInfo{userName='张三', age=13}
|