简体   繁体   English

partitioningBy的目的是什么

[英]What's the purpose of partitioningBy

For example, if I intend to partition some elements, I could do something like:例如,如果我打算对某些元素进行分区,我可以执行以下操作:

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

which outputs:输出:

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

But for me partioningBy is only a subcase of groupingBy .但对我来说partioningBy只是一个子情况groupingBy Although the former accepts a Predicate as parameter while the latter a Function , I just see a partition as a normal grouping function.尽管前者接受Predicate作为参数,而后者接受Function ,但我只是将分区视为正​​常的分组函数。

So the same code does exactly the same thing:所以相同的代码做完全相同的事情:

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

which also results in a Map<Boolean, List<String>> .这也会导致Map<Boolean, List<String>>

So is there any reason I should use partioningBy instead of groupingBy ?那么我有什么理由应该使用partioningBy而不是groupingBy吗? Thanks谢谢

partitioningBy will always return a map with two entries, one for where the predicate is true and one for where it is false. partitioningBy将始终返回一个包含两个条目的映射,一个用于谓词为真的地方,一个用于谓词为假的地方。 It is possible that both entries will have empty lists, but they will exist.两个条目可能都有空列表,但它们会存在。

That's something that groupingBy will not do, since it only creates entries when they are needed.这是groupingBy不会做的事情,因为它只在需要时创建条目。

At the extreme case, if you send an empty stream to partitioningBy you will still get two entries in the map whereas groupingBy will return an empty map.在极端情况下,如果您向partitioningBy发送一个空流,您仍然会在映射中获得两个条目,而groupingBy将返回一个空映射。

EDIT: As mentioned below this behavior is not mentioned in the Java docs, however changing it would take away the added value partitioningBy is currently providing.编辑:正如下面提到的,Java 文档中没有提到这种行为,但是改变它会带走partitioningBy当前提供的附加值。 For Java 9 this is already in the specs.对于 Java 9,这已经在规范中了。

partitioningBy is slightly more efficient, using a special Map implementation optimized for when the key is just a boolean . partitioningBy效率稍高一些,它使用了一个特殊的Map实现,当键只是一个boolean时进行了优化。

(It might also help to clarify what you mean; partitioningBy helps to effectively get across that there's a boolean condition being used to partition the data.) (这也可能有助于澄清您的意思; partitioningBy有助于有效地了解使用布尔条件对数据进行分区。)

partitioningBy method will return a map whose key is always a Boolean value, but in case of groupingBy method, the key can be of any Object type 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);

As you can see, the key for map in case of partitioningBy method is always a Boolean value, but in case of groupingBy method, the key is Object type如您所见,partitioningBy 方法中map 的key 始终为布尔值,而groupingBy 方法中key 为Object 类型

Detailed code is as follows:详细代码如下:

    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);

    }
}

Another difference between groupingBy and partitioningBy is that the former takes a Function<? super T, ? extends K> groupingBypartitioningBy之间的另一个区别是前者采用Function<? super T, ? extends K> Function<? super T, ? extends K> Function<? super T, ? extends K> and the latter a Predicate<? super T> Function<? super T, ? extends K>而后者是Predicate<? super T> Predicate<? super T> . Predicate<? super T>

When you pass a method reference or a lambda expression, such as s -> s.length() > 3 , they can be used by either of these two methods (the compiler will infer the functional interface type based on the type required by the method you choose).当您传递方法引用或 lambda 表达式时,例如s -> s.length() > 3 ,它们可以被这两种方法中的任何一种使用(编译器将根据所需的类型推断功能接口类型)您选择的方法)。

However, if you have a Predicate<T> instance, you can only pass it to Collectors.partitioningBy() .但是,如果您有Predicate<T>实例,则只能将其传递给Collectors.partitioningBy() It won't be accepted by Collectors.groupingBy() . Collectors.groupingBy()不会接受它。

And similarly, if you have a Function<T,Boolean> instance, you can only pass it to Collectors.groupingBy() .同样,如果您有一个Function<T,Boolean>实例,则只能将其传递给Collectors.groupingBy() It won't be accepted by Collectors.partitioningBy() . Collectors.partitioningBy()不会接受它。

As denoted by the other answers, segregating a collection into two groups is useful in some scenarios.正如其他答案所述,将集合分成两组在某些情况下很有用。 As these two partitions would always exist, it would be easier to utilize it further.由于这两个分区将始终存在,因此进一步利用它会更容易。 In JDK, to segregate all the class files and config files, partitioningBy is used.在 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);

Code snippet is from jdk.internal.module.ModulePath#deriveModuleDescriptor代码片段来自jdk.internal.module.ModulePath#deriveModuleDescriptor

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM