如何将FibSupplier变为通用的FiniteSupplier?

时间:2014-02-22 13:00:59

标签: java generics iterator java-8 java-stream

考虑到我有以下课程:

public class Problem2 extends Problem<Integer> {
    @Override
    public void run() {
        result = toList(new FibSupplier(i -> (i <= 4_000_000)))
                .stream()
                .filter(i -> (i % 2 == 0))
                .mapToInt(i -> i)
                .sum();
    }

    @Override
    public String getName() {
        return "Problem 2";
    }

    private static <E> List<E> toList(final Iterator<E> iterator) {
        List<E> list = new ArrayList<>();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }
        return list;
    }

    private class FibSupplier implements Iterator<Integer> {
        private final IntPredicate hasNextPredicate;

        private int beforePrevious = 0;
        private int previous = 1;

        public FibSupplier(final IntPredicate hasNextPredicate) {
            this.hasNextPredicate = hasNextPredicate;
        }

        @Override
        public boolean hasNext() {
            return hasNextPredicate.test(previous);
        }

        @Override
        public Integer next() {
            int result = beforePrevious + previous;
            beforePrevious = previous;
            previous = result;
            return result;
        }
    } 
}

如果你看一下FibSupplier你可以看到它暴露了一个普遍的问题,即使它在这里有一个专门的实现,我设法提取的是:

  • 它有Predicate
  • 它有初始变量。
  • 它有一个需要由谓词测试的变量。
  • 它有自定义next()方法。

我试图概括这一点,但请注意我现在使用的是通用版本而不是专门的整数版本:

public class FiniteSupplier<E> implements Iterator<E> {
    private final Predicate<E> predicate;

    public FiniteSupplier(final Predicate<E> predicate) {
        this.predicate = predicate;
    }

    @Override
    public boolean hasNext() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public E next() {
        throw new UnsupportedOperationException("Not supported yet.");
    }  
}

我希望能够使用FiniteSupplier来呼叫predicate,但是现在我真的不知道如何实现我设法提取的其他要求。我理解可以通过扩展FiniteSupplier并使其成为抽象来完成,但这是正确的方法吗?

1 个答案:

答案 0 :(得分:0)

方法test(int/Integer)可用作Predicate<Integer>IntPredicate。编译器执行转换:

IntPredicate ip = (i) -> i>0;
Predicate<Integer> pi = (i) -> i>0;
Predicate<Integer> ip2pi = ip::test;
IntPredicate pi2ip = pi::test;

但是你不能投射这两种类型,因为它们不可分配。 IntPredicate不会扩展谓词。

所以在创建FibSupplier时只需使用:: test:

new FibSupplier(p) => new FibSupplier(p::test) 

或者在构造函数中执行此操作。我引入了一个新的抽象类型FiniteIntSupplier,它带有一个额外的构造函数,它接受一个I​​ntSupplier并将其转换为一般供应商:

public FiniteIntSupplier(IntPredicate p) {
  this(p::test);
}