Java传递方法引用作为其他方法的参数

时间:2022-04-27 23:17:47

I am trying to pass a selected "get"-method of class A to a method in class B. I have checked out Java Pass Method as Parameter, but I was not able to adopt the interface approach to my problem in a reasonable way. I would prefer to not use java 8 (lambdas) and if possible avoid reflection as well. My feeling is, that I am looking at my problem the wrong way. Here is the specific simplified example of what I am trying to accomplish:

我正在尝试将类A的选定“get”方法传递给B类中的方法。我已经将Java Pass Method作为参数检出,但我无法以合理的方式采用接口方法解决我的问题。我宁愿不使用java 8(lambdas),如果可能的话也要避免反射。我的感觉是,我以错误的方式看待我的问题。以下是我要完成的具体简化示例:

I have a class containing some fields and get-methods:

我有一个包含一些字段和get-methods的类:

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

}

Next I have my main class instantiating DataStore as Values of a Map and then accessing specific fields of DataStore like:

接下来,我让我的主类将DataStore实例化为Map的值,然后访问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;
    }
}

Clearly this wont work, as I have to figure out how to pass my selected get method into getValuesAsArray(). Somehow, I guess, my approach may be wrong. So I am open for suggestions.

显然这不会起作用,因为我必须弄清楚如何将我选择的get方法传递给getValuesAsArray()。不知怎的,我想,我的做法可能是错的。所以我愿意接受建议。

5 个解决方案

#1


8  

Your getX() methods can be seen as a Function that accepts a DataStore instance and returns a float.

您的getX()方法可以看作是一个接受DataStore实例并返回float的Function。

In Java 8 you can represent them with method references :

在Java 8中,您可以使用方法引用来表示它们:

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

Then your getValuesAsArray will accept a Function<DataStore,Float> parameter and execute the function :

然后你的getValuesAsArray将接受一个Function 参数并执行该函数: ,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;
}

Without using Java 8, you can define your own interface that contains a method that accepts a DataStore instance and returns a float. Then, instead of using Java 8 method references, you would have to pass to your getValuesAsArray method an implementation of that interface (you could use an anonymous class instance implementing the interface) which calls one of the getX() methods.

在不使用Java 8的情况下,您可以定义自己的接口,该接口包含接受DataStore实例并返回float的方法。然后,您不必使用Java 8方法引用,而是必须将getValuesAsArray方法传递给该接口的实现(您可以使用实现接口的匿名类实例),该实现调用getX()方法之一。

For example :

例如 :

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

And

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

#2


2  

Awhile ago I used java.util.concurrent.Callable but it doesn't seem to work out, thanks to @Eran.

前一段时间我使用了java.util.concurrent.Callable,但由于@Eran,它似乎无法解决。

Instead, you can use Java 8's java.util.function.Function, like so (without the lambdas):

相反,你可以使用Java 8的java.util.function.Function,就像这样(没有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;
}

#3


0  

MethodReference is a class for reflection purpose. Your code actually need a lambda-like object, which shall be a single method interface in Java 8.

MethodReference是一个用于反射目的的类。您的代码实际上需要一个类似lambda的对象,它应该是Java 8中的单个方法接口。

Without Java 8 or reflection there is no way to directally meet your need though. But you can always pass some internal representation of the method to another calss, and to do so you have to write code to process this internal representation.

没有Java 8或反射,没有办法直接满足您的需求。但是你总是可以将方法的一些内部表示传递给另一个calss,为此你必须编写代码来处理这个内部表示。

#4


0  

There is a workaround: Scala java apis.

有一个解决方法:Scala java apis。

I use Apache Spark and scala offers a series of Anonymous Functions (Function, Function2) which are available since Java 1.5, if I'm not mistaken (although I use it with Java 1.7).
Here is an answer talking about this. Because otherwise the "Function" class is available only from Java 1.8

我使用Apache Spark,scala提供了一系列自Java 1.5以来可用的匿名函数(函数,函数2),如果我没有弄错的话(尽管我在Java 1.7中使用它)。这是一个回答这个问题的答案。因为“Function”类只能从Java 1.8中获得

#5


-1  

You can use Command Design Pattern

您可以使用Command Design Pattern

for more info :

了解更多信息:

https://en.wikipedia.org/wiki/Command_pattern http://www.tutorialspoint.com/design_pattern/command_pattern.htm

#1


8  

Your getX() methods can be seen as a Function that accepts a DataStore instance and returns a float.

您的getX()方法可以看作是一个接受DataStore实例并返回float的Function。

In Java 8 you can represent them with method references :

在Java 8中,您可以使用方法引用来表示它们:

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

Then your getValuesAsArray will accept a Function<DataStore,Float> parameter and execute the function :

然后你的getValuesAsArray将接受一个Function 参数并执行该函数: ,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;
}

Without using Java 8, you can define your own interface that contains a method that accepts a DataStore instance and returns a float. Then, instead of using Java 8 method references, you would have to pass to your getValuesAsArray method an implementation of that interface (you could use an anonymous class instance implementing the interface) which calls one of the getX() methods.

在不使用Java 8的情况下,您可以定义自己的接口,该接口包含接受DataStore实例并返回float的方法。然后,您不必使用Java 8方法引用,而是必须将getValuesAsArray方法传递给该接口的实现(您可以使用实现接口的匿名类实例),该实现调用getX()方法之一。

For example :

例如 :

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

And

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

#2


2  

Awhile ago I used java.util.concurrent.Callable but it doesn't seem to work out, thanks to @Eran.

前一段时间我使用了java.util.concurrent.Callable,但由于@Eran,它似乎无法解决。

Instead, you can use Java 8's java.util.function.Function, like so (without the lambdas):

相反,你可以使用Java 8的java.util.function.Function,就像这样(没有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;
}

#3


0  

MethodReference is a class for reflection purpose. Your code actually need a lambda-like object, which shall be a single method interface in Java 8.

MethodReference是一个用于反射目的的类。您的代码实际上需要一个类似lambda的对象,它应该是Java 8中的单个方法接口。

Without Java 8 or reflection there is no way to directally meet your need though. But you can always pass some internal representation of the method to another calss, and to do so you have to write code to process this internal representation.

没有Java 8或反射,没有办法直接满足您的需求。但是你总是可以将方法的一些内部表示传递给另一个calss,为此你必须编写代码来处理这个内部表示。

#4


0  

There is a workaround: Scala java apis.

有一个解决方法:Scala java apis。

I use Apache Spark and scala offers a series of Anonymous Functions (Function, Function2) which are available since Java 1.5, if I'm not mistaken (although I use it with Java 1.7).
Here is an answer talking about this. Because otherwise the "Function" class is available only from Java 1.8

我使用Apache Spark,scala提供了一系列自Java 1.5以来可用的匿名函数(函数,函数2),如果我没有弄错的话(尽管我在Java 1.7中使用它)。这是一个回答这个问题的答案。因为“Function”类只能从Java 1.8中获得

#5


-1  

You can use Command Design Pattern

您可以使用Command Design Pattern

for more info :

了解更多信息:

https://en.wikipedia.org/wiki/Command_pattern http://www.tutorialspoint.com/design_pattern/command_pattern.htm