1. 已检查异常 VS 未检查异常
简单来说,已检查异常必须被捕获或者声明抛出。未检查异常通常是由一些无法恢复的错误导致的,比如除0, 空引用等。已检查异常的一个非常重要的作用就是,强迫方法调用者去正确的处理可能出现的错误,从而提高程序的健壮性。比如,IOException就是常用的已经检查异常,而RuntimeException是典型的未检查异常。
2. 处理异常的最佳实践
如果一个异常可以被正确地处理,那么我们就应该去捕获它。反之则应当直接抛出,让方法的调用者来决定如何处理。
3. 为什么在try语句块中定义的变量无法在catch和finally中使用?
如下面一段代码,在try中声明了一个String类型的引用s,然后我们在catch中试图读取这个s。这样的代码是无法通过编译的:
try { File file = new File("path"); FileInputStream fis = new FileInputStream(file); String s = "inside"; } catch (FileNotFoundException e) { e.printStackTrace(); System.out.println(s); }
这样设计的原因是,在运行中我们无法确定异常会在try语句块的哪一行代码中被抛出。假如在 File file = new File("path"); 这一行就抛出异常的话,那么try语句块剩下的语句都不会被执行,则s也就不会存在。所以try中的变量不允许在catch 或 finally 中引用。
4. 为什么Double.parseDouble(null)和Integer.parseInt(null)会抛出两个不同的异常?
这两个方法确实会抛不同的异常。这只不过是JDK的设计问题而已,没什么特别的,不用细扣。
Integer.parseInt(null); // throws java.lang.NumberFormatException: null Double.parseDouble(null); // throws java.lang.NullPointerException
5. 常用的RuntimeException
比如
IllegalArgumentException ArrayIndexOutOfBoundsException
经常被这样使用:
if (obj == null) { throw new IllegalArgumentException("obj can not be null");
6. 能在一个catch语句块中捕获多个异常吗?
只要catch的异常是被抛出异常的父类就可以。例如 catch(Exception ex) 就能通吃所有的异常,但不推荐这样。
7. 构造方法能抛异常吗?
可以。比如下面的代码:
class FileReader{ public FileInputStream fis = null; public FileReader() throws IOException{ File dir = new File(".");//get current directory File fin = new File(dir.getCanonicalPath() + File.separator + "not-existing-file.txt"); fis = new FileInputStream(fin); } }
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 语句块中的 try...catch 封装到一个方法中去,然后直接在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. 为什么很多开发者在catch中只写一句printStackTrace()就完事了?
try { ... } catch(Exception e) { e.printStackTrace(); }
很多人都去做的事,并不一定就是正确的。应当尽量避免上面的写法。回顾上面的第二点,如果感觉自己处理不好这个异常,那么应该直接抛出。