[Java]引数で受け取った型でコレクションオブジェクトを生成したいけど

2016年11月21日月曜日

Java

JavaのSetの要素を指定されたものだけ、別のSetに移す必要があったんだけど、指定要素を保持するSetが移動元のSetに存在しない要素も持っていたため、一時的なSetを作成する必要があった。
    private static <T> void moveSet(Set<T> destSet, Set<T> srcSet,
                                    Set<T> targetSet) {
        Set<T> s = new HashSet<>(targetSet);
        s.retainAll(srcSet);
        destSet.addAll(s);
        srcSet.removeAll(s);
    }
結局、上記のようなコードになってしまった。
使い方はこんな感じ。setBからsetAへsetCで指定された要素を移動する。
        Set<Integer> setA = new HashSet<>(Arrays.asList(2, 3, 5, 7, 11));
        Set<Integer> setB = new HashSet<>(Arrays.asList(11, 13, 17));
        Set<Integer> setC = new TreeSet<>(Arrays.asList(3, 5, 13));

        System.out.println("SetA");
        setA.forEach(System.out::println);
        System.out.println("SetB");
        setB.forEach(System.out::println);

        moveSet(setA, setB, setC);

        System.out.println("SetA");
        setA.forEach(System.out::println);
        System.out.println("SetB");
        setB.forEach(System.out::println);
SetA
2
3
5
7
11
SetB
17
11
13
SetA
2
3
5
7
11
13
SetB
17
11

どんなSetでも受け付けるけど、HashSetのインスタンスをメソッドの中で生成することになってしまった。
cloneが使えるか?と思ったけど、Setインターフェース自体はClonableであることを要請していないので、各実装クラスにキャストしないとcloneメソッドが使えないんだね。
    private static <T> void moveSet(Set<T> destSet, Set<T> srcSet,
                                    Set<T> targetSet) {
        // Setインターフェースはcloneメソッドを持っていないので、コンパイルエラー!
        Set<T> s = targetSet.clone();
        s.retainAll(srcSet);
        destSet.addAll(s);
        srcSet.removeAll(s);
    }
まあ、そもそも一時的なSetなのだから、メソッドないで決めた型でもいいんじゃないか?
ただし、コピー元のSetがnull要素を保持している可能性があるから、HashSetのようにnull許容のSetである必要はあるけど。
けど、もっとかっこいいやり方はないかなぁ。。。