注:图片出自《Core Java SE 9 for the Impatient》
图5-1显示了java中的异常继承层次。当发生了某种异常,而这种异常不是期望应用程序处理的,比如内存耗尽,则会抛出Error之类的异常。
程序员报告的异常属于Exception类的子类。它们分为两种:
已检查异常常用于错误可被提前预知的情况,比如:常见的错误原因是输入和输出、指定路径的文件未找到等。
未检查异常表明程序员造成的逻辑错误,不是不可避免的外部风险导致的。
列出方法可能会抛出的异常,这些异常要么是方法本身通过throw语句抛出,要么调用另外一个带throws语句的方法来声明异常。
例子:
//声明异常 public static void Write1 (Object obj, String fileName) throws IOException, ReflectiveOperationException { } //方法本身先抛出异常,后捕获 public static void Write2 (Object obj, String fileName) { try { throw new IOException(); } catch (Exception e) { e.printStackTrace(); } }
对于不同的异常类可以有多个异常处理器。
例子:
try { } catch (ExceptionClass1 e) { }catch (ExceptionClass1 e) { }catch (Exception e) { }
资源管理是异常处理中需要关注的问题之一。
例如:你向一个文件写入内容,当写操作完成后,关闭文件。
例子:
List<String> lines = new ArrayList<>(); PrintWriter out = new PrintWriter("TempOutput.txt"); for (String line: lines) { out.println(line.toLowerCase()); } out.close();//释放资源,如果任意一个地方出现异常,则out.close()将不会执行。 //改进版: List<String> lines = new ArrayList<>(); try(PrintWriter out = new PrintWriter("TempOutput.txt")){ for (String line: lines) { out.println(line.toLowerCase()); } }
在使用try语句的这种特定形式的前提是:这些资源必须属于实现了AutoCloseable接口的类。
try{}finally{} 或 try-catch-finally形式的语句
当try到达末尾时,不管是正常完成还是异常导致的,都会执行finally子句。用于清除一些没有AutoCloseable接口的资源等等。
//这是AutoCloseable接口 public interface Closeable extends AutoCloseable { public void close() throws IOException; }
但是你必须要小心finally子句中的异常。
例子:
BufferedReader in = null; try { Path path = null; in = Files.newBufferedReader(path, StandardCharsets.UTF/_8); }catch (Exception ex){ System.out.println(ex.getMessage()); } finally { if(in != null){ in.close(); //可能抛出异常 } } //改进版: BufferedReader in = null; try { Path path = null; in = Files.newBufferedReader(path, StandardCharsets.UTF/_8); }catch (Exception ex){ System.out.println(ex.getMessage()); } finally { try { if(in != null){ in.close(); } }catch (Exception ex) { System.out.println(ex.getMessage()); } } //或者改为 Path path = null; try(BufferedReader in = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { }catch (Exception ex){ System.out.println(ex.getMessage()); }
使用Objects.requireNonNull便于检测参数是否为空,如果参数为空,马上抛出NullPointerException异常,你马上就能知道哪里出错了。该方法更多的变体请自行查阅api。
public static void Process(String data) { Objects.requireNonNull(data,"data不能为空"); }