如何使用 Java 流 API 添加和更新地图条目

How to add and update map entry using Java Streams API

我刚开始学习 Streams,我有一个任务是对某个字符串数组中的所有单词进行计数和排序。我已经将我的输入解析为单词,但我不知道如何使用流添加和更新条目。

这是我的解析流:

Stream<String> stringStream = lines.stream().flatMap(s -> Arrays.stream(s.split("[^a-zA-Z]+")));
        String[] parsed =  stringStream.toArray(String[]::new);

我在没有流的情况下完成了这个任务,就像这样:

Map<String,WordStatistics> wordToFrequencyMap = new HashMap<>();
for (String line: lines) {
    line=line.toLowerCase();
    String[] mas =  line.split("[^a-zA-Z]+");
    for (String word:mas) {
        if(word.length()>3) {
            if (!wordToFrequencyMap.containsKey(word)) {
                wordToFrequencyMap.put(word, new WordStatistics(word, 1));
            } else {
                WordStatistics tmp = wordToFrequencyMap.get(word);
                tmp.setFreq(tmp.getFreq() + 1);
            }
        }
    }
}

WordStatistics class:

public class WordStatistics implements Comparable<WordStatistics>{
    private String word;
    private int freq;

    public WordStatistics(String word, int freq) {
        this.word = word;
        this.freq = freq;
    }

    public String getWord() {
        return word;
    }

    public int getFreq() {
        return freq;
    }

    public void setWord(String word) {
        this.word = word;
    }

    public void setFreq(int freq) {
        this.freq = freq;
    }

    @Override
    public int compareTo(WordStatistics o) {
        if(this.freq > o.freq)
            return 1;
        if(this.freq == o.freq)
        {
            return -this.word.compareTo(o.word);
        }
        return -1;
    }
}

一种简单的方法是使用合并功能收集 toMap()

Map<String, WordStatistics> wordToFrequencyMap = lines.stream()
        .map(s -> s.split("[^a-zA-Z]+"))
        .flatMap(Arrays::stream)
        .collect(Collectors.toMap(w -> w, w -> new WordStatistics(w, 1), (ws1, ws2) -> {
            ws1.setFreq(ws1.getFreq() + ws2.getFreq());
            return ws1;
        }));

要分解 toMap() 个参数:

  • w -> w只是表示使用流元素作为映射键。
  • 下一个参数为键生成一个值,该值最初是 WordStatistics 的新实例,频率为 1
  • 最后,我们告诉收集器如何将属于同一键的值合并在一起。在我们的例子中,我们将频率求和为值 (ws1) 和 return 之一,作为合并结果。

这应该与您现在在循环中所做的几乎相同。

Pattern pattern = Pattern.compile("[^a-zA-Z]+");
lines.stream().flatMap(pattern::splitAsStream).filter(s -> s.length() > 3).forEach(s -> {
    WordStatistics tmp = wordToFrequencyMap.get(s);
    if (tmp == null) {
        wordToFrequencyMap.put(s, new WordStatistics(word, 1));
    } else {
        tmp.setFreq(tmp.getFreq() + 1);
    }
});