1. 常见异常
异常都是从Throwable类派生出来的,而Throwable类是直接从Object类继承而来。
通常的异常有四类:
1. Error : 系统内部错误,这类错误由系统进行处理,程序本身无需捕获处理。
2. Exception:可以处理的异常
3. RuntimeException:可以捕获,也可以不捕获的异常
4. 继承Exception的其他类:必须捕获,通常在API文档会说明这些方法抛出哪些异常。
2. 算术异常
J2SE官方API文档 - ArithmeticException
Java SE官方文档对于算术异常的定义是:
当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
public class AriExceptionTest { public static void main(String[] args) { System.out.println("Example 1: -1.0 / 0 = " + (-1.0 / 0)); // 演示负浮点数除0 System.out.println("Example 2: +1.0 / 0 = " + (+1.0 / 0)); // 演示正浮点数除0 System.out.println("Example 3: -1 / 0 = " + (-1 / 0)); // 演示负整数除0 System.out.println("Example 4: +1 / 0 = " + (+1 / 0)); // 演示正整数除0 } }
Example 1: -1.0 / 0 = -Infinity Example 2: +1.0 / 0 = Infinity Exception in thread "main" java.lang.ArithmeticException: / by zero at 算术异常.AriExceptionTest.main(AriExceptionTest.java:11)
Example 1: -1.0 / 0 = -Infinity Example 2: +1.0 / 0 = Infinity Exception in thread "main" java.lang.ArithmeticException: / by zero at 算术异常.AriExceptionTest.main(AriExceptionTest.java:11)
看到,实际上程序在运行到Example 3的时候就已经出现了算数异常。当代码抛出一个异常的同时,也终止了对剩余代码的处理,所以Example 4根本没有机会执行。
那么Example 1和2中为什么能出现结果呢?
这是由于在Java中,浮点数(无论是float还是double类型的浮点数)被0除,并不会引发算术异常。具体说来,是操作系统为了保护应用软件而已经处理了该异常,不再抛出,最终运算结果是无穷大。
3. 数组下标越界异常
J2SE官方API文档 - ArrayIndexOutOfBoundsException
Java SE官方文档对于数组下标越界异常的定义是:
用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。
import java.util.Arrays; public class ArrayExceptionTest { public static void main(String[] args) { int[] array = new int[5]; // 声明一个长度为5的整型数组array Arrays.fill(array, 8); // 将该数组所有元素赋值为8 for (int i = 0; i < 6; i++) { // 用遍历的方式,输出所有数组元素,注意此处的控制条件 i < 6 System.out.println("array[" + i + "] = " + array[i]); //下标将会增加到5,显然是超出了数组array的范围(0到4),程序将在第6次循环前抛出异常 } } }
array[0] = 8 array[1] = 8 array[2] = 8 array[3] = 8 array[4] = 8 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5 at 算术异常.ArrayExceptionTest.main(ArrayExceptionTest.java:17)
array[0] = 8 array[1] = 8 array[2] = 8 array[3] = 8 array[4] = 8 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5 at 算术异常.ArrayExceptionTest.main(ArrayExceptionTest.java:17)
4. 空指针异常
J2SE官方API文档 - NullPointerException
Java SE官方文档对于空指针异常的定义是:
当应用程序试图在需要对象的地方使用 null 时,抛出该异常。这种情况包括:
1. 调用 null 对象的实例方法。
2. 访问或修改 null 对象的字段
3. 将 null 作为一个数组,获得其长度。
4. 将 null 作为一个数组,访问或修改其时间片。
5. 将 null 作为 Throwable 值抛出。
应用程序应该抛出该类的实例,指示其他对 null 对象的非法使用。
public class NullPointerExceptionTest { public static void main(String[] args) { String s= null; // 将字符串设置为null System.out.println(s.toUpperCase()); // 尝试将字符串转换成大写,看看会发生什么 } }
Exception in thread "main" java.lang.NullPointerException at 算术异常.NullPointerExceptionTest.main(NullPointerExceptionTest.java:9)
5. 自定义异常类
尽管Java SE的API已经为我们提供了数十种异常类,然而在实际的开发过程中,你仍然可能遇到未知的异常情况。此时,你就需要对异常类进行自定义。
自定义一个异常类非常简单,只需要让它继承Exception或其子类就行。在自定义异常类的时候,建议同时提供无参构造方法和带字符串参数的构造方法,后者可以为你在调试时提供更加详细的信息。
百闻不如一见,下面我们尝试自定义一个算术异常类。
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,就输出此结果 } } }
array[4] / 4 = 1 array[3] / 3 = 1 array[2] / 2 = 2 array[1] / 1 = 5 Exception in thread "main" 算术异常.MyAriException: There is an exception occured. at 算术异常.ExceptionTest.main(ExceptionTest.java:19)
5. 捕获异常
当我们在编程时遇到了异常不要紧,除了可以将异常抛出,还可以将异常捕获。通常使用try和catch语句块来捕获异常,有时候还会用到finally。
对于上述三个关键词所构成的语句块,try语句块是必不可少的,catch和finally语句块可以根据情况选择其一或者全选。你可以把可能发生错误或出现问题的语句放到try语句块中,将异常发生后要执行的语句放到catch语句块中,而finally语句块句,不管异常是否发生,它们都会被执行。
你可能想说,那我把所有有关的代码都放到try语句块中不就妥当了吗?可是你需,捕获异常对于系统而言,其开销非常大,所以应尽量减少该语句块中放置的语句。
public class CatchException { public static void main(String[] args) { try { System.out.println("I am try block."); //声明一个空的Class对象用于引发“类未发现异常” Class<?> tempClass = Class.forName(""); 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(Class.java:264) at 算术异常.CatchException.main(CatchException.java:10) Goodbye! Catch block. I am finally block