【问题标题】:Java pass method reference as parameter to other methodJava将方法引用作为参数传递给其他方法
【发布时间】:2016-12-31 06:59:35
【问题描述】:

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

我有一个包含一些字段和获取方法的类:

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 实例化为 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;
    }
}

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

【问题讨论】:

  • 也许我只是个菜鸟,但你为什么需要在这里传递一个方法?这个程序想要完成什么?
  • @px06 - 实际的 DataStore 将有超过 3 个字段。我正在以随机方式收集该 dataMap 中的数据集。 treeMap 的键是与每个数据集相关联的稀疏整数集。在某些时候,我需要将各个字段值检索或输出为“排序”数组,其中应根据键整数进行排序。

标签: java methods parameters


【解决方案1】:

您的 getX() 方法可以看作是一个接受 DataStore 实例并返回浮点数的函数。

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

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

那么你的getValuesAsArray 将接受Function&lt;DataStore,Float&gt; 参数并执行函数:

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 的方法。然后,您必须将调用 getX() 方法之一的该接口的实现(您可以使用实现该接口的匿名类实例)传递给您的 getValuesAsArray 方法,而不是使用 Java 8 方法引用。

例如:

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

【讨论】:

  • @EarthEngine 它声明“Java 8 (Lambdas)” ...所以我认为建议功能接口是合法的。
  • @EarthEngine 我为 Java 8 之前的实现添加了一个建议,尽管它会不那么优雅。
  • @Eran Supplier 接口呢?我觉得这里会很合适。但我对新的 Java 8 东西不太熟悉 - 所以只是问问。
  • @Fildor A Supplier&lt;T&gt; 在不接受任何输入的情况下生成 T 类型的值。如果 getX() 方法是静态的,则适合这个问题。
  • @SwanAH 请参阅 Java 7 解决方案的编辑(不幸的是不太优雅)。
【解决方案2】:

不久前我使用了 java.util.concurrent.Callable 但它似乎没有成功,感谢@Eran。

相反,您可以使用 Java 8 的 java.util.function.Function,就像这样(没有 lambda):

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

【讨论】:

  • 根据问题,getA(),getB(),getC() 方法不是静态的。应该为 DataStore 的特定实例调用它们。
  • 我只是使用他的示例代码。这里的重点是,他可以用Callable 包装方法,以便以后调用该方法。
  • 如果getA() 是静态的,您只能调用DataStore.getA(),无论您是否使用Callable 包装它。
【解决方案3】:

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

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

【讨论】:

  • 抱歉,误导了。我只是将它用作一些适当机制的占位符,以在不使用 java 8 或反射的情况下传递我的方法。
【解决方案4】:

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

我使用 Apache Spark,Scala 提供了一系列匿名函数(Function、Function2),如果我没记错的话(尽管我在 Java 1.7 中使用它)。
Here is an answer talking about this。因为否则“Function”类只能从 Java 1.8 获得

【讨论】:

    【解决方案5】:
    猜你喜欢
    • 2015-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    相关资源
    最近更新 更多