Collections 如何实现Java8流fluent API和延迟计算
我想找出一个相当于Java 8的简单实现,它允许我探索延迟计算的查询算法的开发(例如Collections 如何实现Java8流fluent API和延迟计算,collections,lambda,java-8,java-stream,higher-order-functions,Collections,Lambda,Java 8,Java Stream,Higher Order Functions,我想找出一个相当于Java 8的简单实现,它允许我探索延迟计算的查询算法的开发(例如map(),filter(),reduce(),等等)注意:我的目标不是实现比Stream更好的解决方案。另一方面,我唯一的目标是理解流的内部结构 然而,我发现的每个实现都是基于Iterable,如以下答案中提供的解决方案: 然而,我对这些解决方案并不满意,因为: 它们太冗长了 对于新的查询方法,它们不灵活。包含新的查询方法需要进行结构修改 尽管有查询参数,但它们没有利用Java8的新特性,例如:第一类
map()
,filter()
,reduce()
,等等)注意:我的目标不是实现比Stream更好的解决方案。另一方面,我唯一的目标是理解流的内部结构
然而,我发现的每个实现都是基于Iterable
,如以下答案中提供的解决方案:
流
上使用的拆分器
方法Spliterator
被设计为允许分区和并行处理,但我认为它独特的迭代器方法(boolean-tryAdvance(Consumer)
)可以被利用到比上面列出的新的替代方法。此外,作为:
拆分器
是一个更好的迭代器
,即使没有并行性。(它们通常更容易写,也更难出错。)
那么,是否有可能开发一个更可读、更简单、简洁和灵活的查询API实现,该API是基于流
的相同原理(除了并行处理部分)进行惰性计算的
如果是,你怎么做?我希望看到比上面列出的实现更简单的实现,如果可能的话,利用新的Java8特性
要求:
- 不要重用Java8API中的现有方法
- 并行处理功能超出了此问题的范围
- 如果可能,最好不要使用
方法Iterable
map()
,filter()
,reduce()
,call()
,bind()
,等等
选择答案:目前我认为这是我的选择,而不是因为后者不允许实现
findAny()
或findFirst()
而不通过dataSrc的forEach()
完全遍历整个元素。但是,我认为,由于基于forEach()
的方法,通过使用函数式编程和利用Java 8默认方法,我们可以实现一个简短而干净的查询API延迟计算解决方案,从而减少迭代代码的开销,该迭代代码用于调解对数据结构内部的访问,如所述。例如,在下面的Queryable
类型中检查如何轻松实现map()
和forEach()
方法,然后您可以这样使用它:
List<String> data = Arrays.asList("functional", "super", "formula");
Queryable.of(data) // <=> data.stream().
.map(String::length)
.forEach(System.out::println);
通过使用函数式编程并利用Java8默认方法,我们可以实现一个简短而干净的查询API延迟计算解决方案。例如,在下面的Queryable
类型中检查如何轻松实现map()
和forEach()
方法,然后您可以这样使用它:
List<String> data = Arrays.asList("functional", "super", "formula");
Queryable.of(data) // <=> data.stream().
.map(String::length)
.forEach(System.out::println);
实现无状态操作子集非常容易,无需短路支持。您只需要注意始终坚持内部迭代。基本构造块是forEach操作,它可以为每个输入元素执行给定的操作。forEach
方法的主体是唯一在不同阶段发生变化的东西。因此,我们可以使用abstractforEach
方法创建抽象类,也可以接受实际上是forEach
主体的函数。我将坚持第二种方法:
public final class MyStream<T> {
private final Consumer<Consumer<T>> action;
public MyStream(Consumer<Consumer<T>> action) {
this.action = action;
}
public void forEach(Consumer<T> cons) {
action.accept(cons);
}
}
现在,让我们使用forEach
创建一些终端操作:
public T reduce(T identity, BinaryOperator<T> op) {
class Box {
T val = identity;
}
Box b = new Box();
forEach(e -> b.val = op.apply(b.val, e));
return b.val;
}
public Optional<T> reduce(BinaryOperator<T> op) {
class Box {
boolean isPresent;
T val;
}
Box b = new Box();
forEach(e -> {
if(b.isPresent) b.val = op.apply(b.val, e);
else {
b.val = e;
b.isPresent = true;
}
});
return b.isPresent ? Optional.empty() : Optional.of(b.val);
}
public long count() {
return map(e -> 1L).reduce(0L, Long::sum);
}
public Optional<T> maxBy(Comparator<T> cmp) {
return reduce(BinaryOperator.maxBy(cmp));
}
public Optional<T> minBy(Comparator<T> cmp) {
return reduce(BinaryOperator.minBy(cmp));
}
等等。这种实现非常简单,但非常接近实际的流API。当然,当您添加短路、并行流、原始专门化和更多有状态操作时,事情会复杂得多
请注意,与Stream API不同,此MyStream
可以多次重复使用:
MyStream<Integer> range = range(0, 10);
range.forEach(System.out::println);
range.forEach(System.out::println); // works perfectly
MyStream范围=范围(0,10);
range.forEach(System.out::println);
range.forEach(System.out::println);//完美地工作
实现无状态操作子集非常容易,无需短路支持。您只需要注意始终坚持内部迭代。基本构造块是forEach操作,它可以为每个输入元素执行给定的操作。forEach
方法的主体是唯一在不同阶段发生变化的东西。因此,我们可以使用abstractforEach
方法创建抽象类,也可以接受实际上是forEach
主体的函数。我将坚持第二种方法:
public final class MyStream<T> {
private final Consumer<Consumer<T>> action;
public MyStream(Consumer<Consumer<T>> action) {
this.action = action;
}
public void forEach(Consumer<T> cons) {
action.accept(cons);
}
}
现在,让我们使用forEach
创建一些终端操作:
public T reduce(T identity, BinaryOperator<T> op) {
class Box {
T val = identity;
}
Box b = new Box();
forEach(e -> b.val = op.apply(b.val, e));
return b.val;
}
public Optional<T> reduce(BinaryOperator<T> op) {
class Box {
boolean isPresent;
T val;
}
Box b = new Box();
forEach(e -> {
if(b.isPresent) b.val = op.apply(b.val, e);
else {
b.val = e;
b.isPresent = true;
}
});
return b.isPresent ? Optional.empty() : Optional.of(b.val);
}
public long count() {
return map(e -> 1L).reduce(0L, Long::sum);
}
public Optional<T> maxBy(Comparator<T> cmp) {
return reduce(BinaryOperator.maxBy(cmp));
}
public Optional<T> minBy(Comparator<T> cmp) {
return reduce(BinaryOperator.minBy(cmp));
}
等等。苏
MyStream<Integer> range = range(0, 10);
range.forEach(System.out::println);
range.forEach(System.out::println); // works perfectly