10个关于Java异常的常见问题
这篇文章总结了十个经常被问到的JAVA异常问题;
1.检查型异常VS非检查型异常
简单的说,检查型异常是指需要在方法中自己捕获异常处理或者声明抛出异常由调用者去捕获处理;
非检查型异常指那些不能解决的异常,如除0,空指针等;
检查型异常非常重要,因为你希望使用你API接口的人知道如何处理这些异常;
举个例子,IOException是非常常见的检查型异常,RuntimeException是非检查型异常;
Java的异常层级关系图如下:
2.异常管理最佳实践
如果一个异常当前能够被恰当的处理,那么应该捕获处理它,否则应该显示的抛出异常;
3.为什么在try代码块里定义的变量,在catch或finally代码块里不能被访问
如下代码,在try代码块中声明字符串s变量,但是不能在catch代码块中使用,代码不能编译通过;
try { File file = new File("path"); FileInputStream fis = new FileInputStream(file); String s = "inside"; } catch (FileNotFoundException e) { e.printStackTrace(); System.out.println(s); }
原因是因为你不知道在try代码块中的哪一句会抛出异常,很有可能这个异常在变量声明之前就抛出了;
这正是以上这个例子的情况;
注:强烈怀疑是因为作用域的关系导致s变量不可见;
4.为什么Integer.parseInt(null)和Double.parseDouble(null)会抛出不同的异常
这是JDK的问题,因为这两个方法是不同的开发人员写的,所以没必要深究;
Integer.parseInt(null); // throws java.lang.NumberFormatException: null Double.parseDouble(null); // throws java.lang.NullPointerException
注:其实我目前的JDK7已经没有该问题了,两个都是抛出NumberFormatException
5.多用运行时异常
几个常见的运行时异常,如IllegalArgumentException、ArrayIndexOutOfBoundsException;
当判断条件不满足时,可以抛出这些异常,如下代码:
if (obj == null) { throw new IllegalArgumentException("obj can not be null");
6.是否可以在一个catch代码块里捕获多个异常
答案是可以的。因为JAVA的异常可以追溯到同一个父类Exception,我们可以使用父类捕获多个异常;
try { } catch (Exception e) { // TODO: handle exception }
补充:
在JAVA7中,增加了新语法,可以这样捕获多个异常:
try { ... } catch( IOException | SQLException ex ) { ... }
在JAVA7之前可以这样写:
try { //..... } catch (Exception exc) { if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException ) { someCode(); } else if (exc instanceof RuntimeException) { throw (RuntimeException) exc; } else { throw new RuntimeException(exc); } }
7.构造方法是否可以抛出异常
答案是可以的,构造方法是一个特殊的方法,同样可以抛出异常;
注意,如果构造方法抛出异常,对象是没有生成的;
8.finally语句块同样可以抛出和捕获异常
以下代码是合法的:
public static void main(String[] args) { File file1 = new File("path1"); File file2 = new File("path2"); try { FileInputStream fis = new FileInputStream(file1); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { FileInputStream fis = new FileInputStream(file2); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
但是出于可读性考虑,最好把finally里的异常处理代码封装到一个方法里,然后调用该方法,如下代码:
public static void main(String[] args) { File file1 = new File("path1"); File file2 = new File("path2"); try { FileInputStream fis = new FileInputStream(file1); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { methodThrowException(); } }
9.finally代码块里是否可以写return语句
是的,可以
10.为什么JAVA程序员经常悄悄地忽略异常的处理
以下代码片段会经常出现在程序中,如果异常处理那么重要,为什么还会有这么多开发人员一直这样做呢?
try { ... } catch (Exception e) { e.printStackTrace(); }
经常出现的代码并不代表是对的;
可能很多开发人员都使用eclipse的快速修复,自动生成异常处理代码,如上所示,其实除了记录下log,并没有做什么处理;
正如条目2所描述的,如果不能正确处理该异常的话,最好抛出异常,以便异常尽早被发现;
译文链接:http://www.programcreek.com/2013/10/top-10-questions-about-java-exceptions/