转载请保留原文链接: http://dashidan.com/article/java/basic/16.html
Java异常是Java提供的一种识别及响应错误的一致性机制.
① Java异常机制相关关键字
Java异常机制相关关键字有: try
、catch
、finally
、throw
、throws
.
关键字解释:
- try 用于监听. 将被监听的代码(可能抛出异常的代码)放在try语句块之内, 当try语句块内发生异常时,异常就被抛出.
- catch 用来捕获try语句块中发生的异常.
- finally finally语句块总是会被执行. 主要用于回收在
try
块里打开的物理资源(如文件, 网络连接, 数据库连接等).
finally语句中return
只有finally块执行完成之后,才会执行try或者catch块中的return或者throw语句. 如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止.
- throw 用于抛出异常.
- throws 用在方法签名中,用于声明该方法可能抛出的异常.
② Java异常框架
Java将可抛出(Throwable)的结构分为三种类型:
- 编译异常(Checked Exception)
- 运行时异常(RuntimeException)
- 错误(Error)
Java异常框架继承关系如图:
1.Throwable
Throwable
是Java
语言中所有错误或异常的超类, 包含两个子类:Error
和Exception
.它们通常用于指示发生了异常情况.Throwable
包含了其线程创建时线程执行堆栈的快照,提供了printStackTrace()
等接口用于获取堆栈跟踪数据等信息.
2.运行时异常RuntimeException
RuntimeException
是那些可能在Java
虚拟机正常运行期间抛出的异常的超类, 简称运行时异常
. RuntimeException及其子类都被称为运行时异常.
Java编译器不会检查运行时异常.当程序中可能出现这类异常时,倘若既”没有通过throws声明抛出它”,也”没有用try-catch语句捕获它”,还是会编译通过.
虽然Java编译器不会检查运行时异常, 但是我们也可以通过throws进行声明抛出, 也可以通过try-catch对它进行捕获处理. 如果产生运行时异常,则需要通过修改代码来进行避免.
例如:
* 除数为零时产生的ArithmeticException异常
* 数组越界时产生的IndexOutOfBoundsException异常
* fail-fail机制产生的ConcurrentModificationException异常等,都属于运行时异常.
异常 | 描述 |
ArithmeticException | 除数为零异常 |
ArrayIndexOutOfBoundsException | 数组越界 |
ClassCastException | 对象转型错误 |
IllegalArgumentException | 参数不合法 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围 |
NegativeArraySizeException | 数组长度为负值 |
NullPointerException | 空指针异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常. |
3.编译异常Exception
Exception
类以及Exception
的子类中除了”运行时异常”之外的其它子类都属于被检查异常. 此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译.
异常 | 描述 |
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常. |
FileNotFoundException | 文件不存在异常 |
ClassCastException | 对象转型错误 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常. |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
4.Error
Error
类及其子类统称错误
. 用于指示试图捕获的严重问题, 大多数这样的错误都是异常条件. 和运行时异常
一样, 编译器也不会检查Error
. 当资源不足、约束失败、或是其它导致程序无法继续运行的条件发生时, 就产生错误. 程序本身无法修复这些错误.
例:
- VirtualMachineError就属于错误.
-
按照Java惯例, 不应该实现任何新的Error子类, 需要自定义异常可以采用Exception类.
到底该哪一种异常?
对于可以恢复的条件使用被检查异常,对于程序错误使用运行时异常.虚拟机及系统错误采用Error.
③ 捕获异常
使用try
和catch
关键字可以捕获异常.try/catch
代码块放在异常可能发生的地方.
语法如下:
try {
/** 程序代码*/
} catch (Exception e) {
/** 异常处理*/
}
一个`try`代码块后面跟随多个`catch`代码块的情况就叫多重捕获. 可以在 try 语句后面添加任意数量的 catch 块. 如果保护代码中发生异常,异常被抛给第一个 catch 块. 如果抛出异常的数据类型与捕获异常类型匹配, 就会被捕获. 如果不匹配,它会被传递给下一个`catch`块.直到异常被捕获或者通过所有的`catch`块. 语法如下:
try {
/** 程序代码*/
} catch (Exception1 e) {
/** 异常处理*/
} catch (Exception1 e) {
/** 异常处理*/
}
④ 抛出异常
可以使用throw
关键字抛出一个异常.
public static void testThrow() {
/** 方法体*/
throw new NullPointerException();
}
如果一个方法没有捕获一个`编译异常`, 那么该方法必须使用`throws`关键字来声明. `throws`关键字放在方法签名的尾部. 示例代码:
public static void testThrows() throws NullPointerException {
/** 方法体*/
}
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开. 例如,下面的方法声明抛出`NullPointerException`和`ArithmeticException` 示例代码:
public static void testThrows() throws NullPointerException, ArithmeticException {
/** 方法体*/
}
⑤ finally关键字
finally
关键字用来创建在try
代码块后面执行的代码块. 无论是否发生异常,finally
代码块中的代码总会被执行. 在finally
代码块中,可以运关闭链接, 释放系统资源等必须要执行的语句.
finally
代码块出现在catch
代码块最后.
语法如下:
try {
/** 方法体*/
} catch (Exception e) {
/** 异常处理*/
} finally {
/** finally语句*/
}
finally 块并非强制添加.
try 代码后不能既没 catch 块也没 finally 块.
示例代码:
package com.dashidan.lesson15;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 15.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.lesson15.Demo2.testFinallyReturn(Demo2.java:21)
at com.dashidan.lesson15.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)
⑥ 自定义异常
在Java
中自定义异常需要注意:
- 所有异常都必须是 Throwable 的子类.
- 如果想写一个检查性异常类,则需要继承 Exception 类.
- 如果想写一个运行时异常类,那么需要继承 RuntimeException 类.
package com.dashidan.lesson15;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 15.Java异常
* 自定义异常
*/
public class SelfException extends Exception {
}
示例代码:
package com.dashidan.lesson15;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 15.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.lesson15.Demo1.testThrow(Demo1.java:30)
at com.dashidan.lesson15.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.