异常概述
对于程序的错误以及外部环境能够对用户造成的影响,我们应当及时报告并且以适当的方式来处理这个错误。
异常都是从Throwab类派生出来的,而Throwable类是直接从Object类继承而来。
异常通常有四类:
- Error:系统内部错误,这类错误由系统进行处理,程序本身无需捕获处理
- Exception:可以处理的异常
- RuntimeException:可以捕获,也可以不捕获的异常
- 继承 Exception 的其他类:必须捕获。
-
抛出异常
异常抛出语法:
throw new 异常名();
-
throws 声明异常
Throws 用于声明异常,表示该方法可能会抛出的异常。如果声明的异常中包括 checked 异常(受查异常),那么调用者必须处理该异常或者使用 throws 继续向上抛出。throws 位于方法体前,多个异常使用,分割。
import java.io.FileInputStream; import java.io.FileNotFoundException; public class ThrowsTest { public static void main(String[] args) throws FileNotFoundException { //由方法的调用者捕获异常或者继续向上抛出 throwsTest(); } public static void throwsTest() throws FileNotFoundException { new FileInputStream("/home/project/shiyanlou.file"); } }
捕获异常
通常抛出异常后,还需要将异常捕获。使用try和catch语句块来捕获异常,有时候还会用到finally。 对于上述三个关键词所构成的语句块,try语句块是必不可少的,catch和finally语句块可以根据情况选择其一或者全选。你可以把可能发生错误或出现问题的语句放到try语句块中,将异常发生后要执行的语句放到catch语句块中,而finally语句块里面放置的语句,不管异常是否发生,它们都会被执行。
public class CatchException { public static void main(String[] args) { try { // 下面定义了一个try语句块 System.out.println("I am try block."); Class<?> tempClass = Class.forName(""); // 声明一个空的Class对象用于引发“类未发现异常” System.out.println("Bye! Try block."); } catch (ClassNotFoundException e) { // 下面定义了一个catch语句块 System.out.println("I am catch block."); e.printStackTrace(); //printStackTrace()的意义在于在命令行打印异常信息在程序中出错的位置及原因 System.out.println("Goodbye! Catch block."); } finally { // 下面定义了一个finally语句块 System.out.println("I am finally block."); } } } 结果: I am try block. I am catch block. java.lang.ClassNotFoundException: at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Unknown Source) at CatchException.main(CatchException.java:8) Goodbye! Catch block. I am finally block.
多个异常情况
在一段代码中,可能会由于各种原因抛出多种不同的异常,而对于不同的异常,我们希望用不同的方式来处理它们,而不是笼统的使用同一个方式处理,在这种情况下,可以使用异常匹配,当匹配到对应的异常后,后面的异常将不再进行匹配
在处理异常时,并不要求抛出的异常同 catch 所声明的异常完全匹配,子类的对象也可以匹配父类的处理程序。比如异常 A 继承于异常 B,那么在处理多个异常时,一定要将异常 A 放在异常 B 之前捕获,如果将异常 B 放在异常 A 之前,那么将永远匹配到异常 B,异常 A 将永远不可能执行,并且编译器将会报错。
自定义异常
自定义一个异常类非常简单,只需要让它继承 Exception 或其子类就行。在自定义异常类的时候,建议同时提供无参构造方法和带字符串参数的构造方法,后者可以为你在调试时提供更加详细的信息。
// MyAriException.java public class MyAriException extends ArithmeticException { //自定义异常类,该类继承自ArithmeticException public MyAriException() { } //实现默认的无参构造方法 public MyAriException(String msg) { super(msg); } //实现可以自定义输出信息的构造方法,将待输出信息作为参数传入即可 } // ExceptionTest.java import java.util.Arrays; public class ExceptionTest { public static void main(String[] args) { int[] array = new int[5]; //声明一个长度为5的数组 Arrays.fill(array, 5); //将数组中的所有元素赋值为5 for (int i = 4; i > -1; i--) { //使用for循环逆序遍历整个数组,i每次递减 if (i == 0) { // 如果i除以了0,就使用带异常信息的构造方法抛出异常 throw new MyAriException("There is an exception occured."); } System.out.println("array[" + i + "] / " + i + " = " + array[i] / i); // 如果i没有除以0,就输出此结果 } } }
异常堆栈
public class ThrowTest { public static void main(String[] args) { Integer a = 1; Integer b = null; //当a或者b为null时,抛出异常 if (a == null || b == null) { throw new NullPointerException(); } else { System.out.println(a + b); } } } 运行结果: Exception in thread "main" java.lang.NullPointerException at ThrowTest.main(ThrowTest.java:8)