【问题标题】:Passing a null function to java function as argument将 null 函数作为参数传递给 java 函数
【发布时间】:2020-05-13 07:59:51
【问题描述】:

我在理解函数如何作为参数传递给方法时遇到了问题。

在 StackOverflow 和 StackExchange 上搜索让我找到了使用 java.util.Functions 的解决方案

public void someFunction(Functions <int[], int[]> myFunction);

(来源:https://codereview.stackexchange.com/questions/186972/passing-a-generic-function-as-parameter)

虽然这个解决方案对我来说似乎不错,但当我需要传递一个什么都不做的函数时,我会遇到问题。为了更好地理解,请考虑以下示例:

public class Example {
    //do stuffs
    myFunction(null);
}

public class Manager {
    public void myFunction(Function<int[], void> funcToPass) { // Can't specify void as return value!
        //do stuff
        if(funcToPass != null) { // can't replicate such behaviour
            funcToPass(someParams)
        }
    }
}

有人可以帮助我清楚地了解这个主题吗?非常感谢。

【问题讨论】:

  • 一个Function没有返回只是一个Consumer
  • 我不认为这是一个有效的答案,因为我需要一个更一般的案例。消费者会限制我只考虑具有 Void 返回值的函数。
  • 确定不是一个有效的答案,它只是一个评论。但是如果您以这种方式定义您的方法,则无法 change 函数返回除声明的内容(Void)之外的任何内容 - 无论如何这对问题无关紧要,所以我将其发布为评论和不回答。为什么“不能复制这种行为”?应该使用 Java(假设函数声明正确)
  • 但它确实有效(再次,假设声明正确)
  • 仅供参考:funcToPass 将作为非原始类型 (mini-example) 的任何参数对实例的引用。在这种情况下实现Function,类型为Function

标签: java function class parameters void


【解决方案1】:

您可以使用反射 API 传递 void 方法作为参考,例如

import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) throws Exception {
        Class[] classParams = new Class[1];
        classParams[0] = String.class;
        Method method = Main.class.getMethod("hello", classParams);
        Main obj = new Main();
        System.out.println(new Main().getSum(obj, method, "world!", 10, 20));
    }

    public void hello(String msg) {
        System.out.println("Hello " + msg);
    }

    int getSum(Object object, Method method, String msg, int x, int y) throws Exception {
        Object[] objectParams = new Object[1];
        objectParams[0] = msg;
        method.invoke(object, objectParams);
        return x + y;
    }
}

输出:

Hello world!
30

【讨论】:

  • 虽然这确实有效,但类型安全和性能成本并不能证明在这种情况下使用反射是合理的,尤其是当有很好的替代解决方案时
  • 所以,如果我没记错的话,这可以通过将hello 方法的参数作为classParams classParams 类型的变量传递Class?
  • hello 方法的参数是"world!"。基本上,您将 method 作为 hello 方法的引用传递给 getSum 方法,从该方法您使用引用调用 hello 方法。
  • 微妙,但确实是一个可能的解决方案。
  • 感谢@KingPowa 的反馈。
【解决方案2】:

如果要描述一个不返回值的函数,可以使用Void 类型。这是一个标准的 Java 类,但旨在用于这种情况。

例如

Function<String, Void> stringPrinter = s -> {
    System.out.println(s);
    return null;  // must return some value, null is acceptable since there is no Void instance
};

return null; 很重要,因为从编译器的角度来看,Void 就像任何其他类(例如String、Integer 等)。它不知道它表示没有值,但它知道返回void 的函数没有返回值。

这意味着编译器仍然期望在你的代码中有一些return 语句,就像它返回一个Integer,所以你必须return null;

编辑:

但是,您可能会发现,如果您严格处理没有返回的函数,则更适合使用Consumer&lt;T&gt;。例如:

Consumer<String> stringPrinter = s -> System.out.println(s);
stringPrinter.accept("hello");

或者,使用方法引用:

Consumer<String> stringPrinter = System.out::println;
stringPrinter.accept("hello");

【讨论】:

  • 实际上return null 是唯一的选择,不仅仅是可以接受的,因为没有Void 的可能实例
  • 这意味着我可以使用返回 null 作为结果的 lambda 函数?
  • 另一个问题:那么不可能将null作为函数参数而不是这个place-filler函数传递?
  • null 是 Java 中所有类的有效值,因此您可以将null 传递给任何需要类的参数(即除int、long 之外的任何类型) .但是,如果function 是null,则调用function.apply(someValue) 将抛出NullPointerException。
  • 好吧,如果我只检查空值,我就解决了我的问题......现在试试这个
猜你喜欢
  • 2013-01-27
  • 1970-01-01
  • 2021-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
  • 2015-06-09
  • 1970-01-01
相关资源
最近更新 更多