如何根据谓词过滤 Iterable?

3 java iterable predicate java-8

我想使用Iterable<String>和 谓词来执行一个字符串列表过滤函数来选择要保留的字符串,其他字符串必须从列表中删除,但我并没有低估如何进行删除。

static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {
    for (T s: it) {
        if (pred.test(s)==false) {
            // what to do here?
        }
    }
    return ...;
}
Run Code Online (Sandbox Code Playgroud)

对于此输入:

{"a","","b",""}
Run Code Online (Sandbox Code Playgroud)

我预计

{"a","b"}
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 5

An代表根据请求Iterable提供的能力。Iterator因此,要使用过滤逻辑装饰现有的可迭代对象,您必须实现装饰Iterator.

static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {
    return () -> new Iterator<T>() {
        Iterator<T> sourceIterator = it.iterator();
        T current;
        boolean hasCurrent;

        @Override
        public boolean hasNext() {
            while(!hasCurrent) {
                if(!sourceIterator.hasNext()) {
                    return false;
                }
                T next = sourceIterator.next();
                if(pred.test(next)) {
                    current = next;
                    hasCurrent = true;
                }
            }
            return true;
        }

        @Override
        public T next() {
            if(!hasNext()) throw new NoSuchElementException();
            T next = current;
            current = null;
            hasCurrent = false;
            return next;
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

你可以通过它进行测试

List<String> original = new ArrayList<>();
Collections.addAll(original, "foo", "bar", "baz");
Iterable<String> filter = select(original, s -> s.startsWith("b"));
System.out.println(String.join(", ", filter));
original.removeIf(s -> !s.endsWith("r"));
System.out.println(String.join(", ", filter));
Run Code Online (Sandbox Code Playgroud)

实现这样的 时最大的挑战Iterator是提供两种方法hasNextnext具有正确的语义,而不能保证调用者将如何调用它们,即您不能假设它永远不会调用hasNext()两次,也next()不能假设它总是用前面hasNext().

使用 Stream API 可以更轻松地实现相同的逻辑:

static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {
    return () -> StreamSupport.stream(it.spliterator(), false)
        .filter(pred).iterator();
}
Run Code Online (Sandbox Code Playgroud)