リストから重複要素を抽出する。

リスト、またはストリームから重複した要素だけを抽出してリストにしたい場合、
equals 、hashCode が正しく実装されていることが前提だが、
直感的かもしれないが、以下のように Collectors.groupingBy で取得できる。

リストでもStreamを取得できるので、Stream から書くと。。

Stream<String> targets;

// TODO String の stream を targets とする

List<String> list = targets
                    .collect(Collectors.groupingBy(t->t))
                    .entrySet().stream()
                    .filter(e->e.getValue().size() > 1)
                    .map(e->e.getKey())
                    .collect(Collectors.toList());

容易に書けるので苦はないが、でも、いくつもこの処理が必要で沢山これを書くのは、
書き間違えてしまうと元も子もない。
そこで、Collector<T, ?, List<T>> を返すメソッドで用意すれば、
Stream終端操作で書き易くコードがすっきりしてくる。

public static <T> Collector<T, ?, List<T>> duplicatedList(){
   Map<T, Integer> map = new HashMap<>();
   return Collectors.reducing(new ArrayList<T>(),
   t->{
      map.put(t, Optional.ofNullable(map.get(t)).map(i->i+1).orElse(1));
      return Arrays.asList(t);
   },(n1, n2)->{
      return map.entrySet().stream().filter(e->e.getValue() > 1)
         .map(e->e.getKey())
         .collect(Collectors.toList());
   });
}
Stream<String> targets;

// TODO String の stream を targets とする

List<String> list = targets.collect(duplicatedList());

ただし、equals 、hashCode が正しく実装されていることが前提