Java 8 Stream
parallelStream
顺序不保证
java.util.function(用于接口编程不适用的场景尤佳)
IO Function // <T, R> 输入输出
IO UnaryOperator // <T> = Function<T, T>
IIO BiFunction // <T, U, R> 2 个输入,1 个输出
IIO BinaryOperator // <T> = BiFunction<T, T, T>
I\ Consumer // <T> 消费
II\ BiConsumer // <T, U> 2 个输入的消费
IO Predicate // <T> 断言
IIO BiPredicate // <T, U> 2 个输入的断言
\O Supplier // <T> 工厂
collect
// 1 个参数方法必须是 non-static 2 个参数方法必须是 static,不管如何其中第 2 个参数合并到第一个
list.parallelStream()
.collect(
() -> new Page<DB>(),
(r, e) -> r.add(e),
(rto, rfrom) -> rto.addAll(rto, rfrom))// 用于 parallelStream,都是 new 出来的,所以安全
.data
.forEach(e -> System.out.println(e.name));
list.parallelStream()
.collect(
Page<DB>::new,
Page::add,
Page::addAll)// 用于 parallelStream,都是 new 出来的,所以安全
.data
.forEach(e -> System.out.println(e.name));
reduce
- 用 Class::Function 的话 Function 都是 2 个参数且是 static
- 1 个参数:默认返回 Optional.value = null
Optional<DB> result = list.parallelStream().reduce((firstOrAnyRefAsResult, e) -> {
// parallelStream: firstOrAnyRefAsResult = 随机的无序的任意一个元素
// stream: firstOrAnyRefAsResult = 有序的第一个元素
// 不安全
// firstOrAnyRefAsResult.price += e.price;
// return firstOrAnyRefAsResult;
// 安全
DB x = new DB(null, null, 0);
x.price += firstOrAnyRefAsResult.price + e.price;
return x;
});
if (result.isPresent())
System.out.println(result.get().price + " - " + (result.get() == one));
else
System.out.println("Not Exists");
- 2 个参数:默认返回 identity
// 没有元素时作为默认值返回,有元素用于(每个线程)result
DB identity = new DB("种子", null, 1);
// method 2
DB result2 = list.parallelStream().reduce(identity, (refIdentityOrNewResult, e2) -> {
// 要结合 1 个参数的方法理解
// refIdentityOrNewResult = identity
// 错误
// refIdentityOrNewResult.price += e.price;
// return refIdentityOrNewResult;
// refIdentityOrNewResult (每个线程)第一次调用=identity, 其它调用=总是下面的 new
// 正确
// DB x = new DB(null, null, 0);
// x.price += refIdentityOrNewResult.price + e.price;
// return x;
// refIdentityOrNewResult (每个线程)第一次调用=identity, 其它调用=总是下面的 new(即当前线程是单例)
// 正确
if (refIdentityOrNewResult == identity) {
refIdentityOrNewResult = new DB(null, null, 0);
}
refIdentityOrNewResult.price += e2.price;
return refIdentityOrNewResult;
});
System.out.println(result2.price + " - " + (result2 == one));
- 3 个参数:默认返回 identity
// 没有元素时作为默认值返回,有元素用于(每个线程)result
DB identity = new DB("种子", null, 1);
DB result3 = list.parallelStream().reduce(identity, (refIdentityOrNewResult, e) -> {
// 等于 2 个参数的方法理解
// 错误
// refIdentityOrNewResult.price += e.price;
// return refIdentityOrNewResult;
// 正确
// DB x = new DB(null, null, 0);
// x.price += refIdentityOrNewResult.price + e.price;
// 正确
if (refIdentityOrNewResult == identity)
refIdentityOrNewResult = new DB(null, null, 0);
refIdentityOrNewResult.price += e.price;
return refIdentityOrNewResult;
}, (r1, r2) -> {
// 此方法用于并行
// 如果第二个做过判断处理 refIdentityOrNewResult 的话这里 r1 r2 就都是 add 里面 new 出来的,每个 new 出来的这里只会合并一次,所以安全
// 正确
// r1.price += r2.price;
// return r1;
// 正确
DB x = new DB(null, null, 0);
x.price += r1.price + r2.price;
return x;
});
System.out.println(result3.price + " - " + (result3 == one));
- groupingBy
根据值分区 - partitioningBy
根据 boolean 分区,就 2 类
// groupingBy 并转换结果
Map<String, List<String>> userIdToHourseListMap = userList.stream()
.filter(Objects::nonNull)
.filter(e -> e.getId() != null)
.filter(e -> e.getHourse() != null)
.collect(Collectors.groupingBy(User::getId,
Collectors.mapping(User::getHourse, Collectors.toList())));
Map<String, IntSummaryStatistics> userIdToHourseListMap = userList.stream()
.filter(Objects::nonNull)
.filter(e -> e.getId() != null)
.filter(e -> e.getScore() != null)
.collect(Collectors.groupingBy(User::getId,
Collectors.summarizingInt(User::getScore)));