Java8新特性3:Stream流
回顾之前《JavaSE-23.2》:
https://www.cnblogs.com/yppah/p/14900824.html
https://www.cnblogs.com/yppah/p/14900829.html
https://www.cnblogs.com/yppah/p/14900834.html
https://www.cnblogs.com/yppah/p/14900837.html
https://www.cnblogs.com/yppah/p/14900847.html
1 什么是stream流
Stream 是JDK1.8 中处理集合的关键抽象概念,Lambda 和 Stream 是JDK1.8新增的函数式编程最有亮点的特性了,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用SQL执行的数据库查询。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
2 创建stream流
// 创建stream流的两种方式
userList.stream(); //并行流,采用多线程执行,数据量比较少的时候
userList.parallelStream(); //串行流,采用单线程执行,数据量比较大的时候
// parallelStream效率比Stream高
//原理:Fork join 将一个大的任务拆分n多个小的子任务并行执行,最后在统计结果,有可能会非常消耗cpu的资源,确实可以提高效率。
//注意:数据量比较少的情况下,不要使用并行流。
3 Stream将list转换为Set
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/25 16:47
*/
public class Test01 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
userList.add(new User("amy", 22)); //对象的属性值重复;但两个对象不相等
User user = new User("sam", 23);
userList.add(user);
userList.add(user); //对象(存储地址)重复;可去重
/*// 创建stream流的两种方式
userList.stream(); //并行流,采用多线程执行
userList.parallelStream(); //串行流,采用单线程执行
// parallelStream效率比Stream要高*/
//利用stream将list转为set
Stream<User> userStream = userList.stream();
Set<User> userSet = userStream.collect(Collectors.toSet());
userSet.forEach(t -> System.out.println(t));
}
}
4 set集合去重底层原理剖析[经典面试题]
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/26 8:45
*/
public class Test01_2 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
userList.add(new User("jack", 19));
userList.add(new User("jack", 19));
System.out.println("list未去重:");
userList.forEach(user -> System.out.println(user));
System.out.println("set以下为去除重复后:");
Stream<User> userStream = userList.stream();
Set<User> userSet = userStream.collect(Collectors.toSet());
userSet.forEach(t -> System.out.println(t));
}
}
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.HashMap;
import java.util.HashSet;
/**
* @Author: haifei
* @Date: 2022/10/27 13:57
*/
public class Test01_3 {
public static void main(String[] args) {
/*
Object类中equals()默认是比较两者内存地址是否相等
此处自定义的User类并未重写equals(),则直接比较两对象的地址
String类重写了equals()
*/
User user1 = new User("jack", 19);
User user2 = new User("jack", 19);
System.out.println("user1.equals(user2): " + user1.equals(user2)); //false
System.out.println("user1==user2: " + (user1==user2)); //false
String str1 = "jack";
String str2 = "jack";
System.out.println("str1.equals(str2): " + str1.equals(str2)); //true
System.out.println("str1==str2: " + (str1==str2)); //true
/*
set集合底层依赖于map集合实现防重复key
map集合底层基于equals比较防重复key,结合hashcode
*/
HashSet<String> strHashSet = new HashSet<>();
strHashSet.add(str1);
strHashSet.add(str2);
HashMap<Object, Object> objectHashMap = new HashMap<>();
objectHashMap.put(user1, "a");
objectHashMap.put(user2, "b");
//此时map会装两个不同的key,因为两个对象地址不同,即为两对象不相等
objectHashMap.forEach((k,v)-> System.out.println("k:" + k + ", v:" + v));
//此处,若User类中重写了equals()和hashcode(),则两对象相等,map中只存储一个key
//因此,上一.java中则会实现去重
}
}
5 Stream将list转换为Map
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/26 16:50
*/
public class Test02 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
Stream<User> userStream = userList.stream();
/*Map<String, User> userMap = userStream.collect(Collectors.toMap(
new Function<User, String>() {
@Override
public String apply(User user) {
return user.getUserName(); //键
}
},
new Function<User, User>() {
@Override
public User apply(User user) {
return user; //值
}
})
);
userMap.forEach(new BiConsumer<String, User>() {
@Override
public void accept(String s, User user) {
System.out.println(s + "," + user);
}
});*/
/*Map<String, User> userMap = userStream.collect(Collectors.toMap(
user -> {
return user.getUserName(); //键
},
user -> {
return user; //值
})
);*/
Map<String, User> userMap = userStream.collect(Collectors.toMap(user -> user.getUserName(), user -> user));
userMap.forEach((s, user) -> System.out.println(s + "," + user));
}
}
6 通过reduce求和
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/26 17:35
*/
public class Test03 {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(10, 50, 30, 10);
// Optional<Integer> reduce = stream.reduce(new BinaryOperator<Integer>() {
// @Override
// public Integer apply(Integer i1, Integer i2) {
// return i1 + i2;
// }
// });
Optional<Integer> reduce = stream.reduce((i1, i2) -> i1 + i2);
System.out.println(reduce.get()); //100
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
userList.add(new User("sam", 23));
Stream<User> userStream = userList.stream();
/*Optional<User> sumAge = userStream.reduce(new BinaryOperator<User>() {
@Override
public User apply(User u1, User u2) {
User user = new User("sumAge", u1.getAge() + u2.getAge());
return user;
}
});*/
Optional<User> sumAge = userStream.reduce((u1, u2) -> {
User user = new User("sumAge", u1.getAge() + u2.getAge());
return user;
});
System.out.println(sumAge.get().getAge()); // 87
}
}
7 Max和Min
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/26 19:13
*/
public class Test04 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
userList.add(new User("sam", 23));
Stream<User> userStream = userList.stream();
/*Optional<User> max = userStream.max(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o1.getAge() - o2.getAge();
}
});*/
Optional<User> max = userStream.max((o1, o2) -> o1.getAge() - o2.getAge());
//java.lang.IllegalStateException: stream has already been operated upon or closed
//记得要重新创建流再求min,要是接着上面的userStream用会报错
Stream<User> userStream2 = userList.stream();
/*Optional<User> min = userStream2.min(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o1.getAge() - o2.getAge();
}
});*/
Optional<User> min = userStream2.min((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println("max age:" + max.get().getAge());
System.out.println("min age:" + min.get().getAge());
}
}
8 Match匹配
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/26 19:24
*/
public class Test05 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
userList.add(new User("sam", 23));
Stream<User> stream = userList.stream();
/*boolean isAnyMatch = stream.anyMatch(new Predicate<User>() {
@Override
public boolean test(User user) {
return "tom".equals(user.getUserName());
}
});*/
boolean isAnyMatch = stream.anyMatch(user -> "tom".equals(user.getUserName()));
System.out.println(isAnyMatch); //只要匹配一条记录就是true,一条也没有则false
Stream<User> stream2 = userList.stream();
/*boolean isAllMatch = stream2.allMatch(new Predicate<User>() {
@Override
public boolean test(User user) {
return "tom".equals(user.getUserName());
}
});*/
boolean isAllMatch = stream2.allMatch(user -> "tom".equals(user.getUserName()));
System.out.println(isAllMatch); //只有每条记录都匹配才是true,否则为false
}
}
9 Fliter过滤器
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/26 19:34
*/
public class Test06 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("lili", 20));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
userList.add(new User("sam", 23));
//where userName="lili" and age > 18
Stream<User> stream = userList.stream();
/*stream.filter(new Predicate<User>() {
@Override
public boolean test(User user) {
return "lili".equals(user.getUserName()) && user.getAge() > 18;
}
}).forEach(user -> System.out.println(user));*/
stream.filter(user -> "lili".equals(user.getUserName()) && user.getAge() > 18)
.forEach(user -> System.out.println(user));
}
}
10 Limit和Skip
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/26 19:51
*/
public class Test07 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
userList.add(new User("sam", 23));
userList.add(new User("jack", 30));
Stream<User> stream = userList.stream();
stream.limit(2).forEach(user -> System.out.println(user)); //limit(0,2),[从第0条往后]取前两条
System.out.println("===========================");
Stream<User> stream2 = userList.stream();
stream2.skip(2).limit(3).forEach(user -> System.out.println(user)); //limit(2,3),从第2条后取3条
}
}
11 Sorted排序
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/27 9:31
*/
public class Test08 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
userList.add(new User("sam", 23));
userList.add(new User("jack", 30));
Stream<User> stream = userList.stream();
/*stream.sorted(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o2.getAge()-o1.getAge(); //前o1-后o2升序;后o2-前o1降序
}
}).forEach(user -> System.out.println(user.toString()));*/
stream.sorted(
(o1, o2) -> (o2.getAge()-o1.getAge())
).forEach(
user -> System.out.println(user.toString())
);
}
}
12 Stream综合案例
package com.yppah.myStream;
import com.yppah.myLambda.p6.User;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* @Author: haifei
* @Date: 2022/10/27 9:40
*/
public class Test09 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("lili", 16));
userList.add(new User("tom", 26));
userList.add(new User("amy", 22));
userList.add(new User("sam", 23));
userList.add(new User("sam", 16));
userList.add(new User("sam", 35));
userList.add(new User("sam22", 23));
userList.add(new User("sam33", 30));
userList.add(new User("jack", 30));
// 需求:对数据流的数据实现降序排列、且名称为sam、获取前两位进行打印
Stream<User> stream = userList.stream();
/*stream.sorted(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o2.getAge()-o1.getAge();
}
}).filter(new Predicate<User>() {
@Override
public boolean test(User user) {
return "sam".equals(user.getUserName());
}
}).limit(2).forEach(user -> System.out.println(user));*/
stream.sorted((o1, o2) -> o2.getAge()-o1.getAge())
.filter(user -> "sam".equals(user.getUserName()))
.limit(2)
.forEach(user -> System.out.println(user)); //forEach是终止操作,其之后当前stream流不再可用
}
}
13 并行流底层实现原理
package com.yppah.myStream;
import java.time.Duration;
import java.time.Instant;
import java.util.OptionalLong;
import java.util.function.LongBinaryOperator;
import java.util.stream.LongStream;
/**
* @Author: haifei
* @Date: 2022/10/27 10:46
*/
public class Test10 {
public static void main(String[] args) {
// 单线程:13330ms 13290ms 13s左右
Instant start = Instant.now();
long sum = 0;
for (long i=0; i<=50000000000L; i++) {
sum += i;
}
System.out.println(sum);
Instant end = Instant.now();
System.out.println("五百亿求和花费时间:" + Duration.between(start, end).toMillis());
// 并行流: 11035ms 11636ms 11s左右
Instant start2 = Instant.now();
LongStream longStream = LongStream.rangeClosed(0, 50000000000L);
/*OptionalLong reduce = longStream.parallel().reduce(new LongBinaryOperator() {
@Override
public long applyAsLong(long left, long right) {
return left + right;
}
});*/
OptionalLong reduce = longStream.parallel().reduce((left, right) -> left + right);
System.out.println(reduce.getAsLong());
Instant end2 = Instant.now();
System.out.println("五百亿求和花费时间:" + Duration.between(start2, end2).toMillis());
/*
原理:
底层是多线程
处理大的任务拆分成n多小任务,最后将计算结果合并
*/
}
}
单线程
多线程