Moh*_*han 12 java lambda functional-programming lazy-evaluation java-8
我正在制作我自己的Java版Stream库以获得乐趣.这是我的班级签名:
class Stream<T> {
Supplier<T> head;
Supplier<Stream<T>> tail;
...
}
Run Code Online (Sandbox Code Playgroud)
另外,我编写了一个基本的无限流迭代器,它将基于给定的函数生成无限列表:
public static <T> Stream<T> iterate(T first, Function<T, T> f) {
return new Stream<T>(
() -> first,
() -> {
T nextElem = f.apply(first);
if (nextElem == null) {
return generate(() -> null);
} else {
return iterate(nextElem, f);
}
}
);
}
Run Code Online (Sandbox Code Playgroud)
该函数generate是iterate的一个特例,它永远重复给定的元素.在上面的函数中,我正在生成一个无限序列null来指示流的结束(我不认为我将在流中存储空值).
然后我写了一个reduce函数,其中reduce函数在第二个参数上是惰性的:
public <U> U reduce(U acc, Function<T, Function<Supplier<U>, U>> f) {
System.out.println("REDUCE CALL");
T elem = head.get();
if (elem != null) {
return f.apply(elem).apply(() -> this.tail.get().reduce(acc, f));
} else {
return acc;
}
}
Run Code Online (Sandbox Code Playgroud)
在reduce函数的基础上,我编写了filter函数.
public Stream<T> filter(Predicate<T> p) {
System.out.println("FILTER");
return reduce(generate(() -> null), elem -> acc -> {
if (p.test(elem)) {
return new Stream<>(
() -> elem,
() -> acc.get()
);
} else {
return acc.get();
}
});
}
Run Code Online (Sandbox Code Playgroud)
最后,我继续使用我自己的Stream类:
public static void main(String[] args) {
Stream<Integer> ilist =
Stream
.iterate(1, x -> x + 1)
.filter(x -> x >= 5);
}
Run Code Online (Sandbox Code Playgroud)
但过滤器不是懒惰的!从下面给出的输出中,我认为filter会对元素进行求值,直到找到与给定谓词匹配的元素.
FILTER
REDUCE CALL
REDUCE CALL
REDUCE CALL
REDUCE CALL
REDUCE CALL
Run Code Online (Sandbox Code Playgroud)
我的代码出了什么问题,如何让我的过滤器功能再次变得懒惰?
更新:基于Sweeper的评论,我在没有使用reduce的情况下又进行了过滤功能.
public Stream<T> filter2(Predicate<T> p) {
System.out.println("FILTER2");
T elem = head.get();
if (elem == null) {
return generate(() -> null);
} else {
if (p.test(elem)) {
return new Stream<>(
() -> elem,
() -> this.tail.get().filter2(p)
);
} else {
return this.tail.get().filter2(p);
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这个功能也不是很懒惰.我使用的主要功能的输出filter2如下:
FILTER2
FILTER2
FILTER2
FILTER2
FILTER2
Run Code Online (Sandbox Code Playgroud)
我该如何解决这个问题,有没有办法通过延迟减少实现一个惰性过滤器?
致谢:本练习和上述功能的实现受到Chiusano和Bjarnason的Scala功能编程一书的启发.
在您没有编写的版本中,reduce元素存在但不满足谓词的情况并不是懒惰的.不像在其他情况下那样将递归调用包装在供应商lambda中,而是急切地获取尾部并立即过滤它.
public Stream<T> filter2(Predicate<T> p) {
System.out.println("FILTER2");
T elem = head.get();
if (elem == null) {
return generate(() -> null);
} else {
if (p.test(elem)) {
return new Stream<>(
() -> elem,
() -> this.tail.get().filter2(p)
);
} else {
return this.tail.get().filter2(p); // <- not lazy!
}
}
}
Run Code Online (Sandbox Code Playgroud)
您需要的是一种创建流的方法,以便决定它是否为空,直到稍后.
public class Stream<T> {
// private constructor(s)
public static <T> Stream<T> empty() { /* ... */ }
public static <T> Stream<T> cons(Supplier<T> head, Supplier<Stream<T> tail) { /* ... */ }
public static <T> Stream<T> lazy(Supplier<Stream<T>> stream) { /* ... */ }
public Stream<T> filter(Predicate<T> p) {
if ( /* this stream is empty */ ) {
return Stream.empty();
} else if ( /* head element satisfies predicate */ ) {
// lazily filter tail, cons head element
} else {
return Stream.lazy(() -> this.tail.get().filter(p));
}
}
}
Run Code Online (Sandbox Code Playgroud)
沿着那条线的东西.
| 归档时间: |
|
| 查看次数: |
226 次 |
| 最近记录: |