其他
处理 Exception 的几种实践,很优雅,已被很多团队采纳!
大家好,我是D哥
点击关注下方公众号,Java面试资料 都在这里
来源:http://ww7.rowkey.me/
# 在Finally块中清理资源或者使用try-with-resource语句
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块中的语句抛出异常或者自己实现的代码抛出异常,那么就不会执行最后的关闭语句,从而资源也无法释放。
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);
}
}
# 指定具体的异常
public void doNotDoThis() throws Exception {
...
}
public void doThis() throws NumberFormatException {
...
}
# 对异常进行文档说明
/**
* This method does something extremely useful ...
*
* @param input
* @throws MyBusinessException if ... happens
*/
public void doSomething(String input) throws MyBusinessException {
...
}
# 抛出异常的时候包含描述信息
在抛出异常时,需要尽可能精确地描述问题和相关信息,这样无论是打印到日志中还是监控工具中,都能够更容易被人阅读,从而可以更好地定位具体错误信息、错误的严重程度等。
但这里并不是说要对错误信息长篇大论,因为本来Exception的类名就能够反映错误的原因,因此只需要用一到两句话描述即可。
try {
new Long("xyz");
} catch (NumberFormatException e) {
log.error(e);
}
NumberFormatException即告诉了这个异常是格式化错误,异常的额外信息只需要提供这个错误字符串即可。当异常的名称不够明显的时候,则需要提供尽可能具体的错误信息。
# 首先捕获最具体的异常
public void catchMostSpecificExceptionFirst() {
try {
doSomething("A message");
} catch (NumberFormatException e) {
log.error(e);
} catch (IllegalArgumentException e) {
log.error(e)
}
}
# 不要捕获Throwable
public void doNotCatchThrowable() {
try {
// do something
} catch (Throwable t) {
// don't do this!
}
}
# 不要忽略异常
public void doNotIgnoreExceptions() {
try {
// do something
} catch (NumberFormatException e) {
// this will never happen
}
}
public void logAnException() {
try {
// do something
} catch (NumberFormatException e) {
log.error("This should never happen: " + e);
}
}
# 不要记录并抛出异常
try {
new Long("xyz");
} catch (NumberFormatException e) {
log.error(e);
throw e;
}
17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"
Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.(Long.java:965)
at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)
如上所示,后面的日志也没有附加更有用的信息。
如果想要提供更加有用的信息,那么可以将异常包装为自定义异常。
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e);
}
}
# 包装异常时不要抛弃原始的异常
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e);
}
}