Java 8 GroupingBy进入Peek

时间:2017-01-09 13:19:42

标签: java java-8 java-stream

我最近了解了Java 8中的流,并开始使用它们。现在我对groupingBy收集器方法有疑问:

通常我使用.NET,所以我用.NET Stream<T>比较(知道它们相同)Java IEnumerable<T>。通过此比较,List<T>存储元素,特定Stream / IEnumerable应用操作。一个例子:

C#:

elements.Where(x => x.Value == 5).ToList();

爪哇:

elements.stream().filter(x -> x.getValue() == 5).collect(Collectors.toList());

在这两个示例中,我从列表开始,定义操作(在此示例中为过滤器)并收集结果以存储它(在此示例中的新列表中)。

现在我遇到了一个更复杂的案例:

data.stream()
    .map( ... ).filter( ... ) // Some operations
    .collect(groupingBy(Chunk::getName, summingLong(Chunk::getValue)));

此查询的结果是Map<String, Long>,我可以使用它,但是,我想说,我想继续处理这些数据而不是存储它。我目前的方法很简单:

    ...
    .collect(groupingBy(Chunk::getName, summingLong(Chunk::getValue)))
    .entrySet().stream().
    .map( ... ) // Do more operations

但是这样,我离开了流,将第一个结果存储在Map中并打开一个新流继续。有没有一种方法可以在没有收藏家的情况下进行分组,这样我就可以保持&#34;在流?

2 个答案:

答案 0 :(得分:5)

只要您可以将操作描述为Collector,您就可以在下游收集器中执行任何操作。目前,只有等效于中间操作mapmapping收集器,但Java 9还将添加filteringflatMapping(您也可以自己实现Java 8)并且几乎已经完成了每个终端操作。

当然,收藏家的嵌套设备看起来与做同样的Stream操作链完全不同......

但是,如果您要处理完整的群组,则无法先完成grouping收集。这不是API的限制,而是分组操作或一般任何操作的固有内容,如果要处理完整的结果,则需要先完成操作。无论API如何,例如你可以用collectingAndThen方式隐藏收集器中的后续操作,创建和填充Map是不可避免的,因为它是维护组的映射。这些组由Map的密钥和查找逻辑确定,因此,例如将SortedMap与自定义比较器或IdentityHashMap一起使用,可以完全更改分组逻辑。

答案 1 :(得分:4)

由于现在的API,你无法逃脱它。

  

groupingBy

是终端操作(它不返回Stream),因此该操作将结束流。

根据您在以后的地图操作中要执行的操作,您可以创建一个自定义收集器,以便&#34;保持&#34;在溪流里面;即使在里面,你可能仍会将元素收集到地图中。