2020-11-30

Java异常

Java异常体系

Java异常体系
顶层类Throwable派生出了Error(错误)和Exception(异常)两个子类:
Error:Java运行时内部错误或资源耗尽错误,应用程序不抛出此类异常,这种内部类错误一旦出现,只能告知用户并是程序终止。如,内存溢出等。
Exception:是各种异常类的父类。有一个子类RunTimeException,又派生出很多常见的异常类,如,NullPointerException,IndexOutOfBoundsException等。
派生于Error类或者RuntimeException类的所有异常称为非受查异常,所有其他的异常称为受查异常。若代码抛出受查异常,则必须要显示地处理。
异常即指程序在运行时出现错误时通知调用者的一种机制。

常见异常

除数是0

System.out.println(10/0);
//执行结果
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Blog.main(Blog.java:9)

数组越界

int[] array = {1,2,3};
System.out.println(array[3]);
//执行结果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
	at Blog.main(Blog.java:11)

访问空对象

public class Blog {
    public int num = 10;
    public static void main(String[] args) {
        Blog blog = null;
        System.out.println(blog.num);
    }
}
//执行结果
Exception in thread "main" java.lang.NullPointerException
	at Blog.main(Blog.java:14)

异常的基本用法

捕获异常

基本语法:

try{
	//有可能出现异常的语句;
}catch(异常类型 异常对象){
	//处理异常
}finally{
	//异常的出口
}
  • try代码块中放的是可能会出现异常的代码;
  • catch代码块中放的是出现异常后的处理行为;
  • finally代码块中的代码用于处理善后工作,会在最后执行(一定会被执行);
  • catch和finally代码块可根据实际情况选择加或不加。
    异常处理流程
  • 程序先执行try中的代码;
  • 若try中的代码出现异常,就会结束try中的代码,并检查和catch中的异常类型是否匹配;
  • 若匹配,则执行catch中的代码;
  • 若无匹配的异常类型,则会将异常向上传递到上层调用者;
  • 若上层调用者也没有相匹配的异常类型,则继续向上传递;
  • 一直到main方法也没有合适的代码来处理异常,则会交给JVM来处理,即程序会异常终止;
  • 无论是否找到了相匹配的类型,finally中的代码都会被执行(在该方法结束之前执行)。

示例1 不处理异常

System.out.println("before");
System.out.println(10/0);
System.out.println("last");
//执行结果
before
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Blog.main(Blog.java:17)

在异常之前的语句可正常运行,但一遇见异常,因为没有对应的异常处理,所以JVM来处理,即程序运行终止。
示例2 使用try catch后的程序

try{
    System.out.println("before");
    System.out.println(10/0);
    System.out.println("after");
}catch(ArithmeticException e){
    e.printStackTrace();
}
System.out.println("have catch");
System.out.println("after");
//执行结果
before
java.lang.ArithmeticException: / by zero
	at Blog.main(Blog.java:22)
have catch

由上述代码可知,若在try代码块中捕获到异常后,则异常语句后面的代码将不会再被执行。之后,再根据catch中的语句进行处理。try catch语句后的代码也会继续被执行。

示例3 catch只能处理对应种类的异常

try{
    System.out.println("before");
    System.out.println(10/0);
    System.out.println("after");
}catch(ArrayIndexOutOfBoundsException e){
    e.printStackTrace();
}
System.out.println("have catch");
//执行结果
before
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Blog.main(Blog.java:31)

此时,catch语句不能捕获到对应的算术运算异常,因为异常类型不匹配。所以交给JVM运行,程序运行终止。
示例4 catch可以有多个

try{
    System.out.println("before");
    System.out.println(10/0);
    System.out.println("after");
}catch(ArrayIndexOutOfBoundsException e){
    System.out.println("数组下标越界异常");
    e.printStackTrace();
}catch(ArithmeticException e){
    System.out.println("算术运算异常");
    e.printStackTrace();
}
System.out.println("have catch");
//执行结果
before
算术运算异常
java.lang.ArithmeticException: / by zero
	at Blog.main(Blog.java:39)
have catch

一段代码可能会抛出多种不同类型的异常,不同的异常有不同的处理方式,因此可以搭配多个catch代码块。
若多个异常的处理方式完全相同,也可写成下述代码

try{
    System.out.println("before");
    System.out.println(10/0);
    System.out.println("after");
}catch(ArrayIndexOutOfBoundsException | ArithmeticException e){
    System.out.println("异常");
    e.printStackTrace();
}
System.out.println("have catch");

示例5 finally进行完善工作

public static int fac(){
        //finally善后
        //1、捕获异常
        try{
            System.out.println(10/0);
        }catch(ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
            return 2;
        }catch(ArithmeticException e){
            e.printStackTrace();
            return 3;
        }finally{
            return 4;
        }
    //执行结果
    java.lang.ArithmeticException: / by zero
	at Blog.fac(Blog.java:65)
	at Blog.main(Blog.java:60)
4

		//未捕获异常
		try{
            System.out.println(10/0);
        }catch(ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
            return 2;
        }finally{
            return 4;
        }
}
//执行结果
4

上述代码均返回的是4,即finally代码块中的内容无论异常是否被捕获到,最终都会被执行到。
由此,可以将Scanner.close()放到代码块中,保证其一定会被执行到。代码如下所示

Scanner scan = new Scanner(System.in);
try{
    int num = scan.nextInt();
    System.out.println(10/0);
}catch(ArrayIndexOutOfBoundsException | ArithmeticException e){
    e.printStackTrace();
}finally{
    System.out.println("hello");
    scan.close();
}

示例6 使用try回收资源
上述代码的一种等价写法。

try(Scanner scan = new Scanner(System.in)){
    int num = scan.nextInt();
    System.out.println(10/0);
}catch(ArrayIndexOutOfBoundsException | ArithmeticException e){
    e.printStackTrace();
}

将Scanner在try的代码块中创建,以保证try执行完毕后自动调用Scanner的close()方法。

示例7 若本方法中没有合适的处理异常的方式,则会沿着调用栈向上传递。

public static void func() {
    int[] arr = {1,2,3};
    System.out.println(arr[10]);
}
public static void main(String[] args) {
    try{
        func();
    }catch(ArrayIndexOutOfBoundsException e){
        System.out.println("下标越界");
        e.printStackTrace();
    }
    System.out.println("after");
}
//执行结果
下标越界
java.lang.ArrayIndexOutOfBoundsException: 10
	at Blog.func(Blog.java:11)
	at Blog.main(Blog.java:15)
after

若一直向上传递都没有合适的异常处理方法,则会交给JVM处理,程序就会异常终止。

抛出异常

除了Java内置的类会抛出一些异常之外,也可以使用throw关键字来自行抛出异常。

public static void main(String[] args) {
    divide(10,0);
}
public static int divide(int x, int y){
    if(y == 0){
       throw new ArithmeticException("除数为0");
    }
    return x/y;
}
//执行结果
Exception in thread "main" java.lang.ArithmeticException: 除数为0
	at Blog.divide(Blog.java:14)
	at Blog.main(Blog.java:10)

自定义异常

场景 用户登录功能
若账号输入错误,则返回“Wrong Username”信息,并终止;若密码错误,则返回“Wrong Password”信息,并终止;否则,显示“登陆成功”。

class UserError extends Exception{
    public UserError(String message){
        super(message);
    }
}
class PassError extends Exception{
    public PassError(String message){
        super(message);
    }
}
public class MyException {
    private static String username = "admin";
    private static String password = "12345";

    public static void main(String[] args) {
        try{
            login("admin", "1234");
        }catch(UserError userError){
            userError.printStackTrace();
        }catch(PassError passError){
            passError.printStackTrace();
        }
    }
    public static void login(String username, String password) throws UserError, PassError{
        if(!MyException.username.equals(username)){
            throw new UserError("Wrong Username!");
        }
        if(!MyException.password.equals(password)){
            throw new PassError("Wrong Password");
        }
        System.out.println("Success!");
    }
}

在上述场景中,定义了两个异常类:UserError和PassError。他们都继承自Exception这个异常类。在使用两个异常类时,需在方法名称后面对其进行声明,即:throws UserError,PassError。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值