是“抛出可扔”的好习惯

在过去,我会用以下方法阅读大量代码:

public Object doSomething() throws Throwable { ... } 

通常的做法是这样做吗?

什么是利弊?

throws Trowable在我看来就像“特工橘子”的方式来完成Exception一样

编辑


  1. 处理方法中的预期exception

  2. 抛出意外的exception(逐个)

  3. 不关心错误

这是要走的路吗?

你不应该抛出Throwable 。 这就是原因。

Throwable是可抛出的事物层次结构的顶层,由ExceptionsErrors 。 由于定义中的Errors源于不可挽回的条件,因此将它们包含在方法声明中是没有意义的。 这只留下了Exception

您应该使用throws Exception声明您的方法。

请注意, throws的范围越窄越好。

声明您的方法被throws Exception是好的,如果您的方法不生成exception,而是调用其他声明为throws Exception代码,并且您希望exception渗透调用堆栈。

如果你的方法是生成exception,那么声明一个更窄的范围,例如throws IOException, MyProcessingException

这是一个有问题的问题。 这与exception处理无关,因为它与代码可读性有关。

这取决于您从哪里获取代码示例。 抛出一种方法时,专业人员更喜欢更具体。 主要原因是它使您的API更具可读性。 例如,如果你的方法抛出Throwable,那基本上意味着任何事情都可能发生,你的方法也不想处理它,无论如何。 但实际上,只有少数事情可能发生:

  • 无论您在方法中进行的其他调用所导致的检查exception
  • 无论检查的exception是什么,你都会根据自己的断言投掷目的
  • 无论你没有计划的任何未经检查的例外
  • 错误( java.lang.Error )对JVM和环境更全面

通过专门陈述您要抛出的exception,您告诉API的用户他们应该注意什么。 例如,当您使用InputStream ,您会注意到大多数方法至少抛出java.io.IOException ,它会为您提供有关您应该注意的内容的一些有用信息。

编码时,作为一般规则,您希望尽可能保持API的表现力。 你基本上有一行代码来显示一个方法的公共API(即它的签名,我猜的注释),所以你想要它完全表达(返回类型,名称,参数,但也抛出exception)。

至于捕获throwable并打印堆栈跟踪,我会说你不应该捕获exception,除非你可以对它做些什么。 相反,让它汇总调用堆栈,直到某个类捕获它来执行某些操作。 有时候,它可能会一直滚动到你的主类,我想它必须抓住它并打印堆栈跟踪作为最后的手段。 基本上,如果你不能对exception采取行动,那么让它上升到调用堆栈。 此外,你发现自己处于一种你应该使exception沉默的情况下极为罕见(即抓住它但却什么都不做)。 在解决问题时,通常会引发问题。

这是一篇有趣但有趣的文章,关于滥用exception处理。

从function上讲,它与throws Exception等效,因为错误是未选中的。

我认为没有理由声明抛出Throwable的方法。 但是,这并不意味着catch和printStackTrace是一个不错的选择。

通常情况下,你想捕捉扔掉的东西,你可以用它们做一些合理的事情。

抛出一个你不期望的throwable的代码应该光荣地爆炸,所以你可以看到错误并修复bug。

通常的做法是这样做吗?

在JDK中很少见。 当不清楚如何处理已检查的exception时,主要使用此方法。

什么是利弊?

优点是您可以编译代码而无需担心已检查的exception

缺点是您应该处理的exception被忽略。

catch和printStackTrace()不是更好吗?

通常打印未处理的exception,因此捕获它们并没有多大帮助。

当你可以添加一些值时,你应该捕获一个exception,并在你不能的时候将exception添加到throws子句。

这是值得商榷的事情。 让方法抛出太多exception将导致大量error handling代码。 有时它不是有意的。

但是因为我不喜欢签名中的太多exception并不意味着让Lets使用所有exception的Parent而我们已经完成了!! 不起作用。

可以做的是对诸如BusinessExceptionServiceException类的exception进行分类,这样如果你有一个业务规则,说明minimum balance in account can not be less than say 100$中的minimum balance in account can not be less than say 100$那么将生成InsufficientBalanceexception,它将是BusinessException子代。

所以你的方法就像

 public Object doSomething() throws BusinessException { if(!hasMinimumbalance()) { throw new InsufficientBalance(ErrorCode); } } 

这将做的是与俱乐部相关的exception在一起,并且每当API用户想要检测exception特定错误然后他可以做到,否则通用error handling是可能的。

这里的核心要点是在用户界面上你应该向用户显示你已经失去了平衡而你无法取款

您可以说在更大的方面显示人类可读的错误forms,确实需要分离exception。

在极少数情况下,抛出Throwable是可以接受的。 例如,Spring AOP中的@Around建议通常被声明为抛出Throwable

以下示例是从Spring AOP docs逐字复制的:

  import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.ProceedingJoinPoint; @Aspect public class AroundExample { @Around("com.xyz.myapp.SystemArchitecture.businessService()") public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { // start stopwatch Object retVal = pjp.proceed(); // stop stopwatch return retVal; } } 

为什么声明doBasicProfiling抛出Throwable ? 因为原始方法(即执行连接点)可能会抛出ErrorRuntimeException或者已检查的exception。 因此,只有声明doBasicProfiling才能抛出Throwable才有意义。

你是专门询问Throwable吗? 如果是这样,那么这不是一个好习惯。 它不向类(方法)用户提供任何有用的信息。

投掷(和捕获)Throwable(或Exception)通常是不好的做法,因为它“覆盖”您可能想要捕获的任何特定exception。 然后你将不得不诉诸丑陋如下:

 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()来处理exception通常不是一个好主意。 printStackTrace()将堆栈跟踪发送到标准错误,可能根本无法读取。 更好的选择是使用应用程序的日志记录工具(如log4j)来报告exception。 即便如此,只记录它可能还不够。

我的经验法则是:

如果您可以在本地处理exception,请执行此操作。 例如,在将String解析为Integer时,您可以捕获NumberFormatException并返回默认值:

 prvate int parseAmount(String amountValue) { int amount; try { amount = Integer.parseInt(amountValue); } catch(NumberFormatException e) { // default amount amount = 0; } return amount; } 

如果您无法在本地处理exception,请考虑是否应公开正在抛出的exception类型。 如果这种类型是一些模糊的(依赖于实现的)类型,那么将它包装在您自己的通用exception类型中可能是一个好主意:

 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层次结构 。

通过包装exception,您可以隐藏实现细节,使您的服务层更易于使用。

如果您决定从方法中抛出exception,则需要在callstack中“更高”处理它。 这可能是Web应用程序中的一般错误页面,指出出现问题并可能提供错误消息或代码。 在某些情况下,更高级别的代码可以尝试重试,或者可能是获得所需结果的替代方法。