1. 简介
流是一种数据渠道,用于操作数据源(集合、数组)所声称的元素系列
集合讲的是数据,流讲的是计算。
注意:
- Stream是不会存储元素
- Stream不会改变源对象,他们会返回一个持有新结果都是Stream
- Stream操作是延使操作
- Stream流的操作,都是懒加载,只有终止操作时才会执行。
1.1. 基本使用
public class User{
private Long id;
private String name;
private Integer age;
}
List<User> list = Arrays.asList(
new User("段誉","男",18),
new User("段誉","男",18),
new User("段誉","男",14),
new User("段誉","男",27),
new User("段誉","男",null),
new User("段誉","男",36)
);
// 拿到 list 中的所有 id 并转换成 list<Long>
List<Long> userIds = list.stream().map(User::getId).collect(Collectors.toList());
// 拿到 list 中的所有id并转换成 list<String>
List<String> userIds = list.stream()
.map(User::getId)
.map(String::valueOf)
.collect(Collectors.toList());
2. 创建Stream的四种方式
// 第一种:Collection 的 stream 或者 parallelStream 方法创建
List<String> list = new ArrayList<>();
Stream<String> s1 = list.stream();
// 第二种:通过Arrays的静态方法 stream 创建
User[] users = new User[10];
Stream<User> s2 = Arrays.stream(users);
// 第三种:通过Stream的静态方法 of()
Stream<String> s3 = Stream.of("我","长", "的", "像","吴", "彦", "祖");
// 第四种:创建无限流
// 迭代
Stream<Integer> s4 = Stream.iterate(0, x -> x + 2);
s4.forEach(System.out::println);
// 生成
Stream.generate(() -> Math.random()).forEach(System.out::println);
3. 筛选
filter:接收Lambda表达式,从流中排除数据。
limit:返回前n条数据。
skip:跳过前n条数据,若流中不足n条元素,则返回空流。
distinct:去重,但是对象必须重写equals和hashCode方法。
List<User> list = Arrays.asList(
new User("段誉","男",18),
new User("段誉","男",18),
new User("段誉","男",14),
new User("段誉","男",27),
new User("段誉","男",null),
new User("段誉","男",36)
);
// 年龄大于18岁
list.stream().filter(e -> e.getAge() > 18).forEach(System.out::println);
// 取前两条数据
list.stream().filter(e -> e.getAge() > 18).limit(2).forEach(System.out::println);
// 跳过前一条数据
list.stream().filter(e -> e.getAge() > 18).skip(1).forEach(System.out::println);
// 去重
list.stream().distinct().forEach(System.out::println);
// 注意点:如果查询的获取list中的所有年龄时,返回结果还是6个,一般情况下建议做过滤处理
list.stream()
.map(User::getAge)
.filter(ObjectUtil::isNotEmpty) // 将为空的数据过滤掉
.forEach(System.out::println);
4. 映射
map:接收Lambda,将元素转换或提取信息,每一个元素都会被应用,并返回一个新的元素。
flatMap:接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连成一个流
注:区别可以参考list集合的add方法和addAll方法
List<User> list = Arrays.asList(
new User("段誉","男",18),
new User("段誉","男",18),
new User("段誉","男",14),
new User("段誉","男",27),
new User("段誉","男",36)
);
@Test
public void test3(){
list.stream().map(e -> e.getAge()).forEach(System.out::println);
List<String> str = Arrays.asList("aaa","bbb","ccc");
str.stream().map(e -> toCharArr(e)).forEach(e -> e.forEach(System.out::println));
str.stream().flatMap(e -> toCharArr(e)).forEach(System.out::println);
}
public static Stream<Character> toCharArr(String str){
List<Character> arr = new ArrayList<>();
for (Character c : str.toCharArray()) {
arr.add(c);
}
return arr.stream();
}
5. 排序
sorted:无参,表示自然排序(按照abc这样排序),默认有序
可以在其中追加reversed使其倒序
有参,自定义排序
List<User> list = Arrays.asList(
new User("段誉","男",18),
new User("段誉","男",18),
new User("段誉","男",14),
new User("段誉","男",27),
new User("段誉","男",36)
);
@Test
public void test4(){
List<String> str = Arrays.asList("aaa","ddd","bbb","ccc");
str.stream().sorted().forEach(System.out::println);
// 根据年龄排序,如果年龄相同,那么根据姓名排序
list.stream().sorted((x,y) -> {
if(x.getAge().equals(y.getAge())){
return x.getName().compareTo(y.getName());
}else{
return x.getAge().compareTo(y.getAge());
}
}).forEach(System.out::println);
}
// 根据年龄倒序排序
@Test
public void test4(){
List<String> str = Arrays.asList("aaa","ddd","bbb","ccc");
str.stream().sorted().forEach(System.out::println);
list.stream().sorted(
Comparator.comparing(User::getAge).reversed()
).forEach(System.out::println);
}
6. 查询操作
allMatch:是否所有数据都满足该条件
anyMatch:所有数据中是否有一个元素满足该条件
noneMatch:检查是否没有匹配所有元素
findFirst:返回第一个元素
findAny:返回当前流中任意元素
count:返回当前流中的元素的总数
max:返回流中的最大值
min:返回流中的最小值
List<User> list = Arrays.asList(
new User("段誉","男",18),
new User("段誉","男",18),
new User("段誉","男",14),
new User("段誉","男",27),
new User("段誉","男",36)
);
@Test
public void test5(){
// 是否所有数据都满足该条件
boolean b = list.stream().allMatch(e -> e.getAge() > 28);
System.out.println(b);
// 所有数据中是否有一个元素满足该条件
boolean b1 = list.stream().anyMatch(e -> e.getAge() > 28);
System.out.println(b1);
// 检查是否没有匹配所有元素
boolean b2 = list.stream().noneMatch(e -> e.getAge() > 28);
System.out.println(b2);
// 返回第一个元素
Optional<User> first = list.stream().findFirst();
System.out.println(first);
// 返回当前流中任意元素
Optional<User> any = list.stream().findAny();
System.out.println(any);
// 返回当前流中的元素的总数
long count = list.stream().count();
System.out.println(count);
// 返回流中的最大值
Optional<User> max = list.stream().max((x,y) -> Integer.compare(x.getAge(),y.getAge()));
System.out.println(max);
Optional<Integer> min = list.stream().map(User::getAge).min(Integer::compare);
System.out.println(min);
}
7. 累积
reduce:将流中的数据反复结合起来,得到一个值
collect:收集,将流转换成其他形式,接收Collector接口实现,用于汇总
// 总年龄
// 注:0会赋值给x,每次循环的元素都是y
Integer reduce = list.stream().map(User::getAge).reduce(0, (x, y) -> x + y);
System.out.println(reduce);
// 同上
Optional<Integer> reduce1 = list.stream().map(User::getAge).reduce(Integer::sum);
System.out.println(reduce1);
// 取出集合中的年龄,并转换成list集合
List<Integer> collect = list.stream().map(User::getAge).collect(Collectors.toList());
System.out.println(collect);
// 取出集合中的年龄,并转换成hashSet集合
HashSet<Integer> collect1 = list.stream().map(User::getAge).collect(Collectors.toCollection(HashSet::new));
System.out.println(collect1);
// 取出集合中年龄最大的元素,同理,还有:平均值、总数、最小值等多个方法
Optional<User> max = list.stream().max((x, y) -> Integer.compare(x.getAge(), y.getAge()));
System.out.println(max.get());
8. Collectors
toList:转换成list集合
toCollection(集合):转换成集合
groupingBy(流的值):按照给定的值分组
joining:拼接
summarizingInt(值):返回结果集
// 取出集合中的年龄,并转换成hashSet集合
HashSet<Integer> collect1 = list.stream().map(User::getAge).collect(Collectors.toCollection(HashSet::new));
System.out.println(collect1);
// 取出集合中年龄最大的元素,同理,还有:平均值、总数、最小值等多个方法
Optional<User> max = list.stream().max((x, y) -> Integer.compare(x.getAge(), y.getAge()));
System.out.println(max.get());
// 等同于同上
IntSummaryStatistics collect2 = list.stream().collect(Collectors.summarizingInt(User::getAge));
System.out.println(collect2.getMax());
System.out.println(collect2.getMin());
System.out.println(collect2.getAverage());
// 根据性别分组
Map<String, List<User>> collect3 = list.stream().collect(Collectors.groupingBy(User::getSex));
System.out.println(collect3);
// 根据性别分组后再根据姓名分组
Map<String, Map<String, List<User>>> collect4 = list.stream().collect(Collectors.groupingBy(User::getSex,Collectors.groupingBy(User::getName)));
System.out.println(collect4);
// 连接元素的所有姓名
String collect5 = list.stream().map(User::getName).collect(Collectors.joining());
System.out.println(collect5);
// 以逗号隔开
String collect6 = list.stream().map(User::getName).collect(Collectors.joining(","));
System.out.println(collect6);
// 前后都加== 并以逗号隔开
String collect7 = list.stream().map(User::getName).collect(Collectors.joining(",","==","=="));
System.out.println(collect7);
我真的有点像