mka*_*unc 38 java lambda functional-programming predicate java-8
如果我编写Predicate接口,我想在接口中编码它只是一个返回原始布尔值的函数,如下所示:
@FunctionalInterface
public interface Predicate<T> extends Function<T, Boolean> {
boolean test(T t);
@Override
default Boolean apply(T t) {
return Boolean.valueOf(test(t));
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道,有没有令人信服的理由让Java 8 API设计者选择将Predicate与Function完全分开?是否有一些证据表明他们认为这样做并决定反对呢?我想类似的问题适用于所有其他'特殊'功能接口,如Consumer(可能是Function <T,Void>),Supplier(Function <Void,T>)和原始函数,如IntFunction(Function <Integer,T>).
我没有深入和彻底地考虑过这个问题的所有后果,所以我可能会遗漏一些东西.
编辑:一些答案强调了应用和测试之间的语义区别.我不是说我不欣赏这种区别,我同意这种区别是有益的.我不明白的是,为什么Predicate不是一个函数,就像List是一个Collection或Double是一个Number,它是一个Object.
如果Predicate(以及所有其他特殊的通用功能接口,例如Consumer,Supplier,IntUnaryOperator等)与Function有这种关系,它将允许人们在预期使用Function参数的地方使用它(想到的是组合与其他功能,例如,呼叫myFunction.compose(比如说myPredicate)或避免在API中写入几个专门的功能时,如上所述的这种汽车(未)拳击实施将是足够的)
编辑2:看看openjdk lambda项目,我发现原始的功能接口用于扩展功能,直到2012-12-19的Brian Goetz提交.我找不到具体的原因,在那个时候对任何lambda-dev或JSR专家组邮件列表进行了更改.
new*_*cct 19
Predicate<T>
返回的方法boolean
.Function<T, Boolean>
返回的方法Boolean
.他们不一样.虽然存在自动装箱,但是当原语可以使用时,Java方法不使用包装类.此外,有喜欢的差异Boolean
可以null
同时boolean
不能.
在这种情况下,它更加不同Consumer<T>
.Consumer<T>
具有返回类型的方法void
,这意味着它可以隐式返回或返回使用return;
,但是Function<T, Void>
必须使用return null;
显式返回方法.
Hol*_*ger 12
不需要这种可疑的继承层次结构.这些功能接口是可互换的.
Function<A,Boolean> f1=…;
Predicate<A> p1=…;
Predicate<A> p2=f1::apply;
Function<A,Boolean> f2=p1::test;
Run Code Online (Sandbox Code Playgroud)
这适用于两个方向.那么为什么要有一个继承关系来宣传一个特定的方向呢?
这不是你问题的直接答案,而是你将用它做什么?
请考虑以下情形:您希望将true/false映射到其值为true的值列表,分别为false.
使用您的代码,您可以使用:
@FunctionalInterface
interface CustomPredicate<T> extends Function<T, Boolean> {
boolean test(T value);
@Override
default Boolean apply(T t) {
return test(t);
}
}
Run Code Online (Sandbox Code Playgroud)
List<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("hg");
stringList.add("dsl");
stringList.add("sldi");
stringList.add("ilsdo");
stringList.add("jlieio");
CustomPredicate<String> customPredicate = str -> (str.length() >= 3);
Map<Boolean, List<String>> mapping = stringList.stream()
.collect(Collectors.groupingBy(customPredicate));
Run Code Online (Sandbox Code Playgroud)
然而,以下内容告诉我他们肯定会想到类似的东西,因为它们提供了分区方法:
List<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("hg");
stringList.add("dsl");
stringList.add("sldi");
stringList.add("ilsdo");
stringList.add("jlieio");
Predicate<String> predicate = str -> (str.length() >= 3);
Map<Boolean, List<String>> mapping = stringList.stream()
.collect(Collectors.partitioningBy(predicate));
Run Code Online (Sandbox Code Playgroud)
我能想到的一些原因是:
apply()
在一个Predicate
你只期望一个test()
方法的地方有一个方法是不直观的.CustomPredicate
包含两种类型的功能.这只会增加混乱.在我看来Function<T, R>
,只是通用功能的定义.如果全部FunctionalInterfaces
实现Function
,则必须命名唯一的抽象方法apply()
.在具体的情境FunctionalInterface
一样FilterFile
,抽象方法boolean accept(File pathname)
是一个更好的名字,那么Boolean apply(File)
.
注释@FunctionalInterface
已将接口标记为可用作a FunctionalInterface
.除了以通用方式处理它们之外,它们都实现基本接口是没有好处的.我不知道你什么时候不关心它的语义,FunctionalInterface
以便让它们全部可用apply
.
归档时间: |
|
查看次数: |
4830 次 |
最近记录: |