Java 8流收集器用于创建包含多个存储桶中的对象的映射
下面的代码可以工作并且可读,但在我看来,我有一些中间操作,感觉它们不必要。我编写了这个简化版本,因为实际代码是更大流程的一部分
我得到了Collection
个Widget
,每个都有一个名称和多个类型(由WidgetType
枚举的常量表示)。这些多个类型可以作为Stream<WidgetType>
获取,但如果需要,我可以将它们作为其他类型返回。(由于各种原因,强烈希望这些小部件以Stream<WidgetType>
的形式返回,因为这些小部件在实际代码中稍后的使用方式。)
这些小部件被添加到一个EnumMap<WidgetType, List<Widget>>
中,这个EnumMap<WidgetType, Widget[]>
稍后被翻译成一个EnumMap<WidgetType, Widget[]>
如果每个Widget
只有一个WidgetType
,这将是一个微不足道的解决方案,但是,由于任何小部件都可能有1个或多个类型,我对Collectors.groupingBy()
方法的语法(及其重载)感到十分困惑
这里的代码示例,同样,功能齐全,并给出了我需要的确切结果
class StackOverFlowExample {
private final Map<WidgetType, Widget[]> widgetMap = new EnumMap<>(WidgetType.class);
public static void main(String[] args) { new StackOverFlowExample(); }
StackOverFlowExample() {
Collection<Widget> widgetList = getWidgetsFromWhereverWidgetsComeFrom();
{
final Map<WidgetType, List<Widget>> intermediateMap = new EnumMap<>(WidgetType.class);
widgetList.forEach(w ->
w.getWidgetTypes().forEach(wt -> {
intermediateMap.putIfAbsent(wt, new ArrayList<>());
intermediateMap.get(wt).add(w);
})
);
intermediateMap.entrySet().forEach(e -> widgetMap.put(e.getKey(), e.getValue().toArray(new Widget[0])));
}
Arrays.stream(WidgetType.values()).forEach(wt -> System.out.println(wt + ": " + Arrays.toString(widgetMap.get(wt))));
}
private Collection<Widget> getWidgetsFromWhereverWidgetsComeFrom() {
return Arrays.asList(
new Widget("1st", WidgetType.TYPE_A, WidgetType.TYPE_B),
new Widget("2nd", WidgetType.TYPE_A, WidgetType.TYPE_C),
new Widget("3rd", WidgetType.TYPE_A, WidgetType.TYPE_D),
new Widget("4th", WidgetType.TYPE_C, WidgetType.TYPE_D)
);
}
}
这将产生:
TYPE_A: [1st, 2nd, 3rd]
TYPE_B: [1st]
TYPE_C: [2nd, 4th]
TYPE_D: [3rd, 4th]
为了完整性起见,下面是Widget
类和WidgetType
枚举:
class Widget {
private final String name;
private final WidgetType[] widgetTypes;
Widget(String n, WidgetType ... wt) { name = n; widgetTypes = wt; }
public String getName() { return name; }
public Stream<WidgetType> getWidgetTypes() { return Arrays.stream(widgetTypes).distinct(); }
@Override public String toString() { return name; }
}
enum WidgetType { TYPE_A, TYPE_B, TYPE_C, TYPE_D }
任何关于更好地执行这种逻辑的想法都是受欢迎的。谢谢
# 1 楼答案
这有点复杂,但它产生相同的输出,不一定以相同的顺序。它使用静态导入
java.util.stream.Collectors.*
我的机器上的输出:
# 2 楼答案
关键是将
Widget
实例转换为Stream<Pair<WidgetType, Widget>>
实例。一旦我们有了它,我们就可以flatMap
一个小部件流,并在结果流上进行收集。当然,Java中没有Pair
,所以必须使用AbstractMap.SimpleEntry
另外,在这种情况下,IntelliJ的建议不会使用方法参考缩短λ