365連休

にわかのandroidとかの開発メモ。

【Self Stack Overflow】Javaで複数の戻り値(タプル)を持つメソッドを定義する方法

自問

Javaで複数の戻り値(タプル構造)を持つメソッドを定義する方法を教えてください。

 

 

ベストアンサー

Javaのメソッドは1つの「プリミティブデータ型」または「クラス」しか返すことができない。

そこで、複数の値を持つクラスを返す方法を考える。

 

Java1.6のAbstractMap.SimpleEntry<K, V>クラスを流用する方法がある。

JavaFX 2.0ではPair<K, V>クラスが追加された。

Android SDKであればandroid.util.Pair<F, S>クラスがある。

3つ以上の値を持つ標準クラスはない。

他に各種OSSライブラリが存在する。

 

しかし、私は、汎用クラスの使用はお勧めしない。

なぜならば、ネストしたジェネリクスによるアンチパターンと考えるから。

Pair<Pair<String, Integer>, Map<String, Pair<String, String>>> getHell(){
return hell;
}

 

 そこで、以下に、メソッドデータ受け渡し専用のTupleクラスを提案する。

 

 

サンプルコード

    /** タプル(メソッドデータ受け渡し用 構造体)、継承してデータアクセスの手段のみを定義すること。<br/>
     * <span style="font-size:1.2em;color:#FF8888;">hashCode、equals、clone、toStringへのアクセスはExceptionを生成する</span><br/>
     * <pre>
     * //内部クラスにするとthis参照を保持してしまうので注意。
     * //再継承するのは本来の目的から離れるためfinal class推奨。
     * //単純化するためメンバへの直接アクセス推奨。
     * public static final class ExampleTuple extends AbsTuple {
     *     public int a = 1;
     *     public int b = 1;
     *     public int c = 1;
     * }</pre>*/
    public static abstract class AbsTuple {
        @Override
        public final int hashCode() throws RuntimeException {
            throw new RuntimeException();
        }
        @Override
        public final boolean equals(@Nullable Object obj) throws RuntimeException {
            throw new RuntimeException();
        }
        @Override
        protected final @NonNull Object clone() throws CloneNotSupportedException {
            throw new CloneNotSupportedException();
        }
        @Override
        public final @NonNull String toString() throws RuntimeException {
            throw new RuntimeException();
        }
    }

    /** 継承例:2つのメンバ変数を持つ汎用タプル、Pairクラスのようなもの。推奨しない使い方 */
    public static final class Tuple2<A, B> extends AbsTuple {
        public A a;
        public B b;
    }

    public static @NonNull Tuple2<String, String> getExample1(){
        Tuple2<String, String> ret = new Tuple2<>();
        ret.a = "this is a a";
        ret.b = "this is a b";
        return ret;
    }

    /** 例:メソッド専用のタプル。勘違いが少なく、定義に柔軟性がある。 */
    public static final class ExampleTuple extends AbsTuple {
        public final @NonNull String first;
        public final @NonNull String second;
        public ExampleTuple(@NonNull String first, @NonNull String second) {
            this.first = first;
            this.second = second;
        }
    }

    public static @NonNull ExampleTuple getExample2(){
        return new ExampleTuple("this is a first", "this is a second");
    }

 

 

目的外の使用を阻止するため、あえてObjectメソッドの禁止という強い制限を設けている。

 

なんでもできるというのは一見便利だが、不便なことも多いと私は考える。