过去对我有帮助的准则包括:
- 当方法无法处理异常时引发异常 ,更重要的是,应由调用方处理。一个很好的例子出现在Servlet API中-在某些无法正确读取请求的情况下,doGet()和doPost()抛出ServletException或IOException。这两种方法均不能处理异常,但是容器是(在大多数情况下,导致50x错误页面)。
- 如果方法无法处理,则将异常冒泡 。这是上面的推论,但适用于必须捕获异常的方法。如果捕获的异常无法通过该方法正确处理,则最好对其进行冒泡。
- 立即抛出异常 。这听起来可能含糊不清,但是如果遇到异常情况,那么最好抛出一个异常以指示原始故障点,而不是尝试通过错误代码来处理故障,直到认为适合抛出异常的点为止。换句话说,尝试最小化混合错误处理和错误处理。
- 记录异常或冒泡,但不要同时执行 。记录异常通常表明异常堆栈已完全解开,这表明没有发生任何进一步的异常冒泡。因此,不建议同时执行这两项操作,因为这通常会导致令人沮丧的调试体验。
- 当您除调用方之外的其他人来处理exception时, 请使用java.lang.Exception(检查的异常)的子类。如果调用者不处理异常,这将导致编译器抛出错误消息。请注意,这通常会导致开发人员“吞噬”代码中的异常。
- 使用 java.lang.RuntimeException的子类(未经检查的异常)来指示编程错误。这里推荐的异常类包括IllegalStateException,IllegalArgumentException,UnsupportedOperationException等。同样,必须谨慎使用NullPointerException之类的异常类(几乎总是抛出该异常的做法)。
- 使用异常类层次结构在各个层之间传递有关异常的信息 。通过实现层次结构,您可以概括调用者中的异常处理行为。例如,您可以使用像DomainException这样的根异常,该异常具有多个子类,例如InvalidCustomerException,InvalidProductException等。这里的警告是,如果将每个单独的例外情况表示为单独的异常,则异常层次结构可能会迅速爆炸。
- 避免捕获无法处理的异常 。很明显,但是很多开发人员试图捕获java.lang.Exception或java.lang.Throwable。由于可以捕获所有子类化的异常,因此,当捕获“全局”异常类时,应用程序的运行时行为通常很模糊。毕竟,人们不想捕获OutOfMemoryError-应该如何处理这样的异常?
- 小心包装例外 。重新抛出异常会重置异常堆栈。除非原始原因已提供给新的异常对象,否则它将永远丢失。为了保留异常堆栈,必须将原始异常对象提供给新异常的构造函数。
- 仅在需要时才将已检查的异常转换为未检查的异常 。当包装一个异常时,可以包装一个检查的异常并抛出一个未检查的异常。在某些情况下,这很有用,尤其是在打算中止当前正在执行的线程时。但是,在其他情况下,这可能会造成一些麻烦,因为不执行编译器检查。因此,将已检查的异常调整为未检查的异常并不意味着会盲目地进行。



