Java: 在一个块中使用 Catch 和 throws?
Java: Using Catch and throws in the one block?
catching
和下面的 throwing
和 Exception
有什么意义?两者都做是不好的做法吗?
try{
//something
} catch (Exception e){
throw new RuntimeException("reason for exception");
}
在您的示例中,捕获了 Exception
并抛出了 RuntimeException
,这有效地将(可能)已检查的异常替换为不必由调用者,也不由 throws
子句中的 throwing 方法声明。
一些例子:
此代码通过编译:
public void SomeMethod ()
{
try {
//something
} catch (Exception e){
throw new RuntimeException("reason for exception");
}
}
此代码未通过编译(假设 "something" 可能会抛出检查异常):
public void SomeMethod ()
{
//something
}
捕获 Exception
并抛出未经检查的异常(即 RuntimeException
)的替代方法是添加 throws
子句:
public void SomeMethod () throws Exception
{
//something
}
这是捕获一种异常并抛出另一种异常的用例。另一个用例是捕获一种类型的异常并抛出另一种类型的已检查异常(您的方法在其 throws
子句中声明)。有时这样做是为了将一个方法内部可能抛出的多个异常归为一组,只向方法的调用者抛出一种类型的异常(这使得他们更容易编写异常处理代码,并且如果所有这些异常应该以相同的方式处理)。
这称为重新抛出异常,这是一种常见模式。
它允许您更改异常的 class(例如在这种情况下),或者添加更多信息(这里也是这种情况,只要该错误字符串是有意义的)。
附加原始异常通常是个好主意:
throw new RuntimeException("cause of the problem", e);
当您仍然想抛出异常时,有时需要重新抛出一个未经检查的异常(RuntimeException),但您的方法的 API 不允许检查异常。
通常这样的代码用于重新包装异常,也就是转换异常的类型。通常,当您在方法中允许的异常受到限制时,您会这样做,但在内部可能会发生其他类型的异常。例如:
class MyServiceImplementaiton implements MyService {
void myService() throws MyServiceException { // cannot change the throws clause here
try {
.... // Do something
} catch(IOException e) {
// re-wrap the received IOException as MyServiceException
throw new MyServiceException(e);
}
}
}
这个惯用语能够继续向调用者传播异常,同时符合接口中的 throws 子句并隐藏内部细节(IOExceptions 可能发生的事实)。
在实践中,这总是比调用 e.printStackTrace()
更好,后者实际上 "swallow" 错误条件并让程序的其余部分 运行 就好像什么都没发生一样。在这方面,Eclipse 的行为非常糟糕,因为如果开发人员不小心,它往往会自动编写此类不良实践结构。
catching
和下面的 throwing
和 Exception
有什么意义?两者都做是不好的做法吗?
try{
//something
} catch (Exception e){
throw new RuntimeException("reason for exception");
}
在您的示例中,捕获了 Exception
并抛出了 RuntimeException
,这有效地将(可能)已检查的异常替换为不必由调用者,也不由 throws
子句中的 throwing 方法声明。
一些例子:
此代码通过编译:
public void SomeMethod ()
{
try {
//something
} catch (Exception e){
throw new RuntimeException("reason for exception");
}
}
此代码未通过编译(假设 "something" 可能会抛出检查异常):
public void SomeMethod ()
{
//something
}
捕获 Exception
并抛出未经检查的异常(即 RuntimeException
)的替代方法是添加 throws
子句:
public void SomeMethod () throws Exception
{
//something
}
这是捕获一种异常并抛出另一种异常的用例。另一个用例是捕获一种类型的异常并抛出另一种类型的已检查异常(您的方法在其 throws
子句中声明)。有时这样做是为了将一个方法内部可能抛出的多个异常归为一组,只向方法的调用者抛出一种类型的异常(这使得他们更容易编写异常处理代码,并且如果所有这些异常应该以相同的方式处理)。
这称为重新抛出异常,这是一种常见模式。
它允许您更改异常的 class(例如在这种情况下),或者添加更多信息(这里也是这种情况,只要该错误字符串是有意义的)。
附加原始异常通常是个好主意:
throw new RuntimeException("cause of the problem", e);
当您仍然想抛出异常时,有时需要重新抛出一个未经检查的异常(RuntimeException),但您的方法的 API 不允许检查异常。
通常这样的代码用于重新包装异常,也就是转换异常的类型。通常,当您在方法中允许的异常受到限制时,您会这样做,但在内部可能会发生其他类型的异常。例如:
class MyServiceImplementaiton implements MyService {
void myService() throws MyServiceException { // cannot change the throws clause here
try {
.... // Do something
} catch(IOException e) {
// re-wrap the received IOException as MyServiceException
throw new MyServiceException(e);
}
}
}
这个惯用语能够继续向调用者传播异常,同时符合接口中的 throws 子句并隐藏内部细节(IOExceptions 可能发生的事实)。
在实践中,这总是比调用 e.printStackTrace()
更好,后者实际上 "swallow" 错误条件并让程序的其余部分 运行 就好像什么都没发生一样。在这方面,Eclipse 的行为非常糟糕,因为如果开发人员不小心,它往往会自动编写此类不良实践结构。