我正在寻找一种优雅的方法来创建一个依赖注入工厂。在我的例子中,工厂只需要调用一个参数构造函数。我发现此answer概述了如何将Function<ParamType, ClassToNew>
用于此类目的。
但我的问题是:在我的情况下,我的ctor宣布抛出一些已检查的异常。
我没有得到:使用对该构造函数的方法引用创建 Function 不起作用。如:
import java.util.function.Function;
public class Mcve {
public Mcve(String s) throws Exception {
// whatever
}
public static void main(String[] args) {
Function<String, Mcve> mcveFactory = Mcve::new;
}
}
告诉我Mcve::new
的“未处理的异常:java.lang.Exception”。虽然此代码不调用构造函数。
两个问题:
throws Exception
添加到我的main()
不帮助答案 0 :(得分:23)
您需要提供一个自定义界面ThrowingFunction
,其中有一个方法会抛出Exception
。
public interface ThrowingFunction<ParameterType, ReturnType> {
ReturnType invoke(ParameterType p) throws Exception;
}
public class Mcve {
public Mcve(String s) throws Exception {
// whatever
}
public static void main(String[] args) {
ThrowingFunction<String, Mcve> mcveFactory = Mcve::new;
}
}
使用此方法会导致调用mcveFactory.invoke("lalala");
强制您处理构造函数抛出的异常。
错误的原因是您要存储的实际函数引用(不是100%确定术语)会引发异常,因此类型根本不匹配。 如果你可以将Mcve::new
存储在一个函数中,那么无论谁调用该函数不再知道都可以抛出Exception
。如果实际抛出异常会怎么样?抛出异常并丢弃它都不起作用。
替代方案:如果你最后需要实际检索Function<String, Mcve>
那么你需要编写一个调用构造函数的函数(或lambda),捕获异常并将其丢弃或重新抛出包装在未选中的内容中RuntimeException
。
public class Mcve {
public Mcve(String s) throws Exception {
// whatever
}
public static void main(String[] args) {
Function<String, Mcve> mcveFactory = parameter -> {
try {
return new Mcve(parameter);
} catch (Exception e) {
throw new RuntimeException(e); // or ignore
}
};
}
}
我认为错误消息本身至少有点误导,因为你在实际调用方法时通常会看到它。我当然可以理解导致第一个子问题的混乱。更明确(遗憾的是不可能)陈述类似
的内容不兼容的类型
Function<String,Mcve>
与Function<String,Mcve> throws Exception
。
答案 1 :(得分:2)
我最近必须这样做......如果可以更改类定义,你可以使用臭名昭着的偷偷摸摸的做法:
static class OneArg {
private final String some;
@SuppressWarnings("unchecked")
public <E extends Exception> 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<String, OneArg> mcveFactory = OneArg::new;
答案 2 :(得分:1)
我一直在思考这个问题,确实如果你想要Function
明确说明你的意图,我认为你需要Function
来扩展java.util.Function
,像这样:
@FunctionalInterface
public interface ThrowingFunction<T, R> extends Function<T, R> {
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
静默包装它的方法。