Java小技巧:100行代码实现Stream基本功能

本文的内容是对《计算机程序的构造和解释(SICP)》3.5 节描述的流的 Java 实现,希望能提供一些启发,仅用于学习,不可用于生产环境。

网络上已经有很多对 Java 8 Stream,RxJava 的流实现的分析,学习后可以对那些API有更深的理解。而本文侧重使用尽可能少的代码从零开始来实现流以及相关的操作(例如,filter、map、reduce),来加深对流的理解。

1. 基本定义

public class Stream<T> {
     
    private static final Stream<?> EMPTY = new Stream<>(null, () -> null); //空的流
    private T value;                            //每个流节点对应的值
    private Supplier<Stream<T>> nextSupplier;   //流的下一个节点的提供者(这里实现懒求值的效果)
    private Stream<T> nextStream;               //下一个流节点的缓存

    public Stream(T value, Supplier<Stream<T>> nextSupplier) {
     
        this.value = value;
        this.nextSupplier = nextSupplier;
    }
    /* 获取下一个流节点,如果之前没求值,就对其 */
    public Stream<T> next() {
     
        if (nextStream == null) {
     
            nextStream = nextSupplier.get();
        }
        return nextStream;
    }
    /* 获取当前流节点的值 */
    public T value() {
     
        return value;
    }
}

2. 各个流方法实现

//1. 获取流的从0开始的第index个元素。
public T ref(int index) {
     
    Stream<T> stream = this;
    for (int i = 0; i < index; i++) {
     
        stream = stream.next();
        if (stream == null || stream == EMPTY) {
     
            throw new IndexOutOfBoundsException(String.format("index[%d] is out of bounds", index));
        }
    }
    return stream.value;
}

//2. 对当前流进行迭代
public void forEach(Consumer<T> consumer) {
     
    Stream<T> stream = this;
    while (stream != null && stream != EMPTY) {
     
        consumer.accept(stream.value);
        stream = stream.next();
    }
}

//3. 将当前流映射为 R 类型的流
public <R> Stream<R> map(Function<T, R> mapper) {
     
    return new Stream<>(mapper.apply(value), () -> nextSupplier.get().map(mapper));
}

//4. 根据给定的断言得到根据该断言过滤的流对象
public Stream<T> filter(Predicate<T> predicate) {
     
    Stream<T> stream = this;
    while (stream != null && stream != EMPTY) {
     
        if (predicate.test(stream.value)) {
     
            Supplier<Stream<T>> supplier = stream.nextSupplier;
            return new Stream<>(stream.value, () -> supplier.get().filter(predicate));
        } else {
     
            stream = stream.next();
        }
    }
    return (Stream<T>) EMPTY;
}

//5. 获取前n个元素的流对象
public Stream<T> takeFirst(int n) {
     
    return n > 0
            ? new Stream<>(value, () -> takeFirst(n - 1))
            : (Stream<T>) EMPTY;
}

//6. 根据给定和归约方法来对流进行归约
public <R> R reduce(R seed, BiFunction<T, R, R> biFunction) {
     
    Stream<T> stream = this;
    while(stream != null && stream != EMPTY){
     
        seed = biFunction.apply(stream.value, seed);
        stream = stream.next();
    }
    return seed;
}

3. 常见的工具方法

//产生从 start 开始的无限整数流
public static Stream<Integer> range(int start) {
     
    return new Stream<>(start, () -> range(start + 1));
}

//产生从 start(包括) 到 end(不包括) 的有限整数流
public static Stream<Integer> range(int start, int end) {
     
    return start < end
            ? new Stream<>(start, () -> range(start + 1, end))
            : (Stream<Integer>) EMPTY;
}

//产生 obj 对象的无限流
public static <T> Stream<T> objects(T obj) {
     
    return new Stream<>(obj, () -> objects(obj));
}

//从一个可迭代对象(例如List、Set)来产生流
public static <T> Stream<T> fromIterable(Iterable<T> iterable) {
     
    return fromIterator(iterable.iterator());
}

//从一个迭代器对象来产生流
public static <T> Stream<T> fromIterator(Iterator<T> iterator) {
     
    return iterator.hasNext()
            ? new Stream<>(iterator.next(), () -> fromIterator(iterator))
            : (Stream<T>) EMPTY;
}

4. 示例

//1. 或许从1到100数字流,按偶数过滤,添加前缀后,收集到List中
LinkedList<String> numberStrList = Stream.range(1, 101)
        .filter(i -> i % 2 == 0)
        .map(i -> "number:" + i)
        .reduce(new LinkedList<>(), (s, strings) -> {
     
            strings.add(s);
            return strings;
        });

//2. 将一个集合转换为流,按偶数过滤,求和并返回
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
Integer evenCount = Stream.fromIterable(integers)
        .filter(i -> i % 2 == 0)
        .reduce(0, Integer::sum);
System.out.println("even:" + evenCount);

//3. 斐波那契数列
//定义数列生成函数
private Stream<Integer> fibGen(int a, int b) {
     
    return new Stream<>(a, () -> fibGen(b, a + b));
}
//得到斐波那契数列的无限流
Stream<Integer> fibStream = fibGen(1, 1);
//获取并打印第10个斐波那契数
System.out.println("fib 10:" + fibStream.ref(9));//输出 fib 10:55
//计算前10个斐波那契数的和
Integer sum = fibStream.takeFirst(10)
        .reduce(0, Integer::sum);
System.out.println("fib sum:" + sum);//输出 fib sum:143

5. 整个类实现

public class Stream<T> {
     
    public static final Stream<?> EMPTY = new Stream<>(null, () -> null);
    private T value;
    private Supplier<Stream<T>> nextSupplier;
    private Stream<T> nextStream;

    public static Stream<Integer> range(int start) {
     
        return new Stream<>(start, () -> range(start + 1));
    }

    public static Stream<Integer> range(int start, int end) {
     
        return start < end
                ? new Stream<>(start, () -> range(start + 1, end))
                : (Stream<Integer>) EMPTY;
    }

    public static <T> Stream<T> objects(T obj) {
     
        return new Stream<>(obj, () -> objects(obj));
    }

    public static <T> Stream<T> fromIterable(Iterable<T> iterable) {
     
        return fromIterator(iterable.iterator());
    }

    public static <T> Stream<T> fromIterator(Iterator<T> iterator) {
     
        return iterator.hasNext()
                ? new Stream<>(iterator.next(), () -> fromIterator(iterator))
                : (Stream<T>) EMPTY;
    }

    public Stream(T value, Supplier<Stream<T>> nextSupplier) {
     
        this.value = value;
        this.nextSupplier = Objects.requireNonNull(nextSupplier);
    }

    public Stream<T> next() {
     
        if (nextStream == null && nextSupplier != null) {
     
            nextStream = nextSupplier.get();
        }
        return nextStream;
    }

    public T value() {
     
        return value;
    }

    public T ref(int index) {
     
        Stream<T> stream = this;
        for (int i = 0; i < index; i++) {
     
            stream = stream.next();
            if (stream == null || stream == EMPTY) {
     
                throw new IndexOutOfBoundsException(String.format("index[%d] is out of bounds", index));
            }
        }
        return stream.value;
    }

    public void forEach(Consumer<T> consumer) {
     
        Stream<T> stream = this;
        while (stream != null && stream != EMPTY) {
     
            consumer.accept(stream.value);
            stream = stream.next();
        }
    }

    public <R> Stream<R> map(Function<T, R> mapper) {
     
        return this == EMPTY ? (Stream<R>) EMPTY : new Stream<>(mapper.apply(value), () -> nextSupplier.get().map(mapper));
    }

    public Stream<T> filter(Predicate<T> predicate) {
     
        Stream<T> stream = this;
        while (stream != null && stream != EMPTY) {
     
            if (predicate.test(stream.value)) {
     
                Supplier<Stream<T>> supplier = stream.nextSupplier;
                return new Stream<>(stream.value, () -> supplier.get().filter(predicate));
            } else {
     
                stream = stream.next();
            }
        }
        return (Stream<T>) EMPTY;
    }

    public Stream<T> takeFirst(int n) {
     
        return n > 0 && this != EMPTY
                ? new Stream<>(value, () -> nextSupplier.get().takeFirst(n - 1))
                : (Stream<T>) EMPTY;
    }

    public <R> R reduce(R seed, BiFunction<T, R, R> biFunction) {
     
        Stream<T> stream = this;
        while (stream != null && stream != EMPTY) {
     
            seed = biFunction.apply(stream.value, seed);
            stream = stream.next();
        }
        return seed;
    }
}

你可能感兴趣的:(Java,java,stream,lambda,函数式编程)