背景
在《java中手写一个简单的Stream流你会吗?》中我们创建了简单的流的构造,转换,过滤,遍历操作,在第二版中,我们新增了reduce简化和collect收集操作,并进行了多次验证,具体代码如下:
代码
package org.example.demo;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;
/**
* 实现一个简单流
*/
public class Demo09<T> {
public static void main(String[] args) {
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 1, 2, 3, 4);
System.out.println("基础流操作展示:");
Demo09.of(integerList)
.filter(integer -> integer > 3)
.map(integer -> integer + "转换后")
.forEach(System.out::println);
System.out.println("------------------");
System.out.println("简化流操作示例:");
System.out.println(Demo09.of(integerList).reduce(Integer::max, 0));
System.out.println("------------------");
System.out.println("收集流操作示例一:HashSet收集");
HashSet<Object> set = Demo09.of(integerList).collect(HashSet::new, HashSet::add);
System.out.println(set);
System.out.println("------------------");
System.out.println("收集流操作示例二-:StringBuilder收集");
StringBuilder stringBuilder = Demo09.of(integerList).collect(StringBuilder::new, StringBuilder::append);
System.out.println(stringBuilder.toString());
System.out.println("------------------");
System.out.println("收集流操作示例三-StringJoiner收集:");
StringJoiner joiner = Demo09.of(integerList).collect(() -> new StringJoiner("-"), (stringJoiner, t) -> stringJoiner.add(String.valueOf(t)));
System.out.println(joiner.toString());
System.out.println("------------------");
System.out.println("收集流操作示例四-StringJoiner收集优化:");
StringJoiner stringJoiner = Demo09.of(integerList).map(String::valueOf).collect(() -> new StringJoiner("--"), StringJoiner::add);
System.out.println(stringJoiner.toString());
System.out.println("------------------");
System.out.println("收集流操作示例五-map收集:");
HashMap<Integer, Integer> hashMap1 = Demo09.of(integerList).collect(HashMap::new, (map, t) -> {
// 注意这里是 没有key的时候 设置1
if (!map.containsKey(t)) {
map.put(t, 1);
} else {
// 有值得时候 取出里面的值 然后在基础上加1
Integer time = map.get(t);
map.put(t, time + 1);
}
});
System.out.println(hashMap1);
System.out.println("------------------");
System.out.println("收集流操作示例六-map收集优化:");
/**
* map.computeIfAbsent(k,v)
* computeIfAbsent方法接受一个key和一个函数对象 value
* computeIfAbsent作用:如果key存在,那么返回key的值
* 如果key不存在,那么按照函数对象,创建一个value,并将key和value存入map中
* getAndIncrement是AtomicInteger的方法,调用这个方法的作用,是将我们从computeIfAbsent方法中获取到的值,增加1
* 这里重点需要理解的是getAndIncrement是AtomicInteger的方法
*
* 注意:k->new AtomicInteger(),这里我们使用的lambda而不是AtomicInteger::new
* 我们这里用的是k 不是t,如果使用的是AtomicInteger::new会默认使用AtomicInteger的有参构造,导致数据异常,需要谨慎
*/
HashMap<Integer, AtomicInteger> hashMap2 = Demo09.of(integerList).collect(HashMap::new, (map, t) -> map.computeIfAbsent(t, k->new AtomicInteger()).getAndIncrement());
System.out.println(hashMap2);
}
/**
* 需求:
* 1.通过of方法实现,集合转换成流
* 2.通过filter方法,实现集合元素过滤
* 3.通过map方法,实现集合元素转换
* 4.通过foreach方法,实现集合元素遍历
*/
// 创建一个私有的构造器
private Demo09(Collection<T> collection) {
this.collection = collection;
}
// 创建一个集合属性
private Collection<T> collection;
// 相当于一个工厂方法
public static <T> Demo09<T> of(Collection<T> collection) {
return new Demo09<T>(collection);
}
private Demo09<T> filter(Predicate<T> predicate) {
List<T> filterCollection = new ArrayList<>();
// 这里的操作 应该是对自己的集合进行,所以要对collection进行操作
for (T t : collection) {
if (predicate.test(t)) {
filterCollection.add(t);
}
}
return new Demo09<>(filterCollection);
}
private <R> Demo09<R> map(Function<T, R> function) {
List<R> mapCollection = new ArrayList<>();
for (T t : collection) {
R result = function.apply(t);
mapCollection.add(result);
}
return new Demo09<>(mapCollection);
}
private void forEach(Consumer<T> consumer) {
for (T t : collection) {
consumer.accept(t);
}
}
/**
* 进行简化操作,比如:找最大值,最小值,平均值等
*/
private T reduce(BinaryOperator<T> binaryOperator, T init) {
// 这种需要多个参数比较的形式,我们需要有个初始的参考值
// 与此同时 我们需要一个在外部的 用来存储最终结果的值
T p = init;
for (T t : collection) {
// 将p和 t 进行处理 得到的结果保存到p 然后继续用 p和下一个t比较 直到最后的结果获取到
p = binaryOperator.apply(t, p);
}
return p;
}
/**
* 简单流之数据收集
* 这里注意泛型的位置在返回值之前
*/
private <C> C collect(Supplier<C> supplier, BiConsumer<C, T> biConsumer) {
// 创建一个容器
C c = supplier.get();
// 将向容器中添加元素的操作
for (T t : collection) {
biConsumer.accept(c, t);
}
return c;
}
}