簡體   English   中英

為什么Java 8的Predicate <T>不擴展Function <T,Boolean>

[英]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設計者選擇將PredicateFunction完全分開? 是否有一些證據表明他們認為這樣做並決定反對呢? 我想類似的問題適用於所有其他'特殊'功能接口,如Consumer (可能是Function<T, Void> ), SupplierFunction<Void, T> )和原始函數,如IntFunctionFunction<Integer, T> )。

我沒有深入和徹底地考慮過這個問題的所有后果,所以我可能會遺漏一些東西。

編輯:一些答案強調應用和測試之間的語義區別。 我不是說我不欣賞這種區別,我同意這種區別是有益的。 我不明白為什么Predicate不是一個Function in的原因,例如, List是一個CollectionDouble是一個Number ,它是一個Object

如果Predicate (以及所有其他特殊的通用功能接口,例如ConsumerSupplierIntUnaryOperator等)與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這樣的差異可以為nullboolean則不能。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM