抛出(和捕获)Throwable(或异常)通常是不好的做法,因为它会“掩盖”您可能想要捕获的任何特定异常。那么你将不得不诉诸如下丑陋:
public void myMethod() throws Throwable {
if (x) {
throw new MyException1();
}
if (y) {
throw new MyException2();
}
}
public void callingMethod() {
try {
myMethod();
}
catch(Throwable t) {
if (t instanceof MyException1) {
// handle exception 1
}
else if (t instanceof MyException2) {
// handle exception 2
}
else {
// handle other exceptions
}
}
}
这很容易出错(并被 CheckStyle 标记为代码违规)。最好有这样的代码:
public void myMethod() throws MyException1, MyException2 {
if (x) {
throw new MyException1();
}
if (y) {
throw new MyException2();
}
}
public void callingMethod() {
try {
myMethod();
}
catch(MyException1 e) {
// handle exception 1
}
catch(MyException2 e) {
// handle exception 2
}
}
仅仅通过调用 printStackTrace() 来处理异常通常不是一个好主意。 printStackTrace() 将堆栈跟踪发送到标准错误,可能根本无法读取。更好的选择是使用应用程序的日志记录工具(如 log4j)来报告异常。即便如此,仅仅记录它可能还不够。
我的经验法则是:
如果您可以在本地处理异常,请执行此操作。例如,当将 String 解析为 Integer 时,您可以捕获 NumberFormatException 并返回默认值:
prvate int parseAmount(String amountValue) {
int amount;
try {
amount = Integer.parseInt(amountValue);
}
catch(NumberFormatException e) {
// default amount
amount = 0;
}
return amount;
}
如果您无法在本地处理异常,请考虑是否应该公开正在抛出的异常类型。如果此类型是某种晦涩的(依赖于实现的)类型,那么将其包装在您自己的通用异常类型中可能是个好主意:
private Customer getCustomer(int customerId) throws ServiceException {
try {
return customerService.getCustomer(customerId);
}
catch(CustomerServiceSpaghettiTangledException e) {
throw new ServiceException("Error calling the customer service", e);
}
}
这里的“ServiceException”是您创建的 Exception 的子类。 Spring 还专门为此目的提供了exception hierarchy。
通过包装异常,您可以隐藏实现细节,让您的服务层更易于使用。
如果您决定从您的方法中抛出异常,您将需要在调用堆栈中“更高”地处理它。这可以是您的 Web 应用程序中的通用错误页面,说明出现问题并可能提供错误消息或代码。在某些情况下,更高级别的代码可以尝试重试或可能的替代方法来获得所需的结果。