![](/img/trans.png)
[英]Why doesn't Java 8's ToIntFunction<T> extend Function<T, Integer>
[英]Why doesn't Java 8's Predicate<T> extend Function<T, Boolean>
如果我編寫Predicate
接口,我想在接口中編碼它只是一個返回原始boolean
的函數,如下所示:
@FunctionalInterface
public interface Predicate<T> extends Function<T, Boolean> {
boolean test(T t);
@Override
default Boolean apply(T t) {
return Boolean.valueOf(test(t));
}
}
我想知道,有沒有令人信服的理由讓Java 8 API設計者選擇將Predicate
與Function
完全分開? 是否有一些證據表明他們認為這樣做並決定反對呢? 我想類似的問題適用於所有其他'特殊'功能接口,如Consumer
(可能是Function<T, Void>
), Supplier
( Function<Void, T>
)和原始函數,如IntFunction
( Function<Integer, T>
)。
我沒有深入和徹底地考慮過這個問題的所有后果,所以我可能會遺漏一些東西。
編輯:一些答案強調應用和測試之間的語義區別。 我不是說我不欣賞這種區別,我同意這種區別是有益的。 我不明白為什么Predicate
不是一個Function in
的原因,例如, List
是一個Collection
, Double
是一個Number
,它是一個Object
。
如果Predicate
(以及所有其他特殊的通用功能接口,例如Consumer
, Supplier
, IntUnaryOperator
等)與Function
有這種關系,它將允許人們在預期使用Function
參數的地方使用它(想到的是組合與其他函數,例如調用myFunction.compose(myPredicate)
或避免在API中編寫幾個專用函數時,如上所述的自動(un)裝箱實現就足夠了)
編輯2:看看openjdk lambda項目,我發現原始的功能接口用於擴展Function
,直到2012-12-19的Brian Goetz提交 。 我找不到具體的原因,在那個時候對任何lambda-dev或JSR專家組郵件列表進行了更改。
Predicate<T>
的方法返回boolean
。 Function<T, Boolean>
返回Boolean
。 他們不一樣。 雖然存在自動裝箱,但是當原語可以使用時,Java方法不使用包裝類。 此外,像Boolean
這樣的差異可以為null
而boolean
則不能。
在Consumer<T>
的情況下,它更加不同。 Consumer<T>
的方法返回類型為void
,這意味着它可以使用return;
隱式返回或return;
,但Function<T, Void>
必須使用return null;
明確。
不需要這種可疑的繼承層次結構。 這些功能接口是可互換的。
Function<A,Boolean> f1=…;
Predicate<A> p1=…;
Predicate<A> p2=f1::apply;
Function<A,Boolean> f2=p1::test;
這適用於兩個方向。 那么為什么要有一個繼承關系來宣傳一個特定的方向呢?
這不是你問題的直接答案,而是你將用它做什么?
請考慮以下情形:您希望將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);
}
}
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));
然而,以下內容告訴我他們肯定會想到類似的東西,因為它們提供了分區方法:
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));
我能想到的一些原因是:
Predicate
中提供apply()
方法並不直觀,您只需要一個test()
方法。 CustomPredicate
包含兩種類型的功能。 這只會增加混亂。 在我看來, Function<T, R>
只是泛型函數的定義。 如果所有FunctionalInterfaces
都實現Function
,則唯一的抽象方法必須命名為apply()
。 在像FilterFile
這樣的具體FunctionalInterface
的上下文中,抽象方法boolean accept(File pathname)
是一個比Boolean apply(File)
更好的名稱。
注釋@FunctionalInterface
已將接口標記為可用作FunctionalInterface
。 除了以通用方式處理它們之外,它們都實現基本接口是沒有好處的。 我不明白的時候,你不會在乎的語義FunctionalInterface
提前,以使其可調用apply
為他們所有。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.