Java 如何否定方法引用谓词
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21488056/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to negate a method reference predicate
提问by assylias
In Java 8, you can use a method reference to filter a stream, for example:
在 Java 8 中,您可以使用方法引用来过滤流,例如:
Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();
Is there a way to create a method reference that is the negation of an existing one, i.e. something like:
有没有办法创建一个方法引用,它是现有引用的否定,即:
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
I could create the not
method like below but I was wondering if the JDK offered something similar.
我可以创建not
如下所示的方法,但我想知道 JDK 是否提供了类似的方法。
static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }
采纳答案by Anton Balaniuc
Predicate.not( … )
Predicate.not( … )
java-11offers a new method Predicate#not
java-11提供了一种新方法Predicate#not
So you can negate the method reference:
所以你可以否定方法引用:
Stream<String> s = ...;
long nonEmptyStrings = s.filter(Predicate.not(String::isEmpty)).count();
回答by Marco13
Shouldn't Predicate#negate
be what you are looking for?
不Predicate#negate
应该是你要找的吗?
回答by The Coordinator
There is a way to compose a method reference that is the opposite of a current method reference. See @vlasec's answer below that shows how by explicitly casting the method reference to a Predicate
and then converting it using the negate
function. That is one way among a few other not too troublesome ways to do it.
有一种方法可以组合与当前方法引用相反的方法引用。请参阅下面的@vlasec 的答案,该答案显示了如何将方法引用显式转换为 a Predicate
,然后使用该negate
函数对其进行转换。这是其他一些不太麻烦的方法之一。
The opposite of this:
与此相反:
Stream<String> s = ...;
int emptyStrings = s.filter(String::isEmpty).count();
is this:
这是:
Stream<String> s = ...;
int notEmptyStrings = s.filter(((Predicate<String>) String::isEmpty).negate()).count()
or this:
或这个:
Stream<String> s = ...;
int notEmptyStrings = s.filter( it -> !it.isEmpty() ).count();
Personally, I prefer the later technique because I find it clearer to read it -> !it.isEmpty()
than a long verbose explicit cast and then negate.
就我个人而言,我更喜欢后一种技术,因为我发现它it -> !it.isEmpty()
比冗长的显式转换然后否定更清晰。
One could also make a predicate and reuse it:
还可以创建一个谓词并重用它:
Predicate<String> notEmpty = (String it) -> !it.isEmpty();
Stream<String> s = ...;
int notEmptyStrings = s.filter(notEmpty).count();
Or, if having a collection or array, just use a for-loop which is simple, has less overhead, and *might be **faster:
或者,如果有一个集合或数组,只需使用一个简单的 for 循环,开销更少,并且 * 可能 ** 更快:
int notEmpty = 0;
for(String s : list) if(!s.isEmpty()) notEmpty++;
*If you want to know what is faster, then use JMH http://openjdk.java.net/projects/code-tools/jmh, and avoid hand benchmark code unless it avoids all JVM optimizations — see Java 8: performance of Streams vs Collections
*如果你想知道什么更快,那么使用 JMH http://openjdk.java.net/projects/code-tools/jmh,并避免手工基准代码,除非它避免了所有 JVM 优化——请参阅Java 8:流的性能与集合
**I am getting flak for suggesting that the for-loop technique is faster. It eliminates a stream creation, it eliminates using another method call (negative function for predicate), and it eliminates a temporary accumulator list/counter. So a few things that are saved by the last construct that might make it faster.
**我因为建议 for 循环技术更快而受到抨击。它消除了流创建,消除了使用另一个方法调用(谓词的负函数),并且消除了临时累加器列表/计数器。因此,最后一个构造保存的一些东西可能会使其更快。
I do think it is simpler and nicer though, even if not faster. If the job calls for a hammer and a nail, don't bring in a chainsaw and glue! I know some of you take issue with that.
我确实认为它更简单,更好,即使不是更快。如果工作需要锤子和钉子,不要带电锯和胶水!我知道你们中的一些人对此有异议。
wish-list: I would like to see Java Stream
functions evolve a bit now that Java users are more familiar with them. For example, the 'count' method in Stream could accept a Predicate
so that this can be done directly like this:
愿望清单:我希望看到 JavaStream
函数有所改进,因为 Java 用户对它们更加熟悉了。例如,Stream 中的 'count' 方法可以接受 a Predicate
,这样就可以像这样直接完成:
Stream<String> s = ...;
int notEmptyStrings = s.count(it -> !it.isEmpty());
or
List<String> list = ...;
int notEmptyStrings = lists.count(it -> !it.isEmpty());
回答by davidillsley
I'm planning to static import the following to allow for the method reference to be used inline:
我计划静态导入以下内容以允许内联使用方法引用:
public static <T> Predicate<T> not(Predicate<T> t) {
return t.negate();
}
e.g.
例如
Stream<String> s = ...;
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
Update: Starting from Java-11, the JDK offers a similar solutionbuilt-in as well.
回答by Jose Alban
Building on other's answers and personal experience:
基于其他人的答案和个人经验:
Predicate<String> blank = String::isEmpty;
content.stream()
.filter(blank.negate())
回答by Askar Kalykov
Another option is to utilize lambda casting in non-ambiguous contexts into one class:
另一种选择是在非歧义上下文中使用 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;
}
}
... and then static import the utility class:
...然后静态导入实用程序类:
stream.filter(as(String::isEmpty).negate())
回答by Vlasec
Predicate
has methods and
, or
and negate
.
Predicate
有方法and
,or
和negate
。
However, String::isEmpty
is not a Predicate
, it's just a String -> Boolean
lambda and it could still become anything, e.g. Function<String, Boolean>
. Type inferenceis what needs to happen first. The filter
method infers type implicitly. But if you negate it before passing it as an argument, it no longer happens. As @axtavt mentioned, explicitinference can be used as an ugly way:
但是,String::isEmpty
不是Predicate
,它只是一个String -> Boolean
lambda,它仍然可以变成任何东西,例如Function<String, Boolean>
。类型推断是需要首先发生的事情。该filter
方法隐式推断类型。但是如果你在将它作为参数传递之前否定它,它就不再发生了。正如@axtavt 提到的,显式推理可以用作一种丑陋的方式:
s.filter(((Predicate<String>) String::isEmpty).negate()).count()
There are other ways advised in other answers, with static not
method and lambda most likely being the best ideas. This concludes the tl;drsection.
其他答案中还建议了其他not
方法,静态方法和 lambda 很可能是最好的想法。tl;dr部分到此结束。
However, if you want some deeper understanding of lambda type inference, I'd like to explain it a bit more to depth, using examples. Look at these and try to figure out what happens:
但是,如果您想更深入地了解 lambda 类型推断,我想使用示例对其进行更深入的解释。看看这些并尝试弄清楚会发生什么:
Object obj1 = String::isEmpty;
Predicate<String> p1 = s -> s.isEmpty();
Function<String, Boolean> f1 = String::isEmpty;
Object obj2 = p1;
Function<String, Boolean> f2 = (Function<String, Boolean>) obj2;
Function<String, Boolean> f3 = p1::test;
Predicate<Integer> p2 = s -> s.isEmpty();
Predicate<Integer> p3 = String::isEmpty;
- obj1 doesn't compile - lambdas need to infer a functional interface (= with one abstract method)
- p1 and f1 work just fine, each inferring a different type
- obj2 casts a
Predicate
toObject
- silly but valid - f2 fails at runtime - you cannot cast
Predicate
toFunction
, it's no longer about inference - f3 works - you call the predicate's method
test
that is defined by its lambda - p2 doesn't compile -
Integer
doesn't haveisEmpty
method - p3 doesn't compile either - there is no
String::isEmpty
static method withInteger
argument
- obj1 无法编译 - lambdas 需要推断功能接口(= 使用一个抽象方法)
- p1 和 f1 工作得很好,每个都推断出不同的类型
- obj2 转换
Predicate
为Object
- 愚蠢但有效 - f2 在运行时失败 - 你不能强制转换
Predicate
为Function
,它不再是关于推理 - f3 有效 - 您调用
test
由其 lambda 定义的谓词方法 - p2 无法编译 -
Integer
没有isEmpty
方法 - p3 也不会编译 - 没有
String::isEmpty
带Integer
参数的静态方法
I hope this helps get some more insight into how type inferrence works.
我希望这有助于更深入地了解类型推断的工作原理。
回答by Per-?ke Minborg
I have written a complete utility class (inspired by Askar's proposal) that can take Java 8 lambda expression and turn them (if applicable) into any typed standard Java 8 lambda defined in the package java.util.function
. You can for example do:
我编写了一个完整的实用程序类(受 Askar 提议的启发),它可以采用 Java 8 lambda 表达式并将它们(如果适用)转换为包中定义的任何类型化标准 Java 8 lambda java.util.function
。例如,您可以执行以下操作:
asPredicate(String::isEmpty).negate()
asBiPredicate(String::equals).negate()
asPredicate(String::isEmpty).negate()
asBiPredicate(String::equals).negate()
Because there would be numerous ambiguities if all the static methods would be named just as()
, I opted to call the method "as" followed by the returned type. This gives us full control of the lambda interpretation. Below is the first part of the (somewhat large) utility class revealing the pattern used.
因为如果所有静态方法都只命名为as()
,将会有很多歧义,所以我选择将方法称为“as”,然后是返回的类型。这使我们可以完全控制 lambda 解释。下面是(有点大)实用程序类的第一部分,揭示了所使用的模式。
Have a look at the complete class here(at gist).
public class FunctionCastUtil {
public static <T, U> BiConsumer<T, U> asBiConsumer(BiConsumer<T, U> biConsumer) {
return biConsumer;
}
public static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> biFunction) {
return biFunction;
}
public static <T> BinaryOperator<T> asBinaryOperator(BinaryOperator<T> binaryOperator) {
return binaryOperator;
}
... and so on...
}
回答by Nikhil Nanivadekar
You can use Predicatesfrom Eclipse Collections
您可以使用谓词从Eclipse的收藏
MutableList<String> strings = Lists.mutable.empty();
int nonEmptyStrings = strings.count(Predicates.not(String::isEmpty));
If you can't change the strings from List
:
如果您无法更改字符串List
:
List<String> strings = new ArrayList<>();
int nonEmptyStrings = ListAdapter.adapt(strings).count(Predicates.not(String::isEmpty));
If you only need a negation of String.isEmpty()
you can also use StringPredicates.notEmpty()
.
如果你只需要否定String.isEmpty()
你也可以使用StringPredicates.notEmpty()
.
Note: I am a contributor to Eclipse Collections.
注意:我是 Eclipse Collections 的贡献者。
回答by outofBounds
In this case u could use the org.apache.commons.lang3.StringUtils
and do
在这种情况下,你可以使用org.apache.commons.lang3.StringUtils
和做
int nonEmptyStrings = s.filter(StringUtils::isNotEmpty).count();