web-dev-qa-db-fra.com

Référence de la méthode de transmission Java en tant que paramètre d'une autre méthode

J'essaie de transmettre une méthode "get" sélectionnée de la classe A à une méthode de la classe B. J'ai vérifié Méthode Java Pass en tant que paramètre , mais je n'ai pas pu adopter l'approche d'interface pour mon problème dans d'une manière raisonnable. Je préférerais pas utiliser Java 8 (lambdas) et si possible éviter toute réflexion. Mon sentiment est que je regarde mon problème de la mauvaise façon. Voici l'exemple simplifié spécifique de ce que j'essaie d'accomplir:

J'ai une classe contenant des champs et méthodes 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;
    }

}

Ensuite, ma classe principale instancie DataStore en tant que valeurs d'une mappe, puis accède à des champs spécifiques de DataStore, tels que:

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;
    }
}

Il est clair que cela ne fonctionnera pas, car je dois trouver comment passer la méthode get sélectionnée à getValuesAsArray(). D'une manière ou d'une autre, je suppose que mon approche est peut-être fausse. Je suis donc ouvert aux suggestions. 

7
SwanAH

Vos méthodes getX() peuvent être considérées comme une fonction qui accepte une instance DataStore et renvoie un float.

En Java 8, vous pouvez les représenter avec des références de méthodes:

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

Ensuite, votre getValuesAsArray acceptera un paramètre Function<DataStore,Float> et exécutera la fonction:

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;
}

Sans utiliser Java 8, vous pouvez définir votre propre interface contenant une méthode qui accepte une instance DataStore et renvoie une float. Ensuite, au lieu d’utiliser des références de méthodes Java 8, vous devrez transmettre à votre méthode getValuesAsArray une implémentation de cette interface (vous pouvez utiliser une instance de classe anonyme implémentant l’interface) qui appelle l’une des méthodes getX().

Par exemple :

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();}});

Et

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;
}
10
Eran

Il y a quelque temps, j'utilisais Java.util.concurrent.Callable, mais cela ne semble pas fonctionner, grâce à @Eran.

Au lieu de cela, vous pouvez utiliser le Java.util.function.Function de Java 8, comme suit (sans les lambdas):

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 est une classe à des fins de réflexion. Votre code nécessite en réalité un objet de type lambda, qui doit être une interface de méthode unique en Java 8.

Sans Java 8 ni réflexion, il n’existe aucun moyen de répondre directement à vos besoins. Mais vous pouvez toujours passer une représentation interne de la méthode à un autre serveur, et pour ce faire, vous devez écrire du code pour traiter cette représentation interne.

0
Earth Engine

Il existe une solution de contournement: Scala Java apis.

J'utilise Apache Spark et scala propose une série de fonctions anonymes (Function, Function2) disponibles depuis Java 1.5, si je ne me trompe pas (même si je l'utilise avec Java 1.7).
Voici une réponse à ce sujet . Sinon, la classe "Fonction" est uniquement disponible à partir de Java 1.8.

0
Vale