异常及异常的处理和使用

大家可能都对异常不陌生了,在进行程序测试的时候,执行过程中发生的不正常行为都叫异常,爆出的那些红色字符就是异常的体现.通过这篇文章,我们来对异常进行一个剖析.就分为下面四个部分进行吧!

1.认识异常

异常的种类非常多,而且不同的种类也有不同的处理方式.

1.1常见的异常例子

a.当除数为0的时候.(算术异常)
相必大家都知道除数不能为0吧,写代码时如果误把除数写成0了,就会报出异常,不多说,上代码.

System.out.println(3/0);
//执行后你会发现这样一行红色的代码
Exception in thread "main" java.lang.ArithmeticException: / by zero

ArithmeticException就是算术异常.在 ArithmeticException: 后面的 / by zero就是你所产生错误的原因:除数不能为0.
b.数组下标越界(数组下标越界异常)
假设数组的长度size为5,而数组的访问范围是[0,4],是从0号下标开始的,到(size-1)号下标结束.如果你访问的时候超过了这个范围,你就会又看见熟悉的红色代码.如我下面的代码.

int[] arr={
    
    1,2,3,4,5};
System.out.println(arr[5]);
//执行后,不好意思,爆红了.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5

ArrayIndexOutOfBoundsException数组下标越界异常,这个异常非常的常见,而且出现率挺高的,如果好兄弟们写代码的时候不细心就会出错.
c.访问null对象(空指针异常).

public class Test{
    
    
	int num=1;
	public static void main(String[] args){
    
    
		//让这个引用t指向null.
		Test t=null;
		System.out.println(t.num);
	}
}
//执行后会出现异常
Exception in thread "main" java.lang.NullPointerException

NullPointerException就是空指针异常.

注意: 在程序发生异常后,出现异常的代码,它后面的代码是不会往下执行的.
代码演示:

System.out.println("hello world");
System.out.println(10/0);
System.out.println("hello,hello");

//执行结果

hello world
Exception in thread "main" java.lang.ArithmeticException: / by zero

1.2 防御式编程(暂时先了解)

错误在代码中是客观存在的,所以我们要让程序出现问题的时候及时通知程序猿.
我们有两种主要的方式.LBYL,EAFP
LBYL:Look Before You Leap:在操作之前就做充分的检查.
EAFP: It’s Easier to Ask Forgiveness than Permission,先操作,遇到问题时再处理.
举个一看就懂的例子:
第一种情况: 你和你妹子去鬼屋玩,你比较怂,想要去拉妹子的手而去询问妹子,等到妹子同意后在拉手 (LBYL).
第二种情况: 妹子的注意力高度集中,这个时候你突然去拉她的手,大不了她吓到了给你一巴掌,你再道歉就是.(EAFP).
我们异常的核心思想就是EAFP.

2.异常的基本用法.

我们来对异常进行处理.

2.1 捕获异常

//基本语法:
try{
    
    
	//...
}catch(异常类型,异常对象){
    
    
	//...
}finally{
    
    
	//...
}

a.try 代码块中放的是可能出现异常的代码.
b.catch 代码块中放的是出现异常后的处理行为.
c.finally 代码块中的代码用于处理善后工作, 会在最后执行.
d.其中 catch 和 finally 都可以根据情况选择加或者不加.

示例一:未处理异常

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

示例二:使用 try catch 进行捕获后

try{
    
    
	System.out.println("hello world");
	System.out.println(10/0);
}catch(ArithmeticException e){
    
    
	e.printStackTrace();
}
System.out.println("hello,hello");
//执行结果:
hello world
hello,hello
java.lang.ArithmeticException: / by zero
	at demo01TimeAndSpace.Test.main(Test.java:7)

可以发现,捕获异常后异常后面的代码语句就可以执行了.

2.2 异常处理流程

a.程序先执行 try 中的代码
b.如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.
c.如果找到匹配的异常类型, 就会执行 catch 中的代码
d.如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.
e.无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).
f.如果上层调用者也没有处理的了异常, 就继续向上传递.
g.一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.

2.3 抛出异常

除了Java内置的类会抛出异常外,我们也可以手动抛出某个异常,使用throw关键字来完成此操作.
语法:

throw new 异常类型(可以写一些注释);

完成一个 x/y 的方法

public class Test {
    
    
    public static int divide(int x,int y){
    
    
        if (y==0){
    
    
            throw new ArithmeticException("除数为 0 异常");
        }
        return x/y;
    }
    public static void main(String[] args) {
    
    
        int num=divide(20,0);
        System.out.println(num);
    }
}

当我们调用此方法时,不小心将y设置为0,会出现下面的情况.

Exception in thread "main" java.lang.ArithmeticException: 除数为 0 异常
	at demo01TimeAndSpace.Test.divide(Test.java:6)
	at demo01TimeAndSpace.Test.main(Test.java:11)

2.4 异常说明

我们在处理异常的时候, 通常希望知道这段代码中究竟会出现哪些可能的异常.
我们可以使用 throws 关键字, 把可能抛出的异常显式的标注在方法定义的位置. 从而提醒调用者要注意捕获这些异常.
直接看例子:

public static int divide(int x,int y) throws ArithmeticException{
    
    
     if (y==0){
    
    
         throw new ArithmeticException("除数为 0 异常");
     }
     return x/y;
 }

2.5关于finally的注意事项

finally 中的代码保证一定会执行到.但是也会带来一些麻烦,来看一个代码.

public static int func() {
    
    
 	try {
    
    
 		return 10;
 	}finally {
    
    
 		return 20;
 	}
}
//方法被调用后结果为:
//20.

finally 执行的时机是在方法返回之前:
try 或者 catch 中如果有 return 会在这个 return 之前执行 finally.

但是如果finally 中也存在 return 语句, 那么就会执行 finally 中的 return, 从而不会执行到 try 中原有的 return.
所以一般不建议在finally中写return 语句.

3.异常体系

在这里插入图片描述

a. 顶层类 Throwable 派生出两个重要的子类, ErrorException
b. Error 指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误一旦出现,除了告知用户并使程序终止之外, 再无能无力. 这种情况很少出现. (相当于人得了一种癌症,还是处于晚期不能治的那种)
c. Exception 是我们程序猿所使用的异常类的父类.
d. Exception 有一个子类称为 RuntimeException , 这里面又派生出很多我们常见的异常类NullPointerException , IndexOutOfBoundsException

Java语言规范将派生于 Error 类或 RuntimeException 类的所有异常称为受查异常 , 所有的其他异常称为 非受查异常

如果代码出现了受查异常,那么就要进行显式处理,如果不处理,编译就会无法通过.
而方法我们上面已经给过了.就是 2.3 和 2.4,使用throw关键字或throws关键字进行处理.

4.自定义异常类.

Java库中已经有非常丰富的异常类了,但是我们在实际场景中可能要去创建符合我们要求的异常类,即自定义异常类.它继承自Exception类.
我们来举一个模拟用户登录的例子吧:
在实现用户登录的功能中,用户可能会出现用户名输入错误或者密码输入错误的情况,这个时候我们进行处理,就与要去抛出两个异常,即用户名输入错误异常和密码输入错误异常去提醒客户.

自定义 用户名输入异常:

public class UserException extends RuntimeException{
    
    
    public UserException(String message) {
    
    
        super(message);
    }
}

自定义 密码输入异常:

public class PasswordException extends Exception{
    
    
    public PasswordException(String message) {
    
    
        super(message);
    }
}

具体实现我们来给一个完整的代码:

import java.util.Scanner;

public class Login {
    
    
    String name="admin";
    String password="123456";

    public boolean loginInfo(String n,String p){
    
    
        if (!name.equals(n)){
    
    
        	//如果输入的用户名和我们所给的不一样,会抛异常
           throw new UserException("用户名输入有误");
        }
        if (!password.equals(p)){
    
    
        	//如果输入的密码和我们所给的不一样,会抛异常
           throw new PasswordException("密码输入有误");
        }
        return true;
    }
    public static void main(String[] args) {
    
    
        Scanner sc=new Scanner(System.in);
        String s1=sc.next();
        String s2=sc.next();
        Login login=new Login();
        login.loginInfo(s1,s2);
        System.out.println("login ok");
        sc.close();
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_47278183/article/details/121033422