如何包装已检查的异常但将原始运行时异常保留在 Java 中
How to wrap checked exceptions but keep the original runtime exceptions in Java
我有一些代码可能会抛出检查异常和运行时异常。
我想捕获已检查的异常并将其包装为运行时异常。但是如果抛出 RuntimeException,我不必包装它,因为它已经是一个运行时异常。
我的解决方案有点开销,不是 "neat":
try {
// some code that can throw both checked and runtime exception
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
有没有更优雅的方法?
不是真的。
如果你经常这样做,你可以把它藏在辅助方法中。
static RuntimeException unchecked(Throwable t){
if (t instanceof RuntimeException){
return (RuntimeException) t;
} else if (t instanceof Error) { // if you don't want to wrap those
throw (Error) t;
} else {
return new RuntimeException(t);
}
}
try{
// ..
}
catch (Exception e){
throw unchecked(e);
}
我使用 "blind" 重新抛出来传递已检查的异常。我已经使用它来通过 Streams API ,在那里我不能使用抛出检查异常的 lambda。例如,我们有 ThrowingXxxxx 功能接口,因此可以传递已检查的异常。
这让我可以自然地在调用者中捕获检查异常,而无需知道被调用者必须通过不允许检查异常的接口传递它。
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
throw rethrow(e);
}
在调用方法中我可以再次声明检查异常。
public void loadFile(String file) throws IOException {
// call method with rethrow
}
/**
* Cast a CheckedException as an unchecked one.
*
* @param throwable to cast
* @param <T> the type of the Throwable
* @return this method will never return a Throwable instance, it will just throw it.
* @throws T the throwable as an unchecked throwable
*/
@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
throw (T) throwable; // rely on vacuous cast
}
处理异常有很多不同的选项。我们使用其中的一些。
https://vanilla-java.github.io/2016/06/21/Reviewing-Exception-Handling.html
您可以使用 instanceof 运算符重写相同的内容
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw e;
} else {
throw new RuntimeException(e);
}
}
不过,您的解决方案看起来更好。
Guava 的 Throwables.propagate()
正是这样做的:
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
throw Throwables.propagate(e);
}
更新:此方法现已弃用。有关详细说明,请参阅 this page。
问题是 Exception
太宽泛了。您应该确切知道可能的已检查异常是什么。
try {
// code that throws checked and unchecked exceptions
} catch (IOException | SomeOtherException ex) {
throw new RuntimeException(ex);
}
这不起作用的原因揭示了应该解决的更深层次的问题:
如果一个方法声明它 throws Exception
那么它就太宽泛了。知道 "something can go wrong" 没有更多信息对调用者没有用。该方法应该在有意义的层次结构中使用特定的异常 类,或者在适当的情况下使用未经检查的异常。
如果一个方法抛出太多不同种类的检查异常,那么它就太复杂了。它应该被重构为多个更简单的方法,或者异常应该被安排在一个合理的继承层次结构中,视情况而定。
当然也有例外。如果某种横切框架(例如 JUnit 或 AspectJ 或 Spring)使用方法而不是包含一个 API 供其他人使用,则声明方法 throws Exception
可能是完全合理的。
我通常使用相同类型的代码结构,但在三元运算符实际上使代码更好的几次之一中将其压缩为一行:
try {
// code that can throw
}
catch (Exception e) {
throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e);
}
这不需要额外的方法或 catch
块,这就是我喜欢它的原因。
我有一个专门编译的 .class 文件,其中包含以下内容:
public class Thrower {
public static void Throw(java.lang.Throwable t) {
throw t;
}
}
它很管用。 java 编译器通常会拒绝编译它,但字节码验证器根本不在乎。
class 的用法类似于 Peter Lawrey 的回答:
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
Thrower.Throw(e);
}
lombok 已通过方法上的简单注释处理此问题
示例:
import lombok.SneakyThrows;
@SneakyThrows
void methodThatUsusallyNeedsToDeclareException() {
new FileInputStream("/doesn'tMatter");
}
在示例中,方法应该声明 throws FileNotFoundException
,但使用 @SneakyThrows
注释时,它没有声明。
在幕后实际发生的是 lombok 对同一个问题使用与 相同的技巧。
任务完成!
我有一些代码可能会抛出检查异常和运行时异常。
我想捕获已检查的异常并将其包装为运行时异常。但是如果抛出 RuntimeException,我不必包装它,因为它已经是一个运行时异常。
我的解决方案有点开销,不是 "neat":
try {
// some code that can throw both checked and runtime exception
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
有没有更优雅的方法?
不是真的。
如果你经常这样做,你可以把它藏在辅助方法中。
static RuntimeException unchecked(Throwable t){
if (t instanceof RuntimeException){
return (RuntimeException) t;
} else if (t instanceof Error) { // if you don't want to wrap those
throw (Error) t;
} else {
return new RuntimeException(t);
}
}
try{
// ..
}
catch (Exception e){
throw unchecked(e);
}
我使用 "blind" 重新抛出来传递已检查的异常。我已经使用它来通过 Streams API ,在那里我不能使用抛出检查异常的 lambda。例如,我们有 ThrowingXxxxx 功能接口,因此可以传递已检查的异常。
这让我可以自然地在调用者中捕获检查异常,而无需知道被调用者必须通过不允许检查异常的接口传递它。
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
throw rethrow(e);
}
在调用方法中我可以再次声明检查异常。
public void loadFile(String file) throws IOException {
// call method with rethrow
}
/**
* Cast a CheckedException as an unchecked one.
*
* @param throwable to cast
* @param <T> the type of the Throwable
* @return this method will never return a Throwable instance, it will just throw it.
* @throws T the throwable as an unchecked throwable
*/
@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
throw (T) throwable; // rely on vacuous cast
}
处理异常有很多不同的选项。我们使用其中的一些。
https://vanilla-java.github.io/2016/06/21/Reviewing-Exception-Handling.html
您可以使用 instanceof 运算符重写相同的内容
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw e;
} else {
throw new RuntimeException(e);
}
}
不过,您的解决方案看起来更好。
Guava 的 Throwables.propagate()
正是这样做的:
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
throw Throwables.propagate(e);
}
更新:此方法现已弃用。有关详细说明,请参阅 this page。
问题是 Exception
太宽泛了。您应该确切知道可能的已检查异常是什么。
try {
// code that throws checked and unchecked exceptions
} catch (IOException | SomeOtherException ex) {
throw new RuntimeException(ex);
}
这不起作用的原因揭示了应该解决的更深层次的问题:
如果一个方法声明它 throws Exception
那么它就太宽泛了。知道 "something can go wrong" 没有更多信息对调用者没有用。该方法应该在有意义的层次结构中使用特定的异常 类,或者在适当的情况下使用未经检查的异常。
如果一个方法抛出太多不同种类的检查异常,那么它就太复杂了。它应该被重构为多个更简单的方法,或者异常应该被安排在一个合理的继承层次结构中,视情况而定。
当然也有例外。如果某种横切框架(例如 JUnit 或 AspectJ 或 Spring)使用方法而不是包含一个 API 供其他人使用,则声明方法 throws Exception
可能是完全合理的。
我通常使用相同类型的代码结构,但在三元运算符实际上使代码更好的几次之一中将其压缩为一行:
try {
// code that can throw
}
catch (Exception e) {
throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e);
}
这不需要额外的方法或 catch
块,这就是我喜欢它的原因。
我有一个专门编译的 .class 文件,其中包含以下内容:
public class Thrower {
public static void Throw(java.lang.Throwable t) {
throw t;
}
}
它很管用。 java 编译器通常会拒绝编译它,但字节码验证器根本不在乎。
class 的用法类似于 Peter Lawrey 的回答:
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
Thrower.Throw(e);
}
lombok 已通过方法上的简单注释处理此问题
示例:
import lombok.SneakyThrows;
@SneakyThrows
void methodThatUsusallyNeedsToDeclareException() {
new FileInputStream("/doesn'tMatter");
}
在示例中,方法应该声明 throws FileNotFoundException
,但使用 @SneakyThrows
注释时,它没有声明。
在幕后实际发生的是 lombok 对同一个问题使用与
任务完成!