簡體   English   中英

partitioningBy的目的是什么

[英]What's the purpose of partitioningBy

例如,如果我打算對某些元素進行分區,我可以執行以下操作:

Stream.of("I", "Love", "Stack Overflow")
      .collect(Collectors.partitioningBy(s -> s.length() > 3))
      .forEach((k, v) -> System.out.println(k + " => " + v));

輸出:

false => [I]
true => [Love, Stack Overflow]

但對我來說partioningBy只是一個子情況groupingBy 盡管前者接受Predicate作為參數,而后者接受Function ,但我只是將分區視為正​​常的分組函數。

所以相同的代碼做完全相同的事情:

 Stream.of("I", "Love", "Stack Overflow")
       .collect(Collectors.groupingBy(s -> s.length() > 3))
       .forEach((k, v) -> System.out.println(k + " => " + v));

這也會導致Map<Boolean, List<String>>

那么我有什么理由應該使用partioningBy而不是groupingBy嗎? 謝謝

partitioningBy將始終返回一個包含兩個條目的映射,一個用於謂詞為真的地方,一個用於謂詞為假的地方。 兩個條目可能都有空列表,但它們會存在。

這是groupingBy不會做的事情,因為它只在需要時創建條目。

在極端情況下,如果您向partitioningBy發送一個空流,您仍然會在映射中獲得兩個條目,而groupingBy將返回一個空映射。

編輯:正如下面提到的,Java 文檔中沒有提到這種行為,但是改變它會帶走partitioningBy當前提供的附加值。 對於 Java 9,這已經在規范中了。

partitioningBy效率稍高一些,它使用了一個特殊的Map實現,當鍵只是一個boolean時進行了優化。

(這也可能有助於澄清您的意思; partitioningBy有助於有效地了解使用布爾條件對數據進行分區。)

partitioningBy方法將返回一個映射,其鍵始終是布爾值,但在groupingBy方法的情況下,鍵可以是任何 Object 類型

//groupingBy
Map<Object, List<Person>> list2 = new HashMap<Object, List<Person>>();
list2 = list.stream().collect(Collectors.groupingBy(p->p.getAge()==22));
System.out.println("grouping by age -> " + list2);

//partitioningBy
Map<Boolean, List<Person>> list3 = new HashMap<Boolean, List<Person>>();
list3 = list.stream().collect(Collectors.partitioningBy(p->p.getAge()==22));
System.out.println("partitioning by age -> " + list2);

如您所見,partitioningBy 方法中map 的key 始終為布爾值,而groupingBy 方法中key 為Object 類型

詳細代碼如下:

    class Person {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String toString() {
        return this.name;
    }
}

public class CollectorAndCollectPrac {
    public static void main(String[] args) {
        Person p1 = new Person("Kosa", 21);
        Person p2 = new Person("Saosa", 21);
        Person p3 = new Person("Tiuosa", 22);
        Person p4 = new Person("Komani", 22);
        Person p5 = new Person("Kannin", 25);
        Person p6 = new Person("Kannin", 25);
        Person p7 = new Person("Tiuosa", 22);
        ArrayList<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        list.add(p5);
        list.add(p6);
        list.add(p7);

        // groupingBy
        Map<Object, List<Person>> list2 = new HashMap<Object, List<Person>>();
        list2 = list.stream().collect(Collectors.groupingBy(p -> p.getAge() == 22));
        System.out.println("grouping by age -> " + list2);

        // partitioningBy
        Map<Boolean, List<Person>> list3 = new HashMap<Boolean, List<Person>>();
        list3 = list.stream().collect(Collectors.partitioningBy(p -> p.getAge() == 22));
        System.out.println("partitioning by age -> " + list2);

    }
}

groupingBypartitioningBy之間的另一個區別是前者采用Function<? super T, ? extends K> Function<? super T, ? extends K> Function<? super T, ? extends K>而后者是Predicate<? super T> Predicate<? super T>

當您傳遞方法引用或 lambda 表達式時,例如s -> s.length() > 3 ,它們可以被這兩種方法中的任何一種使用(編譯器將根據所需的類型推斷功能接口類型)您選擇的方法)。

但是,如果您有Predicate<T>實例,則只能將其傳遞給Collectors.partitioningBy() Collectors.groupingBy()不會接受它。

同樣,如果您有一個Function<T,Boolean>實例,則只能將其傳遞給Collectors.groupingBy() Collectors.partitioningBy()不會接受它。

正如其他答案所述,將集合分成兩組在某些情況下很有用。 由於這兩個分區將始終存在,因此進一步利用它會更容易。 在 JDK 中,為了隔離所有類文件和配置文件,使用partitioningBy

    private static final String SERVICES_PREFIX = "META-INF/services/";
    
    // scan the names of the entries in the JAR file
    Map<Boolean, Set<String>> map = jf.versionedStream()
            .filter(e -> !e.isDirectory())
            .map(JarEntry::getName)
            .filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX)))
            .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
                                               Collectors.toSet()));

    Set<String> classFiles = map.get(Boolean.FALSE);
    Set<String> configFiles = map.get(Boolean.TRUE);

代碼片段來自jdk.internal.module.ModulePath#deriveModuleDescriptor

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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