Java 过滤函数不懒惰

Java 过滤函数不懒惰,java,lambda,java-8,functional-programming,lazy-evaluation,Java,Lambda,Java 8,Functional Programming,Lazy Evaluation,为了好玩,我正在制作自己版本的Java流库。这是我的班级签名: class Stream<T> { Supplier<T> head; Supplier<Stream<T>> tail; ... } 在reduce函数的基础上,我编写了filter函数 public Stream<T> filter(Predicate<T> p) { System.out.println("FILTER");

为了好玩,我正在制作自己版本的Java流库。这是我的班级签名:

class Stream<T> {
  Supplier<T> head;
  Supplier<Stream<T>> tail;
  ...
}
在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();
      }
    });
  }
我的代码出了什么问题,如何使我的过滤器函数再次变懒

更新:根据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);
      }
    }
  }
我如何解决这个问题,有没有办法通过一个懒惰的reduce实现一个懒惰的过滤器


确认:此练习和上述函数的实现受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!
        }
    }
}
公共流过滤器2(谓词p){
System.out.println(“过滤器2”);
T elem=head.get();
if(elem==null){
返回生成(()->null);
}否则{
如果(p.test(elem)){
返回新流(
()->元素,
()->this.tail.get().filter2(p)
);
}否则{

返回此.tail.get().filter2(p);//
filter
并不懒惰,因为
reduce
并不懒惰。我认为你不能用一个非懒惰的
reduce
@Sweeper实现一个懒惰的
filter
。@Sweeper有没有办法让reduce变得懒惰?根本不用reduce呢?@Sweeper我试过了。更新请看帖子。我明白了。你会怎么让它变得懒惰?返回to在绘图板上,找出一种不同的设计,让您创建一个流,这样您就可以推迟决定它是否为空。我读的Scala代码更容易理解(使用Lisp-like
Cons
)。当然,我会尝试不同的设计!我建议提供三种创建流的基本方法(无论是构造函数还是静态工厂方法):一个不接受参数并返回空流,一个接受头部和尾部并返回非空流,另一个接受
供应商
并返回可能的空流,为了懒惰,将决策推迟到以后。我理解前两个工厂方法的目的,但第三个方法是什么d工厂方法用于?我被这句话弄糊涂了:“另一个接受
供应商
并返回可能为空的流。”
  public static void main(String[] args) {
    Stream<Integer> ilist =
            Stream
              .iterate(1, x -> x + 1)
              .filter(x -> x >= 5);
  }
FILTER
REDUCE CALL
REDUCE CALL
REDUCE CALL
REDUCE CALL
REDUCE CALL
  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);
      }
    }
  }
FILTER2
FILTER2
FILTER2
FILTER2
FILTER2
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!
        }
    }
}
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));
        }
    }
}