[英]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);
}
}
groupingBy
和partitioningBy
之間的另一個區別是前者采用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.