Java 8将流转换为Map。

huangapple go评论82阅读模式
英文:

Java 8 Convert a stream of set to Map

问题

我已经编写了一个 Lambda 表达式,它从包含在枚举类型 MessageKeyRegistry 中的映射 <Code, Message> 获取值,并将其添加到另一个以 Code 为键、MessageKeyRegistry 为值的映射中。

Map<MessageKey, MessageKeyRegistry> keyMap = new HashMap<>();
EnumSet.allOf(MessageKeyRegistry.class)
        .forEach(messageKeyRegistry -> messageKeyRegistry.getCodeToMessage().keySet()
                .forEach(code -> keyMap.put(code, messageKeyRegistry)));

现在,我想要满足函数式编程中不可变性的概念,并编写一个直接返回不可变映射的 Lambda 表达式。

英文:

I have written this lambda that is getting values from a map <Code, Message>contained inside an enum MessageKeyRegistry and creating adding to another map with Code as the key and the MessageKeyRegistry as the value.

Map<MessageKey, MessageKeyRegistry> keyMap = new HashMap<>();
    EnumSet.allOf(MessageKeyRegistry.class)
            .forEach(messageKeyRegistry -> messageKeyRegistry.getCodeToMessage().keySet()
                    .forEach(code -> keyMap.put(code, messageKeyRegistry)));

Now I want to satisfy the immutability concept of functional programming and write a lambda that returns an immutable map directly.

答案1

得分: 1

> 我编写了这个 lambda 函数,它是一个使用 lambda 表达式链接方法的链式操作。其中之一是 code -> keyMap.put(code, messageKeyRegistry)

回到你的问题。你正确地开始了迭代(从 EnumSet),下一步是理解 forEach 方法中发生的事情。

  • 使用 messageKeyRegistry 将代码从键的集合中提取出来,将其用作键
  • 使用提取器作为值 messageKeyRegistry

这是 map 方法的工作,但由于数据结构更复杂(集合中的集合),所以 flatMap 更适合。最后,你将得到类似以下的结果:

Map<MessageKey, MessageKeyRegistry> keyMap = EnumSet.allOf(MessageKeyRegistry.class)
			.stream()
			.flatMap(messageKeyRegistry -> messageKeyRegistry.getCodeToMessage().keySet()
                 .stream()
                 .map(code -> new AbstractMap.SimpleEntry<>(code, messageKeyRegistry)))
			.collect(Collectors.toMap(Entry::getKey, Entry::getValue));

然而,你所做的操作有一个缺点。我看到键被覆盖了,因为不能有重复项,这从原始解决方案中可以看出,即从这一行开始至少迭代一次,这意味着键可能被覆盖:

.forEach(code -> keyMap.put(code, messageKeyRegistry))

因此,我建议使用 Collectors.groupingBy 进行分组映射,得到 Map<MessageKey, List<MessageKeyRegistry>>

Map<MessageKey, List<MessageKeyRegistry>> keyMap = EnumSet.allOf(MessageKeyRegistry.class)
			.stream()
			.flatMap(messageKeyRegistry -> messageKeyRegistry.getCodeToMessage().keySet()
                .stream()
                .map(code -> new AbstractMap.SimpleEntry<>(code, messageKeyRegistry)))
			.collect(Collectors.groupingBy(Entry::getKey));

对于不可变映射,如果你指的是只读映射,请使用 Collections.unmodifiableMap() 包装器:

Map<MessageKey, List<MessageKeyRegistry>> unmodifiableKeyMap = Collections.unmodifiableMap(keyMap);
英文:

> I have written this lambda that is..

You didn't write just a lambda, but a chain of methods using lambda expressions. one if them is code -&gt; keyMap.put(code, messageKeyRegistry).

Back to your question. You start with the iteration correctly (from the EnumSet), the next step is to realize what happens in the forEach methods.

  • Extract codes from the set of keys using them as keys using messageKeyRegistry
  • Using the extractor as a value messageKeyRegistry .

This is a job for map, however since the data structure is more complicated (collection in a collection), then flatMap would serve better. Finally, you'd result with something like:

Map&lt;MessageKey, MessageKeyRegistry&gt; keyMap = EnumSet.allOf(MessageKeyRegistry.class)
		.stream()
		.flatMap(messageKeyRegistry -&gt; messageKeyRegistry.getCodeToMessage().keySet()
             .stream()
             .map(code -&gt; new AbstractMap.SimpleEntry&lt;&gt;(code, messageKeyRegistry)))
		.collect(Collectors.toMap(Entry::getKey, Entry::getValue));

However, what you do has a drawback. I see the keys are overridden since there cannot be duplicates which is visible from the original solution, i.e. from this line that iterates at least once which implies the key may be overridden:

.forEach(code -&gt; keyMap.put(code, messageKeyRegistry))

So what I suggest is rather group mapping using Collectors.groupingBy resulting in Map&lt;MessageKey, List&lt;MessageKeyRegistry&gt;&gt;:

Map&lt;MessageKey, List&lt;MessageKeyRegistry&gt;&gt; keyMap = EnumSet.allOf(MessageKeyRegistry.class)
		.stream()
		.flatMap(messageKeyRegistry -&gt; messageKeyRegistry.getCodeToMessage().keySet()
            .stream()
            .map(code -&gt; new AbstractMap.SimpleEntry&lt;&gt;(code, messageKeyRegistry)))
		.collect(Collectors.groupingBy(Entry::getKey));

For immutable map, if you mean a map that is read-only use the Collections.unmodifiableMap() wrapper:

Map&lt;MessageKey, List&lt;MessageKeyRegistry&gt;&gt; unmodifiableKeyMap = Collections.unmodifiableMap(keyMap);

答案2

得分: 0

我不确定函数式编程的不可变性概念是否适用于 Java Stream,意味着返回的集合是不可变的。
让我们考虑一个更简单的情况:

final List<String> result = Stream.of("1", "2").collect(Collectors.toList());
result.add("3");
System.out.println(result);
System.out.println(result.getClass());

这将输出:

[1, 2, 3]
class java.util.ArrayList
英文:

I'm not sure the immutability concept of functional programming applying to java streams means immutable returning collections.
Let's consider more simple case

final List&lt;String&gt; result = Stream.of(&quot;1&quot;, &quot;2&quot;).collect(Collectors.toList());
result.add(&quot;3&quot;);
System.out.println(result);
System.out.println(result.getClass());

that outputs

[1, 2, 3]
class java.util.ArrayList

答案3

得分: 0

不是最好的,但类似这样的代码应该可以:

Map<MessageKey, MessageKeyRegistry> keyMap = EnumSet.allOf(MessageKeyRegistry.class)
       .stream()
       .flatMap(messageKeyRegistry -> messageKeyRegistry.getCodeToMessage().keySet().stream().map(code -> new Pair(code, messageKeyRegistry)))
       .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
英文:

Not the nicest but something like this should do:

Map&lt;MessageKey, MessageKeyRegistry&gt; keyMap = EnumSet.allOf(MessageKeyRegistry.class)
       .stream()
       .flatMap(messageKeyRegistry -&gt; messageKeyRegistry.getCodeToMessage().keySet().stream().map(code -&gt; new Pair(code, messageKeyRegistry))
       .collect(Collectors.toMap(Pair::getKey, Pair::getValue)));

huangapple
  • 本文由 发表于 2020年4月11日 03:06:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/61147011.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定