简体   繁体   English

在Java 8中优雅地创建具有对象字段的映射作为来自对象流的键/值

[英]Elegantly create map with object fields as key/value from object stream in Java 8

I have the following class 我有以下课程

class Person {
    public String name;
    public int age;
    public List<String> hobbies;

    Person(String name, int age, List<String> hobbies)
    {this.name = name; this.age = age; this.hobbies = hobbies;}
}

How do I create a Map of age to hobbies like Map<Integer, Set<String>> ? 如何创建Map<Integer, Set<String>>等爱好的年龄Map<Integer, Set<String>>

The Java 8 way I cooked up is: 我编写的Java 8方式是:

Map<Integer, Set<String>> collect8 = persons.stream()
    .collect(
        toMap(
            p -> p.age,
            p -> p.hobbies.stream().collect(toSet()),
            (hobbies1, hobbies2) ->
                Stream.concat(hobbies1.stream(), hobbies2.stream()).collect(toSet())
        )
     );

Is there a more idiomatic way of doing this with Collectors.groupingBy() perhaps? 是否有一种更惯用的方法可以使用Collectors.groupingBy()

As a related question, I find the version without Java streams to be more readable. 作为一个相关的问题,我发现没有Java流的版本更具可读性。

Map<Integer, Set<String>> collect7 = new HashMap<>();

for(Person p: persons) {
    Set<String> hobbies = collect7.getOrDefault(p.age, new HashSet<>());
    hobbies.addAll(p.hobbies);
    collect7.put(p.age, hobbies);
}

Should we go with non streams code if it is easier to read; 如果它更容易阅读,我们应该使用非流代码; specially when the streamed version, as seen here, has no intermediate streams with transformations of the data but quickly end in a terminal operation? 特别是当流式版本,如此处所示,没有中间流与数据的转换,但很快在终端操作中结束?

Look at similar example from Java 8 Collectors documentation: 查看Java 8 Collectors文档中的类似示例:

Map<City, Set<String>> namesByCity
     = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,                                           
           mapping(Person::getLastName, toSet())));

You could use the same approach here. 你可以在这里使用相同的方法。

As you noted yourself: the Stream solution might not be as readable as your current non- Stream -solution. 正如您自己所说: Stream解决方案可能不像您当前的非Stream -solution那样可读。 Solving your problem with groupingBy might not look as good as you might expect as you want to transform your List into a Set . 使用groupingBy解决问题可能看起来不像您想要的那样将List转换为Set

I constructed a solution with groupingBy , mapping and reducing , but that solution is not that easy to read and did even contain an error. 我使用groupingBymappingreducing构建了一个解决方案,但该解决方案并不容易阅读,甚至包含错误。 You can read more about that in: Java 8 stream.collect( ... groupingBy ( ... mapping( ... reducing ))) reducing BinaryOperator-usage I really suggest to look up the answer Holger gave as it also contains a simpler solution using a custom Collector and a little Outlook to Java 9's flatMapping , which for me comes close to your non- Stream -solution. 您可以在以下内容中阅读更多相关内容: Java 8 stream.collect(... groupingBy(... mapping(... reduction)))减少BinaryOperator用法我真的建议查找Holger给出的答案,因为它还包含一个更简单的解决方案使用自定义Collector和一点Outlook到Java 9的flatMapping ,这对我来说非常接近你的非Stream -solution。

But another solution using groupingBy I came up with and that actually works is the following: 但另一个使用groupingBy解决方案我想出了它实际上有以下几点:

Map<Integer, Set<String>> yourmap;
yourmap = personList.stream()
                    .flatMap(p -> p.hobbies.stream()
                                           .flatMap(hobby -> Stream.of(new SimpleEntry<>(p.age, hobby)))
                            )
                    .collect(Collectors.groupingBy(Entry::getKey,
                             Collectors.mapping(Entry::getValue, Collectors.toSet())));

for that you need the following imports: 为此,您需要以下导入:

import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;

Of course you can take also a Tuple or Pair or what you like the most. 当然,你也可以采取TuplePair或你最喜欢的。

But then again not better in any ways. 但在任何方面再也不会更好。

I would stay with your current non- Stream -solution. 我会留在你目前的非Stream -solution。 It is more readable and does what it should do. 它更具可读性,可以做它应该做的事情。

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

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