Stream の Collector 見直し。。

去年、書いたStream の終端処理 Collector 以下は、
リストから重複要素を抽出する。 - Oboe吹きプログラマの黙示録
並行Stream実行ではNGであるのを反省して、以下のように修正すべきです。

static <T> Collector<T, Map<T, Integer>, List<T>> duplicatedList(){
   return Collector.of(HashMap::new,
      (r, t)->r.put(t, Optional.ofNullable(r.get(t)).map(i->i+1).orElse(1)),
      (a1, a2)->{
         a1.entrySet().stream().forEach(e->{
            a2.put(e.getKey(), Optional.ofNullable(a2.get(e.getKey()))
                     .map(i->i+e.getValue()).orElse(e.getValue()));
         });
         return a2;
      },
      a->a.entrySet().stream().filter(e->e.getValue() > 1)
               .map(e->e.getKey())
               .collect(Collectors.toList()),
      Characteristics.CONCURRENT
   );
}

java.util.stream.Collector.Characteristics の指定

CONCURRENT マルチスレッドで呼ばれても大丈夫な場合に指定する。
UNORDERED 順序を保証しない場合に指定する。
IDENTITY_FINISH finisherが省略可能

メソッド名、duplicatedList というのは、あまり良い名称に思えませんが、

重複カウント数を指定するなら以下です。

static <T> Collector<T, Map<T, Integer>, List<T>> duplicateCountOverList(int cnt){
   return Collector.of(HashMap::new,
      (r, t)->r.put(t, Optional.ofNullable(r.get(t)).map(i->i+1).orElse(1)),
      (a1, a2)->{
         a1.entrySet().stream().forEach(e->{
            a2.put(e.getKey(), Optional.ofNullable(a2.get(e.getKey()))
                     .map(i->i+e.getValue()).orElse(e.getValue()));
         });
         return a2;
      },
      a->a.entrySet().stream().filter(e->e.getValue() > cnt)
               .map(e->e.getKey())
               .collect(Collectors.toList()),
      Characteristics.CONCURRENT
   );
}

しかし、やはり以下のように  Collectors.groupingBy を使って書くことの方が多いかな?

List<String> res =
list.stream().collect(Collectors.groupingBy(t->t, Collectors.counting()))
.entrySet().stream().filter(e->e.getValue() == 2)
.map(e->e.getKey())
.collect(Collectors.toList());