在Java 8中优雅地创建具有对象字段的映射作为来自对象流的键/值 [英] Elegantly create map with object fields as key/value from object stream in Java 8

查看:114
本文介绍了在Java 8中优雅地创建具有对象字段的映射作为来自对象流的键/值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下课程

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

如何创建年龄图到喜欢 Map< Integer,Set< String>>

How do I create a Map of age to hobbies like Map<Integer, Set<String>>?

我制作的Java 8方式是:

The Java 8 way I cooked up is:

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

使用 Collectors.groupingBy()是否有更惯用的方法也许?

作为一个相关的问题,我发现没有Java流的版本更具可读性。

As a related question, I find the version without Java streams to be more readable.

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?

推荐答案

正如您自己所说: Stream 解决方案可能不如您当前的非 Stream -solution那样可读。使用 groupingBy 解决您的问题可能看起来不如您想要的那样,因为您希望将列表转换为设置

As you noted yourself: the Stream solution might not be as readable as your current non-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 的解决方案,映射减少,但该解决方案并不容易阅读,甚至包含错误。您可以在以下网址阅读更多相关信息: Java 8 stream.collect( ... groupingBy(... mapping(... reduction)))减少BinaryOperator使用我真的建议查找Holger给出的答案,因为它还包含一个使用自定义收藏家和一点点Outlook到Java 9的 flatMapping ,这对我来说非常接近你的非 Stream -solution。

I constructed a solution with groupingBy, mapping and reducing, but that solution is not that easy to read and did even contain an error. 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.

但另一个使用 groupingBy 的解决方案我想出了它实际上是有效的以下:

But another solution using groupingBy I came up with and that actually works is the following:

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

您需要以下导入:

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.

但是在任何方面都不会更好。

But then again not better in any ways.

我会留在你当前的非 Stream -solution。它更具可读性,可以做它应该做的事情。

I would stay with your current non-Stream-solution. It is more readable and does what it should do.

这篇关于在Java 8中优雅地创建具有对象字段的映射作为来自对象流的键/值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆