为什么方法引用了 "throws" ... 也抛出的 ctor?
Why does a method reference to ctor that "throws" ... throw as well?
我正在寻找一种优雅的方式来创建依赖注入工厂。在我的例子中,工厂只需调用一个单参数构造函数。我发现此 概述了如何将 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
的 "Unhandled exception: java.lang.Exception"。虽然这段代码不是调用构造函数。
两个问题:
- 为什么会出现这个错误?上面的代码不调用ctor(还)?
- 有什么优雅的方法可以解决这个难题吗? (简单地将
throws Exception
添加到我的 main()
中 没有 帮助)
您需要提供一个自定义接口 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
}
};
}
}
我认为错误消息本身至少有点误导,因为您通常在实际调用该方法时会看到它。我当然可以理解导致第一个子问题的混乱。像
这样的陈述会更清楚(遗憾的是不可能)
Incompatible types Function<String,Mcve>
vs. Function<String,Mcve> throws Exception
.
我最近不得不这样做...如果您 可以 更改 class 定义,您可以使用臭名昭著的偷偷摸摸的 throws 做事方式:
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;
我已经考虑了一段时间,确实 - 如果你想要一个 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
默默地包装它。
我正在寻找一种优雅的方式来创建依赖注入工厂。在我的例子中,工厂只需调用一个单参数构造函数。我发现此 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
的 "Unhandled exception: java.lang.Exception"。虽然这段代码不是调用构造函数。
两个问题:
- 为什么会出现这个错误?上面的代码不调用ctor(还)?
- 有什么优雅的方法可以解决这个难题吗? (简单地将
throws Exception
添加到我的main()
中 没有 帮助)
您需要提供一个自定义接口 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
}
};
}
}
我认为错误消息本身至少有点误导,因为您通常在实际调用该方法时会看到它。我当然可以理解导致第一个子问题的混乱。像
这样的陈述会更清楚(遗憾的是不可能)Incompatible types
Function<String,Mcve>
vs.Function<String,Mcve> throws Exception
.
我最近不得不这样做...如果您 可以 更改 class 定义,您可以使用臭名昭著的偷偷摸摸的 throws 做事方式:
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;
我已经考虑了一段时间,确实 - 如果你想要一个 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
默默地包装它。