目录
1.什么是异常
2.异常的处理
2.1 异常的抛出
(1)什么是异常的抛出
(2)如何抛出异常
2.2 异常的捕获
(1)异常声明throws
(2)try-cathc捕获处理
3. 自定义异常类
如何定义异常类
异常:程序在执行过程中发生的不正常行为
例如:
public class Test {
public static void main(String[] args) {
int a = 1/0;
System.out.println(a);
}
}
Java中有许多不同类型的异常,例如算数异常(ArithmeticException)、空指针异常(NullPointerException)、类型转换异常(ClassCastException)
当出现异常时,我们要设法处理异常,使程序能够继续正常运行
当程序中出现异常时,将错误信息告知调用者。
使用 throw 关键字,抛出一个指定的异常对象,将错误信息告知调用者
使用格式:
throw new 异常类名( 参数 );
例如
public class Test {
public static void main(String[] args) {
int ret = divide(3,0);
System.out.println(ret);
}
public static int divide(int a, int b){
//判断除数是否为0,若为0,抛出异常
if(b == 0){
throw new ArithmeticException("除数为0,无法计算!");
}
return a/b;
}
}
运行结果
注:
1. throw关键字必须在方法内部使用
2. 抛出的对象必须是 Exception 或者 Exception的子类对象
3. 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
5.异常一旦抛出,其后的代码不再执行
对出现的异常进行捕捉,主要有两种 异常声明throws 和 try-catch捕获处理
当方法中抛出编译时异常,用户不想处理异常时,就可以借助throws将异常抛给方法的调用者来处理。即自己不处理异常,将异常上抛(抛给调用者),由调用者对这个异常进行处理,若调用者不处理,继续上抛,最终抛给main方法,main方法再上抛,抛给JVM处理,处理结果则是Java程序终止。
throws处在方法声明时参数列表之后,可抛出多个异常类型
使用格式
修饰符 返回值类型 方法名( 参数列表 ) throws 异常类型1, 异常类型2, ...{
}
例如
public static int getNumber(int[] arr, int i) throws NullPointerException, ArithmeticException{
if(arr == null){
throw new NullPointerException();
}
if(i >= arr.length){
throw new ArrayIndexOutOfBoundsException();
}
return arr[i];
}
将光标放在抛出异常方法上,alt+ 回车,即可快速抛出异常
注:
1.throws必须处在方法的参数列表之后
2. 声明的异常必须是 Exception 或者 Exception 的子类
3.方法内部如果抛出多个异常,throws之后必须跟多个异常类型,异常类型之间用逗号隔开,若抛出的多个异常类型具有父子关系,则直接声明父类即可
throws只是将异常抛给调用者,要真正处理异常,则需使用try-catch处理异常
使用格式
try{
//可能出现异常的代码
} catch(异常类型 e){
//若try中的代码抛出异常,此处catch捕获的异常类型与try中抛出的异常类型一致,或是try中抛出异常的基类,就会捕捉异常
//对异常进行处理,处理完成后,跳出try-catch结果,执行后续代码
} catch(异常类型 e){
//对异常进行处理
}finally{
//一定会被执行的代码
}
//后续代码
//当异常被捕获到(即异常被处理了),后续的代码就会执行
//当异常未被捕获到(异常未被处理),后续的代码不会被执行
注:
1.try块内抛出异常位置之后的代码将不会被执行
2.抛出异常类型与catch异常类型不匹配,即异常未被成功捕获,就不会被处理,继续向外抛,直到JVM收到后中断程序,异常是按照类型来捕获的
后续代码的执行
public class Test {
public static void main(String[] args) {
try{
int[] arr = {0,1,2,3};
System.out.println(arr[10]);
}catch (NullPointerException e){
e.printStackTrace();
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}finally {
System.out.println("*************");
}
System.out.println("aaa");
}
}
e.printStackTrace():打印异常追踪的堆栈信息
运行结果
此时异常类型被捕获,后续代码被执行
public class Test {
public static void main(String[] args) {
try{
int[] arr = {0,1,2,3};
System.out.println(arr[10]);
}catch (NullPointerException e){
e.printStackTrace();
}finally {
System.out.println("*************");
}
System.out.println("aaa");
}
}
运行结果
此时异常与catch异常类型不匹配,未被捕获到,即异常未被捕获成功,后续代码不再执行,仅finally中代码执行
try中可能出现多种异常,此时用多个catch对异常进行捕获
public class Test {
public static void main(String[] args) {
try{
int a = 1/0;
int[] arr = {0,1,2,3};
System.out.println(arr[10]);
}catch (NullPointerException e){
e.printStackTrace();
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("*************");
}
}
}
当异类之间具有父子关系时,先捕获子类异常,后捕获父类异常,否则会出现语法错误
若多个异常的处理方式是相同的,也可以写成
catch (ArrayIndexOutOfBoundsException | NullPointerException e){
e.printStackTrace();
}
finally的使用
finally不是必须存在的,当没有需要必须执行的代码时,可不使用finally
而有的特定的代码,程序是否发生异常,都需要执行,如对打开的资源进行回收,此时就可使用finally解决这个问题
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner sc = null;
try{
sc = new Scanner(System.in);
int a = sc.nextInt();
System.out.println(a);
}catch (InputMismatchException e){
e.printStackTrace();
}finally {
if(sc != null){
sc.close();
}
}
}
}
由于finally中的代码一定会执行的,一般在finally中进行一些资源清理的扫尾工作。
public class Test {
public static void main(String[] args) {
System.out.println(fun());
}
public static int fun(){
try{
return 1;
}finally {
return 10;
}
}
}
运行结果
由于finally执行是在方法返回之前,如果try或者catch中有return语句,finally会在该语句之前执行,若finally中也有return语句,那么则执行finally中语句,而不会执行try或者catch中有return语句
因此,不建议在finally中使用return语句
Java中虽然有许多异常类,但是并不能完全满足我们的需求,此时就需要我们依据实际情况,自定义异常类
自定义异常通常会继承自 Exception 或 RuntimeException,继承 Exception 的异常默认是受查异常,继承自 RuntimeException 的异常默认是非受查异常
1.自定义一个异常类,继承自 Exception 或 RuntimeException
2.实现一个带有String类型参数的构造方法,参数表示出现异常的原因
我们以用户登录为例
public class Login {
private static String userName = "admin";
private static String password = "111";
public static void login(String name, String word)
throws UserNameException,PassWordException{
if(!userName.equals(name)){
throw new UserNameException("用户名错误!");
}
if(!password.equals(word)){
throw new PassWordException("密码错误!");
}
System.out.println("登录成功!");
}
public static void main(String[] args) {
try{
login("admin","aaa");
} catch (UserNameException e){
e.printStackTrace();
} catch (PassWordException e){
e.printStackTrace();
}
}
}
//用户名异常
class UserNameException extends Exception{
public UserNameException(String message){
super(message);
}
}
//登录密码异常
class PassWordException extends Exception{
public PassWordException(String message){
super(message);
}
}
运行结果