错误处理

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
 
 
原文地址:https://www.cnblogs.com/gaoss/p/6628203.html