前言
该案例是自己根据网上相关资料整理的一些项目中可能会用到的Stream流的操作相关内容,项目中我会慢慢养成这种习惯的,可以很大程度的提高开发效率
代码
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 用于演示java8中Stream流的相关内容
* 注意:
* ①Stream操作符中与Collectors.中类似的收集器功能,如果能用Steam的操作符就去使用,这样可以降低系统开销
* ②在整个流的操作过程中,终止操作符只能使用一次,用作收尾。forEach除外,因为foreach只是一个语法糖
*
* @author wyj
* @date 2021/5/14 9:21
*/
public class MyStream {
public static void main(String[] args) {
collectOperator();
}
/** *终止操作符,collect的收集器详解 */
public static void collectOperator() {
// collect 收集: 使用系统提供的收集器可以将最终的数据流收集到List,Set,Map等容器中
User user = new User(1L, 1L, "老大");
User user1 = new User(2L, 1L, "老二");
User user2 = new User(3L, 2L, "老三");
User user3 = new User(4L, 2L, "老三");
// Collectors.toSet()将数据收集到Set集合,可自行去重
Stream.of(user, user1, user2).collect(Collectors.toSet()).forEach(System.out::println);
// Collectors.toList()将数据收集到ArrayList集合
Stream.of(user, user1, user2).collect(Collectors.toList()).forEach(System.out::println);
Stream.of(user, user1, user2)
.collect(Collectors.toCollection(ArrayList::new))
.forEach(System.out::println);
/*
* Collectors.toList():将流中的元素转换到一个Map中,需要指定key和value
*/
// id作为key,name作为value
Map<Long, String> collect =
Stream.of(user, user1, user2).collect(Collectors.toMap(User::getId, User::getName));
System.out.println(collect);
// id作为key,对象作为value
Map<String, User> userMap =
Stream.of(user, user1, user2).collect(Collectors.toMap(User::getName, Function.identity()));
System.out.println(userMap);
/*
* Collectors.joining() 拼接,有三个重载方法,底层实现是StringBuilder,
* 通过append方法拼接到一起,并且可以自定义分隔符
* (这个感觉还是很有用的,很多时候需要把一个list转成一个String,指定分隔符就可以实现了,非常方便)、前缀、后缀
*/
String names =
Stream.of(user, user1, user2).map(User::getName).collect(Collectors.joining(","));
String names1 =
Stream.of(user, user1, user2).map(User::getName).collect(Collectors.joining(",", "[", "]"));
// Collectors.counting() 统计元素个数和Stream.count() 作用都是一样,使用场景还是有区别的
Long aLong = Stream.of(user, user1, user2).collect(Collectors.counting());
System.out.println(aLong);
long count = Stream.of(user, user1, user2).count();
System.out.println(count);
// Collectors.minBy()、Collectors.maxBy()和Stream.min()、Stream.max() 作用也是一样的
Stream.of(user, user1, user2)
.map(User::getId)
.collect(Collectors.maxBy(Long::compareTo))
.ifPresent(System.out::println);
// Collectors.summarizingLong()、Collectors.summarizingLong()、Collectors.summarizingDouble()
// 这三个分别用于int、long、double类型数据一个求总操作,返回的是一个SummaryStatistics(求总),包含了数量统计count、求和sum、最小值min、平均值average、最大值max
// 虽然IntStream、DoubleStream、LongStream 都可以是求和sum但是也仅仅只是求和,没有summing结果丰富。
// 如果要一次性统计、求平均值什么的,summing还是非常方便的。
IntSummaryStatistics summaryStatistics =
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.collect(Collectors.summarizingInt(Integer::valueOf));
System.out.println(summaryStatistics.getMax());
System.out.println(summaryStatistics.getMin());
System.out.println(summaryStatistics.getSum());
System.out.println(summaryStatistics.getAverage());
// 求总和、最大、最小、平均值
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.mapToInt(Integer::valueOf)
.min()
.ifPresent(System.out::println);
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.mapToInt(Integer::valueOf)
.max()
.ifPresent(System.out::println);
System.out.println(Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).mapToInt(Integer::valueOf).sum());
System.out.println(
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).mapToInt(Integer::valueOf).average());
// Collectors.averagingInt()、Collectors.averagingDouble()、Collectors.averagingLong()
// 求平均值,适用于高级场景
System.out.println(
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.collect(Collectors.averagingInt(Integer::valueOf)));
// Collectors.reducing() 好像也和Stream.reduce()差不多,也都是规约操作。其实Collectors.counting() 就是用reducing()实现的
/*
* *前后处理
*/
// Collectors.groupingBy()和Collectors.groupingByConcurrent():
// 这两者区别也仅是单线程和多线程的使用场景,为什么要groupingBy归类为前后处理呢?
// groupingBy 是在数据收集前分组的,再将分好组的数据传递给下游的收集器
Map<Long, List<User>> collect1 =
Stream.of(user, user1, user2, user3)
.collect(
Collectors.groupingBy(
User::getParentId,
Collectors.mapping(Function.identity(), Collectors.toList())));
System.out.println(collect1);
// Collectors.mapping() 可以自定义要收集的字段。 以下2种方式是等价的
List<Long> longs =
Stream.of(user, user1, user2, user3)
.collect(Collectors.mapping(User::getId, Collectors.toList()));
longs.forEach(System.out::println);
List<Long> longs1 =
Stream.of(user, user1, user2, user3).map(User::getId).collect(Collectors.toList());
longs1.forEach(System.out::println);
// Collectors.collectingAndThen()收集后操作,如果你要在收集数据后再做一些操作,那么这个就非常有用了。
ListIterator<User> collect2 =
Stream.of(user, user1, user2, user3)
.collect(Collectors.collectingAndThen(Collectors.toList(), List::listIterator));
collect2.forEachRemaining(System.out::println);
}
/** * 终止操作符,不包括collect */
public static void finishOperator() {
// count操作符:统计数据流中的元素个数,返回的是long 类型
long count = Stream.of("apple", "banana", "orange", "waltermaleon", "grape", "grape").count();
System.out.println(count);
// findFirst操作符: 获取流中的第一个元素
Optional<String> first =
Stream.of("apple", "banana", "orange", "waltermaleon", "grape", "grape").findFirst();
first.ifPresent(System.out::println);
// findAny操作符: 获取流中任意一个元素 在parallel(并行流)的情况下每次获取结果可能不一样
Optional<String> any =
Stream.of("apple", "banana", "orange", "waltermaleon", "grape", "grape")
.parallel()
.findAny();
any.ifPresent(System.out::println);
// noneMatch操作符:若流中的元素都与指定的元素不匹配则返回true
System.out.println(Stream.of("aac", "bb", "cc", "aa").noneMatch(e -> e.length() == 3));
System.out.println(Stream.of("aa", "bb", "cc", "aa").noneMatch("aa"::equals));
// allMatch anyMatch 和noneMatch操作符同理,allMatch是全匹配上为true,anyMatch是一个匹配上则为true
System.out.println(Stream.of("aa", "bb", "cca", "aa").allMatch(e -> e.length() == 2));
System.out.println(Stream.of("aa", "bb", "cc", "aa").anyMatch("aa"::equals));
// min操作符:最小的一个,传入比较器,也可能没有(如果数据流为空)
System.out.println(Stream.of(0, 9, 8, 4, 5, 6, -1).min((a, b) -> a - b).get());
// max操作符:最大的一个,传入比较器,也可能没有(如果数据流为空)
System.out.println(Stream.of(0, 9, 8, 4, 5, 6, -1).max((a, b) -> a - b).get());
// reduce操作符:规约操作,所有的元素归约成一个,比如对所有元素求和,乘啊等
System.out.println(Stream.of(0, 9, 8, 4, 5, 6, -1).reduce(Integer::sum).get());
System.out.println(Stream.of(0, 9, 8, 4, 5, 6, -1).reduce((a, b) -> a * b).get());
// toArray操作符:转成数组,可以提供自定义数组生成器
Object[] objects = Stream.of(0, 2, 6, 5, 4, 9, 8, -1).toArray();
System.out.println(Arrays.toString(objects));
// 转换成指定类型数组
Integer[] integers = Stream.of(0, 2, 6, 5, 4, 9, 8, -1).toArray(Integer[]::new);
System.out.println(Arrays.toString(integers));
// 转换成指定类型数组
Long[] strings = Stream.of(0L, 2L, 6L, 5L, 4L, 9L, 8L, -1L).toArray(Long[]::new);
System.out.println(Arrays.toString(strings));
}
/** *中间操作符 */
public static void intermediateOperator() {
List<String> list = Arrays.asList("apple", "banana", "orange", "waltermaleon", "grape");
// map操作符: 将T类型转换成R类型的
list.stream().map(String::length).forEach(System.out::println);
// mapToInt操作符: 将T类型转换成Int类型 (mapToLong、mapToDouble与mapToInt 类似)
list.stream().mapToInt(String::length).forEach(System.out::println);
// flatmap操作符: 将元素拍平拍扁 ,将拍扁的元素重新组成Stream,并将这些Stream 串行合并成一条Stream
Stream.of("a-b-c-d", "e-f-i-g-h")
.flatMap(i -> Stream.of(i.split("-")))
.forEach(System.out::println);
// limit操作符:限制元素的个数,只需传入 long 类型 表示限制的最大数
Stream.of(1, 2, 3, 4, 5, 6).limit(3).forEach(System.out::println);
// distinct filter 比较常用不做介绍
// peek操作符: 挑选 ,将元素挑选出来做处理,
User user = new User(1L, 1L, "老大");
User user1 = new User(2L, 1L, "老二");
User user2 = new User(3L, 1L, "老三");
Stream.of(user, user1, user2)
.peek(i -> i.setName(i.getName() + i.getId()))
.forEach(System.out::println);
// skip操作符:跳过指定个数的元素
Stream.of(1, 2, 3, 4, 5, 6).skip(3).forEach(System.out::println);
// stored:排序,可以自定义比较器,默认从小到大排序
Stream.of(2, 1, 3, 6, 4, 9, 6, 8, 0).sorted().forEach(System.out::println);
}
}
class User {
private Long id;
private Long parentId;
private String name;
public User(Long id, Long parentId, String name) {
this.id = id;
this.parentId = parentId;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("User{");
sb.append("id=").append(id);
sb.append(", parentId=").append(parentId);
sb.append(", name='").append(name).append('\'');
sb.append('}');
return sb.toString();
}
}