リスト、またはストリームから重複した要素だけを抽出してリストにしたい場合、
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 が正しく実装されていることが前提