使用collect保留Java流中的顺序

时间:2018-06-05 17:43:27

标签: java functional-programming java-stream

我遇到了一个问题,我需要在对字符串列表执行的操作中保留顺序,并使用java stream api中的collect方法。

public List<String> countOccurrences(ArrayList<String> messages) {
        List<String> stackedMessages = new LinkedList<>();
        HashMap<String, Integer> messageOccurrences = 
                   messages.stream()
                           .collect(groupingBy(Function.identity(), summingInt(e -> 1)));

        messageOccurrences.forEach((key, value) -> {
            String appendString = value == 1 ? "" : " (" + value + " times)";
            stackedMessages.add(key + appendString);
        });

        return stackedMessages;
    }

上述代码的问题是,如果我处理["blah", "blah", "yep"]这样的列表,它会返回["yep", "blah (2 times)"]我需要它返回["blah (2 times)", "yep"]

我已经在这里查看了这篇文章,并且相信如果我在已经排序的数据结构上使用流,那么将确保订单:How to ensure order of processing in java8 streams?

我想我需要将groupingBy更改为toMap,现在我正在阅读该文档。任何精通这一主题的人都已经提出了一些建议。

更新:

感谢用户@Aominè,这是使用groupingBy

执行此操作的正确方法
.collect(groupingBy(Function.identity(),LinkedHashMap::new, summingInt(e->1)))

1 个答案:

答案 0 :(得分:1)

您需要收集到LinkedHashMap才能获得预期结果。此外,您不必在forEach之后与流管道分开执行另一个groupingBy,只需从entrySetmap创建一个流然后收集到列表。

return messages.stream()
               .collect(groupingBy(Function.identity(), LinkedHashMap::new, summingInt(e -> 1)))
               .entrySet()
               .stream()
               .map(e -> e.getKey()+(e.getValue() == 1 ? "" : " (" + e.getValue() +" times)"))
               .collect(toList());