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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39118268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:53:32  来源:igfitidea点击:

Java pass method reference as parameter to other method

javamethodsparameters

提问by SwanAH

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 notuse 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 as Parameter,但我无法以合理的方式采用接口方法来解决我的问题。我宁愿使用 java 8 (lambdas),如果可能的话也避免反射。我的感觉是,我以错误的方式看待我的问题。这是我试图完成的具体简化示例:

I have a class containing some fields and 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 DataStoreas 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(). 不知何故,我想,我的方法可能是错误的。所以我愿意接受建议。

采纳答案by Eran

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

您的getX()方法可以被视为一个函数,它接受一个 DataStore 实例并返回一个浮点数。

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 getValuesAsArraywill accept a Function<DataStore,Float>parameter and execute the function :

然后你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;
}

Without using Java 8, you can define your own interface that contains a method that accepts a DataStoreinstance and returns a float. Then, instead of using Java 8 method references, you would have to pass to your getValuesAsArraymethod 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;
}

回答by Earth Engine

MethodReferenceis 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,为此你必须编写代码来处理这个内部表示。

回答by Vale

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 以来可用的匿名函数(Function、Function2),如果我没记错的话(尽管我在 Java 1.7 中使用它)。
这是一个谈论这个的答案。因为否则“函数”类只能从 Java 1.8 中获得

回答by Julio D

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