英文:
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 -> 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<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));
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 -> keyMap.put(code, messageKeyRegistry))
So what I suggest is rather group mapping using Collectors.groupingBy
resulting in 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));
For immutable map, if you mean a map that is read-only use the Collections.unmodifiableMap()
wrapper:
Map<MessageKey, List<MessageKeyRegistry>> 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<String> result = Stream.of("1", "2").collect(Collectors.toList());
result.add("3");
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<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)));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论