在Java 8中,你可以使用方法引用来过滤流,例如:

Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();

是否有一种方法可以创建一个方法引用,它是现有方法引用的否定,例如:

long nonEmptyStrings = s.filter(not(String::isEmpty)).count();

我可以创建如下所示的not方法,但我想知道JDK是否提供了类似的东西。

static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }

当前回答

另一种选择是在明确的上下文中使用lambda强制转换为一个类:

public static class Lambdas {
    public static <T> Predicate<T> as(Predicate<T> predicate){
        return predicate;
    }

    public static <T> Consumer<T> as(Consumer<T> consumer){
        return consumer;
    }

    public static <T> Supplier<T> as(Supplier<T> supplier){
        return supplier;
    }

    public static <T, R> Function<T, R> as(Function<T, R> function){
        return function;
    }

}

... 然后静态导入实用程序类:

stream.filter(as(String::isEmpty).negate())

其他回答

您可以使用Eclipse集合中的谓词

MutableList<String> strings = Lists.mutable.empty();
int nonEmptyStrings = strings.count(Predicates.not(String::isEmpty));

如果你不能改变List中的字符串:

List<String> strings = new ArrayList<>();
int nonEmptyStrings = ListAdapter.adapt(strings).count(Predicates.not(String::isEmpty));

如果你只需要String.isEmpty()的否定,你也可以使用StringPredicates.notEmpty()。

注意:我是Eclipse Collections的贡献者。

谓词#否定不是你要找的吗?

谓词。不是(…)

java-11提供了一个新方法Predicate#not

所以你可以对reference方法求反:

Stream<String> s = ...;
long nonEmptyStrings = s.filter(Predicate.not(String::isEmpty)).count();

你可以用long emptyStrings = s.filter(s->!s. isempty ()).count();

有一种方法可以组合与当前方法引用相反的方法引用。参见下面@vlasec的回答,该回答展示了如何显式地将方法引用转换为Predicate,然后使用否定函数进行转换。这是其他几种不太麻烦的方法中的一种。

反义词:

Stream<String> s = ...;
int emptyStrings = s.filter(String::isEmpty).count();

是这样的:

Stream<String> s = ...;
int notEmptyStrings = s.filter(((Predicate<String>) String::isEmpty).negate()).count()

或:

Stream<String> s = ...;
int notEmptyStrings = s.filter( it -> !it.isEmpty() ).count();

就我个人而言,我更喜欢后一种技术,因为我发现它比冗长的显式强制转换然后求反更清晰。

还可以创建一个谓词并重用它:

Predicate<String> notEmpty = (String it) -> !it.isEmpty();

Stream<String> s = ...;
int notEmptyStrings = s.filter(notEmpty).count();

或者,如果有一个集合或数组,只需使用简单的for循环,开销更少,并且*可能更快:

int notEmpty = 0;
for(String s : list) if(!s.isEmpty()) notEmpty++;

*如果你想知道哪个更快,那么使用JMH http://openjdk.java.net/projects/code-tools/jmh,避免手动基准代码,除非它避免所有JVM优化-参见Java 8:流与集合的性能

**我因为建议for循环技术更快而受到批评。它消除了流的创建,它消除了使用另一个方法调用(谓词为负函数),并且它消除了临时累加器列表/计数器。最后一个构造保留的一些东西可能会让它更快。

我确实认为它更简单、更好,即使不是更快。如果这项工作需要锤子和钉子,不要带电锯和胶水!我知道你们有些人对此有异议。

愿望清单:我希望看到Java流函数的发展,现在Java用户更熟悉它们了。例如,Stream中的'count'方法可以接受Predicate,这样就可以像这样直接完成:

Stream<String> s = ...;
int notEmptyStrings = s.count(it -> !it.isEmpty());

or

List<String> list = ...;
int notEmptyStrings = lists.count(it -> !it.isEmpty());