为什么一个方法引用ctor“抛出”……抛出?

我正在寻找一种优雅的方式来创建一个dependency injection工厂。 在我的例子中,工厂只需调用一个参数构造函数。 我找到了这个答案,概述了如何将Function用于此类目的。

但我的问题是:在我的情况下,我的ctor声明抛出一些检查exception。

我没有得到:使用对该构造函数的方法引用创建该函数不起作用。 如:

 import java.util.function.Function; public class Mcve { public Mcve(String s) throws Exception { // whatever } public static void main(String[] args) { Function mcveFactory = Mcve::new; } } 

告诉我关于Mcve::new “Unhandled exception:java.lang.Exception”。 虽然这段代码没有调用构造函数。

两个问题:

  • 为什么那个错误? 上面的代码没有调用ctor(还)?
  • 有没有优雅的方法来解决这个难题? (简单地向我的main()添加throws Exception 没有帮助)

您需要提供一个自定义接口ThrowingFunction ,它有一个抛出Exception方法。

 public interface ThrowingFunction { ReturnType invoke(ParameterType p) throws Exception; } public class Mcve { public Mcve(String s) throws Exception { // whatever } public static void main(String[] args) { ThrowingFunction mcveFactory = Mcve::new; } } 

使用这种方法导致调用mcveFactory.invoke("lalala"); 强制你处理构造函数抛出的exception。

错误的原因是您要存储的实际函数引用(不是100%确定术语)会引发exception,因此类型根本不匹配。 如果你可以将Mcve::new存储在一个函数中,那么调用该函数的人不再知道可以抛出exception。 如果实际抛出exception会怎么样? 抛出exception并丢弃它都不起作用。


替代方案:如果您需要实际检索Function ,那么您需要编写一个调用构造函数的函数(或lambda),捕获exception并将其丢弃或重新抛出包装在未经检查的RuntimeException

 public class Mcve { public Mcve(String s) throws Exception { // whatever } public static void main(String[] args) { Function mcveFactory = parameter -> { try { return new Mcve(parameter); } catch (Exception e) { throw new RuntimeException(e); // or ignore } }; } } 

我认为错误消息本身至少有点误导,因为你通常在实际调用方法时会看到它。 我当然可以理解导致第一个子问题的混乱。 更清楚(遗憾的是不可能)陈述类似的东西

不兼容的类型Function vs. Function throws Exception

我最近不得不这样做…如果你可以改变类定义,你可以使用臭名昭着的鬼鬼祟祟的做法:

 static class OneArg { private final String some; @SuppressWarnings("unchecked") public  OneArg(String some) throws E { try { this.some = some; // something that might throw an Exception... } catch (Exception e) { throw (E) e; } } public String getSome() { return some; } } Function mcveFactory = OneArg::new; 

我一直在思考这个问题,确实如果你想要一个能明确宣告你的意图的Function ,我认为你需要有一个扩展java.util.FunctionFunction ,如下所示:

 @FunctionalInterface public interface ThrowingFunction extends Function { R applyWithExc(T t) throws Exception; @Override default R apply(T t) { try { return applyWithExc(t); } catch (Exception e) { throw new RuntimeException(e); } } } 

你可以在定义构造函数引用时选择你调用的方法 – 一个抛出Exception ,另一个用RuntimeException静默包装它的方法。