1.Stream流介绍
Stream是Java 8提供的新功能,是对集合(Collection)对象功能的增强,能对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。 与Lambda 表达式结合,也可以提高编程效率、简洁性和程序可读性。
同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势
Stream<User> stream = userList.stream(); //串行
Stream<User> userStream = userList.parallelStream(); //并行
Stream的操作符大体分为两种:中间操作符和终止操作符
中间操作符:中间操作符在执行特定处理程序之后,数据依然可以传递给下一级的操作符
1.1 中间操作符
中间操作符主要包含8种:
- map(mapToInt,mapToLong,mapToDouble) 转换操作符,把比如A->B,这里默认提供了转int,long,double操作符
- flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作,比如把int[]{2,3,4}拍平,变成2,3,4也就是从原来的一个数据变成三个数据,这里默认拍平成int,double,long的操作符。
- limit限流操作,比如数据流中有10个,我只要出前三个就可以使用。
- distint去重操作,对重复元素去重,底层使用了equals方法。
- filter过滤操作,把不必要的数据过滤。
- peek挑出操作,对某些数据进行某些操作,如读取,编辑修改等。
- skip跳过操作,跳过某些元素
- sorted排序操作,对元素进行排序,前提是实现Comparable接口,也可以自定义比较器。
1.2 终止符
终止符包含8种:
- collect收集操作,将所有的数据收集起来,这个操作非常重要,官方提供的Collectors 提供了非常多收集器,可以说Stream的核心在于Collectors
- count统计操作,统计最终的数据个数
- findFirst,finfAny查找操作,查找第一个,查找任何一个返回的类型都是Optiona
- noneMatch,allMatch,anyMatch匹配操作,数据流中存在符合条件的元素,返回bool值
- min,max最值操作,需要自定义比较器,返回数据流中的最大值,最小值
- reduce规约操作,将整个流的值规约为一个值,count、min、max底层就是使用reduce。
- forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了。
- toArray 数组操作,将数据流的元素转换成数组。
终止操作符:数据经过中间加工操作,就轮到终止操作符上场了;终止操作符就是对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次。
2.stream流的创建方式
2.1 使用Collection下的 stream() 和 parallelStream() 方法
List<String> list = new ArrayList<>();
Stream<String> Stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
2.2 使用Arrays 中的 stream() 方法,将数组转成流
Integer[] nums = new Integer[10];
Stream<Integer> Stream = Arrays.stream(nums);
2.3 使用Stream中的静态方法:of()、iterate()、generate()
Stream<Integer> Stream = Stream.of(1,2,3,4,5,6);
Stream<Integer> Stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
Stream2.forEach(System.out::println); // 0 2 4 6 8 10
Stream<Double> Stream3 = Stream.generate(Math::random).limit(2);
Stream3.forEach(System.out::println);
2.4 使用 Pattern.splitAsStream() 方法,将字符串分隔成流
Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
stringStream.forEach(System.out::println); //a b c d
3.Stream操作实例
1.准备一个用户对象
package stream;
import java.util.Objects;
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private Integer sex;
private Double money;
public User() {
}
public User(Integer id, String username, String password, Integer age, Integer sex, Double money) {
this.id = id;
this.username = username;
this.password = password;
this.age = age;
this.sex = sex;
this.money = money;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", sex=" + sex +
", money=" + money +
'}';
}
}
2.集合里面放入对象
List<User> userList = new ArrayList<>();
userList.add(new User(1, "yykk", "111111", 34, 1, 34600d));
userList.add(new User(2, "祈福", "2222222", 24, 0, 883600d));
userList.add(new User(3, "小王", "3333333", 24, 1, 734090d));
userList.add(new User(4, "小楠", "4444444", 14, 0, 33400d));
userList.add(new User(5, "小张", "55555", 29, 1, 140000d));
3.1 filter过滤某些元素
查询用户年龄大于25岁的
List<User> collect = userList.stream().filter(new Predicate<User>() {
@Override
public boolean test(User user) {
return user.getAge() > 25;
}
}).collect(Collectors.toList());
可以简写成下面这个
List<User> collect5 = stream.filter(user -> user.getAge() > 25).collect(Collectors.toList());
3.2 peek和map
peek没返回值
Stream<T> peek(Consumer<? super T> action); //无返回值
map有返回值
<R> Stream<R> map(Function<? super T, ? extends R> mapper); //有返回值
peek 实例:查询年龄大于25岁并且年龄加1岁
List<User> collect1 = userList.stream().
filter(user -> user.getAge() > 25).
peek(u -> u.setAge(u.getAge()+1)).
collect(Collectors.toList());
System.out.println(collect1);
map实例:查询年龄大于25岁并且年龄加1岁
//年龄大于25岁的加1岁 map
List<User> collect2 = userList.stream().filter(user -> user.getAge() > 25).
map(user -> {
user.setAge(user.getAge() + 1);
return user;
}).collect(Collectors.toList());
System.out.println("==========");
System.out.println(collect2);
peek和map的区别是什么?
-
peek和map区别:peek无返回值,map有返回值
-
peek你前面集合流化对象返回的是什么就是什么?map可以把stream返回值进行改变。我可以把集合中的对象改成map在返回。或者我只需要集合中某个一列的值。
比如下面的例子
只返回用户的姓名
List<String> collect3 = userList.stream().map(user -> {
return user.getUsername();
}).collect(Collectors.toList());
for (String s : collect3) {
System.out.println(s);
}
//输出结果
//yykk
//祈福
//小王
//小楠
//小张
只返回用户的姓名和年龄(定义的map,返回的类型发生了改变) 除了定义map 也可以定义一个vo类
List<Map<String, Object>> collect4 = userList.stream().map(user -> {
Map<String, Object> map = new HashMap<>();
map.put("username", user.getUsername());
map.put("age", user.getAge());
return map;
}).collect(Collectors.toList());
//输出结果
//{age=36, username=yykk}
//{age=24, username=祈福}
//{age=24, username=小王}
//{age=14, username=小楠}
//{age=31, username=小张}
3.3 sorted排序
用户根据年龄排序
List<User> collect = userList.stream().sorted(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o1.getAge() - o2.getAge();
}
}).collect(Collectors.toList());
//可以简写成
//List<User> collect = userList.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).collect(Collectors.toList());
for (User user : collect) {
System.out.println(user);
}
3.4 distinct 去重
去重,去重重复的用户对象 去重时一定重新equals和hashCode。但是如果两个用户之间比较是否相等,用户对象只需要重写equals方法
重写equals和hashcode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(username, user.username) &&
Objects.equals(password, user.password) &&
Objects.equals(age, user.age) &&
Objects.equals(sex, user.sex) &&
Objects.equals(money, user.money);
}
@Override
public int hashCode() {
return Objects.hash(id, username, password, age, sex, money);
}
3.5 limit 限流操作
比如用户数据有5个 我只取3个
List<User> collect2 = userList.stream()
.limit(3)
.collect(Collectors.toList());
for (User user : collect2) {
System.out.println(user);
}
3.6 skip 跳过操作,跳过某些元素
跳过三条数据再取数据 就是有5条数据的话 跳过了3条,就只能取最后两条了
List<User> collect2 = userList.stream()
.skip(3)
.collect(Collectors.toList());
for (User user : collect2) {
System.out.println(user);
}
limit和skip组合可以简单的实现分页
//分页设计
Integer pageSize = 2;//每页几条
Integer pageNo = 1; //第几页
Integer skip = (pageNo-1)*pageSize;
//skip(2) 代表跳过两个用户再取数据
List<User> collect2 = userList.stream()
.skip(skip)
.limit(pageSize)
.collect(Collectors.toList());
for (User user : collect2) {
System.out.println(user);
}
3.7 mapToInt
int sum = userList.stream().mapToInt(user11 -> user11.getAge()).sum(); //年龄和
double average = userList.stream().mapToInt(user11 -> user11.getAge()).average().getAsDouble(); //平均值
int min = userList.stream().mapToInt(user11 -> user11.getAge()).min().getAsInt(); //最小值
int max = userList.stream().mapToInt(user11 -> user11.getAge()).max().getAsInt(); //最小值
终止操作
3.8 max min 最大最小值
年龄最大的用户
User user2 = userList.stream().max(((o1, o2) -> o1.getAge() - o2.getAge())).get();
System.out.println(user2);
用户最大的年龄 利用map转化输出的流形式
Integer maxAge = userList.stream().map(user3 -> user3.getAge()).max(((o1, o2) -> o1 - o2)).get();
System.out.println(maxAge);
3.9 count 数量大小
long count1 = userList.stream().count();
System.out.println(count1);
3.10 findFirst 取出集合中第一个元素,findAny 取出集合中任意一个数据
取出用户集合中的第一个用户
Optional<User> user = userList.stream().distinct().findFirst();
System.out.println(user.get());
取出用户集合中的任意一个用户
注意:取出集合中的任意一个元素,需要使用并行流,串行流一直取出的都是第一个元素
//取出集合中的随意一条数据 需要并行流
User user1 = userList.parallelStream().distinct().findAny().get();
System.out.println(user1);
3.11 anyMatch 只要有一个数据满足条件就是true
allMatch 必须所有条件都满足 才可以是true
noneMatch 和allMatch相对的
所有用户年龄大于16岁,才可以是true
boolean b2 = userList.stream().anyMatch(user1 -> user1.getAge() > 16);
System.out.println(b2);
所有人年龄大于16岁,是false
boolean b = userList.stream().noneMatch(new Predicate<User>() {
@Override
public boolean test(User user) {
return user.getAge() > 16;
}
});
//简写成
boolean b3 = userList.stream().noneMatch(user1 -> user1.getAge() > 16);
只要有一个人的年龄大于16岁就是true
boolean b2 = userList.stream().anyMatch(user1 -> user1.getAge() > 16);
System.out.println(b2);
3.12 Collectors.groupingBy 分组
根据用户性别进行分组
Map<Integer, List<User>> collect = userList.stream().collect(Collectors.groupingBy(User::getSex));
List<User> users = collect.get(0);
Collectors.partitioningBy 根据条件划分
用户年龄大于16岁,和小于等于16岁分成两组
Map<Boolean, List<User>> collect1 = userList.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 16));
List<User> aTrue = collect1.get(true);
本文章根据飞哥视频总结出来
b站视频:【学相伴飞哥】Java新特性-stream流初步学习_哔哩哔哩_bilibili