首页 > java > basic > 16.Java异常

16.Java异常

Java异常是Java提供的一种识别及响应错误的一致性机制.

1 异常机制相关关键字

1.1 异常相关关键字

异常机制相关关键字有: try、catch、finally、throw、throws.关键字解释:

  • try: 用于监听.将被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出.
  • catch: 用来捕获try语句块中发生的异常.
  • finally: finally语句块总是会被执行.主要用于回收在try块里打开的物理资源(如文件,网络连接,数据库连接等).
  • throw 用于抛出异常.
  • throws 用在方法签名中,用于声明该方法可能抛出的异常.

finally语句中加入return语句与和处理? 只有finally块执行完成之后,才会执行try或者catch块中的return或者throw语句.如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止.

2 异常框架

将可抛出(Throwable)的结构分为三种类型:

  • 编译异常(Checked Exception)
  • 运行时异常(RuntimeException)
  • 错误(Error)

异常框架继承关系如图: 图15-1

2.1 Throwable

Throwable是Java语言中所有错误或异常的父类,包含两个子类:Error和Exception.它们通常用于指示发生了异常情况.Throwable包含了其线程创建时线程执行堆栈的快照,提供了printStackTrace()等接口用于获取堆栈跟踪数据等信息.

2.2 RuntimeException

运行时异常RuntimeException是那些可能在Java虚拟机正常运行期间抛出的异常的父类,简称运行时异常.RuntimeException及其子类都被称为运行时异常.Java编译器不会检查运行时异常.当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过.虽然Java编译器不会检查运行时异常,但是我们也可以通过throws进行声明抛出,也可以通过try-catch对它进行捕获处理.如果产生运行时异常,则需要通过修改代码来进行避免.

常见的运行时异常RuntimeException举例:

  • 除数为零时产生的ArithmeticException异常
  • 数组越界时产生的IndexOutOfBoundsException异常
  • fail-fail机制产生的ConcurrentModificationException异常等,都属于运行时异常.

常见运行时异常:

java常见运行时异常
异常 描述
ArithmeticException 除数为零异常
ArrayIndexOutOfBoundsException 数组越界
ClassCastException 对象转型错误
IllegalArgumentException 参数不合法
IndexOutOfBoundsException 指示某排序索引(例如对数组、字符串或向量的排序)超出范围
NegativeArraySizeException 数组长度为负值
NullPointerException 空指针异常
NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常.

2.3 编译异常Exception

Exception类以及Exception的子类中除了"运行时异常"之外的其它子类都属于被检查异常.此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译.

常见编译异常:

java常见编译异常
异常 描述
ClassNotFoundException 应用程序试图加载类时,找不到相应的类,抛出该异常.
FileNotFoundException 文件不存在异常
ClassCastException 对象转型错误
InterruptedException 一个线程被另一个线程中断,抛出该异常.
NoSuchFieldException 请求的变量不存在
NoSuchMethodException 请求的方法不存在

2.4 Error

java Error类及其子类统称错误.用于指示试图捕获的严重问题,大多数这样的错误都是异常条件.和运行时异常一样,编译器也不会检查Error.当资源不足、约束失败、或是其它导致程序无法继续运行的条件发生时,就产生错误.程序本身无法修复这些错误.例:VirtualMachineError就属于错误.

按照Java惯例,不应该实现任何新的Error子类,需要自定义异常可以采用Exception类.

2.5 该用哪一种异常

对于可以恢复的条件使用被检查异常,对于程序错误使用运行时异常.虚拟机及系统错误采用Error.

3 捕获异常

使用try和catch关键字可以捕获异常.try/catch代码块放在异常可能发生的地方.java try/catch语法:

try {
    /** 程序代码*/
} catch (Exception e) {
    /** 异常处理*/
}

一个try代码块后面跟随多个catch代码块的情况就叫多重捕获.可以在try语句后面添加任意数量的catch块.如果保护代码中发生异常,异常被抛给第一个catch块.如果抛出异常的数据类型与捕获异常类型匹配,就会被捕获.如果不匹配,它会被传递给下一个catch块.直到异常被捕获或者通过所有的catch块.

多个catch情况语法如下:

try {
    /** 程序代码*/
} catch (Exception1 e) {
    /** 异常处理*/
} catch (Exception1 e) {
    /** 异常处理*/
}

4 抛出异常

可以使用throw关键字抛出一个异常.如果一个方法没有捕获一个编译异常,那么该方法必须使用throws关键字来声明.throws关键字放在方法签名的尾部.

public static void testThrow() {
    /** 方法体*/
    throw new NullPointerException();
}

java抛出异常示例:

public static void testThrows() throws NullPointerException {
    /** 方法体*/
}

一个java方法可以声明抛出多个异常,多个异常之间用逗号隔开.例如,下面的方法声明抛出NullPointerExceptionArithmeticException示例代码:

public static void testThrows() throws NullPointerException,ArithmeticException {
    /** 方法体*/
}

5 finally关键字

java finally是java保留关键字中的一个,用来创建在try代码块后面执行的代码块.无论是否发生异常,finally代码块中的代码总会被执行.在finally代码块中,可以运关闭链接,释放系统资源等必须要执行的语句.finally代码块出现在catch代码块最后.语法如下:

try {
    /** 方法体*/
} catch (Exception e) {
    /** 异常处理*/
} finally {
    /** finally语句*/
}

finally 块并非强制添加.try 代码后不能既没catch块也没finally块.示例代码:

package com.dashidan.lesson16;

/**
 * 大屎蛋教程网-dashidan.com
 * <p>
 * Java教程基础篇: 16.Java异常
 * 测试finally return
 */
public class Demo2 {
    public static void main(String[] args) {
        int result = testFinallyReturn();
        System.out.println("result: " + result);
    }

    public static int testFinallyReturn() {
        int a;
        try {
            a = 1;
            /** 抛出异常*/
            System.out.println("抛出异常");
            throw new NullPointerException();
        } catch (NullPointerException e) {
            a = 2;
            /** 捕获异常*/
            System.out.println("捕获异常");
            e.printStackTrace();
            /** 注意这里没有返回*/
            System.out.println("注意这里没有返回");
            return a;
        } finally {
            a = 3;
            System.out.println("finally执行返回");
            /** 抛出异常后,执行finally的语句,如果这里返回,不再执行catch中语句*/
            return a;
        }
    }
}

输出:

抛出异常
捕获异常
注意这里没有返回
finally执行返回
result: 3
java.lang.NullPointerException
    at com.dashidan.lesson16.Demo2.testFinallyReturn(Demo2.java:21)
    at com.dashidan.lesson16.Demo2.main(Demo2.java:11)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

6 自定义异常

在Java中自定义异常需要注意:

  • 所有异常都必须是 Throwable 的子类.
  • 如果想写一个检查性异常类,则需要继承 Exception 类.
  • 如果想写一个运行时异常类,那么需要继承 RuntimeException 类.
package com.dashidan.lesson16;

/**
 * 大屎蛋教程网-dashidan.com
 * <p>
 * Java教程基础篇: 16.Java异常
 * 自定义异常
 */
public class SelfException extends Exception {
}

示例代码:

package com.dashidan.lesson16;

/**
 * 大屎蛋教程网-dashidan.com
 * <p>
 * Java教程基础篇: 16.Java异常
 */
public class Demo1 {
    public static void main(String[] args) {
        try {
            /** 方法体*/
            testThrow();
            testThrows();
        } catch (NullPointerException e) {
            /** 异常处理*/
            System.out.println("run catch NullPointerException.");
            e.printStackTrace();
        } catch (Exception e) {
            /** 异常处理*/
            System.out.println("run catch Exception.");
            e.printStackTrace();
        } finally {
            /** finally语句*/
            System.out.println("run finally.");
        }
    }

    public static void testThrow() {
        /** 方法体*/
        throw new NullPointerException();
    }

    public static void testThrows() throws NullPointerException,ArithmeticException {
        /** 方法体*/
    }
}

输出:

java.lang.NullPointerException
at com.dashidan.lesson16.Demo1.testThrow(Demo1.java:30)
at com.dashidan.lesson16.Demo1.main(Demo1.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
run catch NullPointerException.
run finally.
转载请保留原文链接.