在Java中处理惩罚异常并不是一个简朴的工作。不只仅初学者很难领略,纵然一些有履历的开拓者也需要耗费许多时间来思考如那里理惩罚异常,包罗需要处理惩罚哪些异常,奈何处理惩罚等等。这也是绝大大都开拓团队城市拟定一些法则来类型对异常的处理惩罚的原因。而团队之间的这些类型往往是截然差异的。
本文给出几个被许多团队利用的异常处理惩罚最佳实践。
1. 在Finally块中清理资源可能利用try-with-resource语句
当利用雷同InputStream这种需要利用后封锁的资源时,一个常见的错误就是在try块的最后封锁资源。
public void doNotCloseResourceInTry() { FileInputStream inputStream = null; try { File file = new File("./tmp.txt"); inputStream = new FileInputStream(file); // use the inputStream to read a file // do NOT do this inputStream.close(); } catch (FileNotFoundException e) { log.error(e); } catch (IOException e) { log.error(e); } }
上述代码在没有任何exception的时候运行是没有问题的。可是当try块中的语句抛出异常可能本身实现的代码抛出异常,那么就不会执行最后的封锁语句,从而资源也无法释放。
公道的做法例是将所有清理的代码都放到finally块中可能利用try-with-resource语句。
public void closeResourceInFinally() { FileInputStream inputStream = null; try { File file = new File("./tmp.txt"); inputStream = new FileInputStream(file); // use the inputStream to read a file } catch (FileNotFoundException e) { log.error(e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { log.error(e); } } } } public void automaticallyCloseResource() { File file = new File("./tmp.txt"); try (FileInputStream inputStream = new FileInputStream(file);) { // use the inputStream to read a file } catch (FileNotFoundException e) { log.error(e); } catch (IOException e) { log.error(e); } }
2. 指定详细的异常
尽大概的利用最详细的异常来声明要领,这样才气使得代码更容易领略。
public void doNotDoThis() throws Exception { ... } public void doThis() throws NumberFormatException { ... }
如上,NumberFormatException字面上即可以看出是数字名目化错误。
3. 对异常举办文档说明
当在要领上声明抛出异常时,也需要举办文档说明。和前面的一点一样,都是为了给挪用者提供尽大概多的信息,从而可以更好地制止/处理惩罚异常。
在Javadoc中插手throws声明,而且描写抛出异常的场景。
/** * This method does something extremely useful ... * * @param input * @throws MyBusinessException if ... happens */ public void doSomething(String input) throws MyBusinessException { ... }
4. 抛出异常的时候包括描写信息
在抛出异常时,需要尽大概准确地描写问题和相关信息,这样无论是打印到日志中照旧监控东西中,都可以或许更容易被人阅读,从而可以更好地定位详细错误信息、错误的严重水平等。
但这里并不是说要对错误信息长篇大论,因为原来Exception的类名就可以或许反应错误的原因,软件开发,因此只需要用一到两句话描写即可。
try { new Long("xyz"); } catch (NumberFormatException e) { log.error(e); }
NumberFormatException即汇报了这个异常是名目化错误,软件开发,异常的特别信息只需要提供这个错误字符串即可。当异常的名称不足明明的时候,则需要提供尽大概详细的错误信息。
5. 首先捕捉最详细的异常
此刻许多IDE都能智能提示这个最佳实践,当你试图首先捕捉最笼统的异常时,会提示不能到达的代码。
当有多个catch块中,凭据捕捉顺序只有第一个匹配到的catch块才气执行。因此,假如先捕捉IllegalArgumentException,那么则无法运行到对NumberFormatException的捕捉。
public void catchMostSpecificExceptionFirst() { try { doSomething("A message"); } catch (NumberFormatException e) { log.error(e); } catch (IllegalArgumentException e) { log.error(e) } }
6. 不要捕捉Throwable
Throwable是所有异常和错误的父类。你可以在catch语句中捕捉,可是永远不要这么做。
假如catch了throwable,那么不只仅会捕捉所有exception,还会捕捉error。而error是表白无律例复的jvm错误。因此除非绝对必定可以或许处理惩罚可能被要求处理惩罚error,不要捕捉throwable。
public void doNotCatchThrowable() { try { // do something } catch (Throwable t) { // don't do this! } }
7. 不要忽略异常