【问题标题】:Array Containing Methods/Functions for Argument Passing包含参数传递的方法/函数的数组
【发布时间】:2017-02-17 17:58:22
【问题描述】:

我有一个方法可以在数组的参数之间进行选择并返回一个特定的参数。例如,这里是那个方法:

private <T> T selectOnType(T[] selection, T defaultOp){
    switch(this.type){
        case Resources.TEXT:
            return selection[Resources.TEXT];
        case Resources.LISTEN:
            return selection[Resources.LISTEN];
        default:
            return defaultOp;
    }
}

如何构造一个充满方法引用(即函数指针)的数组,以便能够将该数组传递给上面的这个方法?

我尝试做这样的事情:

java.util.function.Function<Void, Void>[] array = {ClassA::method1, ClassA::method2};

(其中 method1 和 method1 不带参数并返回 void)

但这会引发编译器错误:

不兼容的类型:无效的方法引用,但预期没有参数。
    发现:java.lang.Void
    原因:实际参数列表和正式参数列表的长度不同

我一直在玩 lambda,例如:

() -> ClassA.method1()

但我无法让它工作。有谁知道我做错了什么并且知道解决这个问题的方法?

编辑: 我在 Stack Overflow 上看到过this,但这是针对 C# 的,我还没有弄清楚如何在 Java 中模仿它。

示例:
假设我有一个Word 类:

public class Word{
    private final String text;
    private int listenCorrect = 0, textCorrect = 0;
    public Word(final String test){
        this.text = text;
    }
    public void incListenCorrect(){
        listenCorrect++;
    }
    public void incTextCorrect(){
        textCorrect--;
    }
}

最后我有一个Main 课程。在action 方法内(在Main 类中)我想要一个包含这两种方法的数组,以便在type(如下所示)是listentext 时在它们之间进行选择:

public class Main{
    int type = 0;
    public void action(){
        Word word = new Word("Hello");
        // 'Functions' is used to represent something I tried above (just for demonstration)
        Function[] array = {word::incListenCorrect, word::incTextCorrect};
        Function picked = selectOnType(array, word::incTextCorrect);
        picked.call();
    }
    /*
     *  Resources is another class that contains the following values:
     *            public static final int TEXT       = 0;
     *            public static final int LISTEN     = 1;
     */
    private <T> T selectOnType(T[] selection, T defaultOp){
        switch(this.type){
            case Resources.TEXT:
                return selection[Resources.TEXT];
            case Resources.LISTEN:
                return selection[Resources.LISTEN];
            default:
                return defaultOp;
        }
    }
}

【问题讨论】:

  • method1method2 是实例方法还是静态方法?
  • 你的方法不等同于Function&lt;Void, Void&gt;,而是Runnable
  • @ajb 看看我包含的示例;它们是实例方法。
  • 使用Runnable 的列表,如List&lt;Runnable&gt; array = Arrays.asList(word::incListenCorrect, word::incTextCorrect);

标签: java arrays java-8 function-pointers method-reference


【解决方案1】:

Function 是一种接受一个参数并返回结果的方法。您正在使用不带参数且不返回结果的方法。您不能为此使用Function(使用Void 不是解决此问题的方法),但the java.util.function 包包含许多用于不同常见组合的类(不带参数但返回结果的方法, 采用一个或两个参数但不返回结果的方法, 采用原始参数或返回原始结果的方法在Function 中不起作用, 因为类型不是类类型等)。

java.util.function 中没有用于没有参数也没有结果的函数式接口的类,但 Runnable 可以用于此。

您需要确保使用正确的界面。

注意:我假设 method1method2 是静态方法,因此它们不接受任何参数,即使是实例方法所采用的隐藏“实例”参数。如果它们是实例方法,则必须以不同的方式完成。

既然您已经澄清了它们是实例方法,那么情况就不同了——但这取决于您如何获得该方法。如果你说

Word::incListenCorrect

由于您使用的是类名,因此您需要提供实例作为参数。因此,Word::incListenCorrect 为带有一个参数的方法返回一个函数接口,例如Consumer&lt;Word&gt;,并且当您使用.accept() 调用该方法时,您必须将Word 作为参数传递。 但是

word::incListenCorrect

非常不同。现在,word 实例被“烘焙到”方法引用中,因此它不需要作为参数传递。因此,在这种情况下,您仍然需要不带参数且不返回值的接口,即Runnable。当你说

Runnable r = word::incListenCorrect;    
r.run();

如果rRunnable,它将自动使用word 作为实例方法的实例,因为当您将方法引用分配给word 时,它成为r 的一部分。

【讨论】:

  • 我会看看这个。另外,请查看我添加的示例,以进一步说明我在做什么(即它们不是静态方法)
  • 你,我的朋友,太棒了! :) 给你一个快速的问题,如果我有一个实例方法(如上面的例子),它接受“x”个参数并返回一个结果,我会使用 lambdas 吗?我想我不能再将它包装到 Runnable 对象中了,因为 run() 方法不接受任何参数并且是一个 void 函数,那么我将它包装成什么呢?
  • 这里的问题是您需要正确的类型,无论是RunnableConsumer&lt;T&gt;Function&lt;T,U&gt; 还是其他类型。如果有 1 或 2 个参数,您可以使用 java.util.function 中的接口之一(除非某些参数是原始类型,然后您可能会也可能不会)。如果有 >=3 个参数,则需要定义自己的接口类型,然后可以使用方法引用。 lambda 不会帮助您解决定义自己的类型的需要。
  • 因此,public int echo(int x) { return x; } 之类的函数将无法被 java.util.function 使用,因为原始类型(如上所述),但我可以创建一个接口,就像你说的那样,能够处理这样的事情吗?还是我强制将基元包装在对象中?
  • 实际上,java.util.function 确实有 IntUnaryOperator 能够处理这种功能。您只需查看那里列出的类并确定它是否受支持。如果不支持,那么可以,您可以创建自己的界面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-21
  • 2015-12-21
  • 2016-12-18
  • 2019-01-07
相关资源
最近更新 更多