web-dev-qa-db-ja.com

Javaメソッド参照をパラメータとして他のメソッドに渡す

クラスAの選択した「取得」メソッドをクラスBのメソッドに渡そうとしています。チェックアウトしたのは Javaパスメソッドをパラメーターとして ですが、インターフェースアプローチを採用できませんでした合理的な方法で私の問題。私はしないJava 8(lambdas)を使用し、可能であれば反射も回避することをお勧めします。私の気持ちは、私が自分の問題を間違った方法で見ていることをここに示します。

いくつかのフィールドとgetメソッドを含むクラスがあります。

_public class DataStore {
    private float a;
    private float b;
    private float c;

    public float getA() {
        return a;
    }

    public float getB() {
        return b;
    }

    public float getC() {
        return c;
    }

}
_

次に、マップの値としてDataStoreをインスタンス化してから、次のようにDataStoreの特定のフィールドにアクセスするメインクラスがあります。

_public class App {

    public static void main(String[] args) {
        // declare TreeMap using DataStore class as value
        Map<Integer, DataStore> dataMap = new TreeMap<Integer, DataStore>();

        // populate Map with example data
        dataMap.put(2,  new DataStore(1f,2f,3f));
        dataMap.put(10, new DataStore(3f,4f,5f));
        dataMap.put(4,  new DataStore(6f,7f,8f));

        // work with specific fields in DataStore, e.g. assign to array
        float[] aArray = getValuesAsArray(dataMap, DataStore.getA());
        float[] bArray = getValuesAsArray(dataMap, DataStore.getB());
        float[] cArray = getValuesAsArray(dataMap, DataStore.getC());
    }

    /**
     * Assign specific field of DataStore from Map to Array
     * @param dataMap
     * @param getVar - reference for specified getter method
     * @return 
     */
    private static float[] getValuesAsArray(Map<Integer, DataStore> dataMap, MethodReference getVar()) {
        int i = 0;
        int nMap = dataMap.size();
        float[] fArray = new float[nMap];
        for (Map.Entry<Integer, DataStore> entry : dataMap.entrySet()) {
            DataStore ds = entry.getValue();
            fArray[i] = ds.getVar();
            i++;
        }
        return fArray;
    }
}
_

選択したgetメソッドをgetValuesAsArray()に渡す方法を理解する必要があるため、これは明らかに機能しません。どういうわけか、私のアプローチは間違っているかもしれません。だから私は提案を開いています。

12
SwanAH

getX()メソッドは、DataStoreインスタンスを受け入れ、floatを返す関数と見なすことができます。

Java 8では、それらをメソッド参照で表すことができます。

_    float[] aArray = getValuesAsArray(dataMap, DataStore::getA);
    float[] bArray = getValuesAsArray(dataMap, DataStore::getB);
    float[] cArray = getValuesAsArray(dataMap, DataStore::getC);
_

次に、getValuesAsArrayは_Function<DataStore,Float>_パラメータを受け入れ、関数を実行します。

_private static float[] getValuesAsArray(Map<Integer, DataStore> dataMap, Function<DataStore,Float> func) {
    int i = 0;
    int nMap = dataMap.size();
    float[] fArray = new float[nMap];
    for (Map.Entry<Integer, DataStore> entry : dataMap.entrySet()) {
        DataStore ds = entry.getValue();
        fArray[i] = func.apply(ds);
        i++;
    }
    return fArray;
}
_

Java 8を使用せずに、DataStoreインスタンスを受け入れ、floatを返すメソッドを含む独自のインターフェースを定義できます。次に、=を使用する代わりにJava 8つのメソッド参照。getValuesAsArrayメソッドに、getX()の1つを呼び出すそのインターフェースの実装(インターフェースを実装する匿名クラスインスタンスを使用できます)を渡す必要があります。メソッド。

例えば ​​:

_public interface ValueGetter
{
    public float get (DataStore source);
}

float[] aArray = getValuesAsArray(dataMap, new ValueGetter() {public float get (DataStore source) {return source.getA();}});
float[] bArray = getValuesAsArray(dataMap, new ValueGetter() {public float get (DataStore source) {return source.getB();}});
float[] cArray = getValuesAsArray(dataMap, new ValueGetter() {public float get (DataStore source) {return source.getC();}});
_

そして

_private static float[] getValuesAsArray(Map<Integer, DataStore> dataMap, ValueGetter func) {
    int i = 0;
    int nMap = dataMap.size();
    float[] fArray = new float[nMap];
    for (Map.Entry<Integer, DataStore> entry : dataMap.entrySet()) {
        DataStore ds = entry.getValue();
        fArray[i] = func.get(ds);
        i++;
    }
    return fArray;
}
_
14
Eran

少し前にJava.util.concurrent.Callableを使用しましたが、@ Eranのおかげでうまくいかないようです。

代わりに、Java 8's Java.util.function.Functionを次のように使用できます(ラムダなし):

public static void main(String[] args) {
 //...
    getValuesAsArray(dataMap, new Function<DataStore,Float>(){ public Float apply(DataStore input) { return input.getA(); }});
    getValuesAsArray(dataMap, new Function<DataStore,Float>(){ public Float apply(DataStore input) { return input.getB(); }});
    getValuesAsArray(dataMap, new Function<DataStore,Float>(){ public Float apply(DataStore input) { return input.getC(); }});
}

private static float[] getValuesAsArray(Map<Integer, DataStore> dataMap, Function<DataStore, Float> function) {
    int i = 0;
    int nMap = dataMap.size();
    float[] fArray = new float[nMap];
    for (Map.Entry<Integer, DataStore> entry : dataMap.entrySet()) {
        DataStore ds = entry.getValue();
        fArray[i] = function.apply(ds);
        i++;
    }
    return fArray;
}
2
Julio D

MethodReferenceはリフレクション用のクラスです。実際には、コードにはラムダのようなオブジェクトが必要です。これは、Java 8。

Java 8またはリフレクションなしでは、直接あなたのニーズを満たす方法はありません。しかし、メソッドの内部表現を別のクラスにいつでも渡すことができます。そうするためには、次のコードを書く必要があります。この内部表現を処理します。

0
Earth Engine

回避策があります:Scala Java apis。

私はApacheを使用しますSparkおよびscalaは、Java 1.5以降で利用可能な一連の匿名関数(Function、Function2)を提供します) 、私が間違っていない場合(ただし、Java 1.7で使用します)。
これはこれについて話す答えです 。それ以外の場合、「関数」クラスはJava 1.8からのみ利用できます。

0
Vale