Java基础 - 异常

1. 异常的分类

1.1 Throwable

Java中所有的异常都继承自java.lang.Throwable这个类表示可抛出的

Throwable这顶级父类的常用方法:

1. 返回异常发生时的详细信息
public string getMessage();
 
2. 返回异常发生时的简要描述
public string toString();
 
3. 返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同
public string getLocalizedMessage();
 
4. 在控制台上打印Throwable对象封装的异常信息
public void printStackTrace();

1.2 Exception和Error

ExceptionError这是Thorwable的两个重要的子类:

Exception表示异常Error表示错误

1.2.1 Error

定义:

​ 程序无法处理的错误,表示程序运行中出现较为严重的问题;

​ 通常有: VirtualMachineError(虚拟机错误),比如说当jvm耗完可用内存时,将出现OutOfMemoryError(OOM)

​ 此类错误发生时,JVM一般会终止线程,

1.2.2 Exception

定义:

​ 程序本身可以处理的异常

分类:

  • 运行时异常:(RuntimeException)这一类异常,在编写代码时,可以不捕获;例如: NullPotinterException(空指针异常)
  • 非运行时异常: 这一类异常,在编写代码时,必须要捕获,否则编译不过去;例如: FileNotFoundException(文件未找到异常)

2. 异常的处理

2.1 抛出 Throw、Thorws

2.1.1throw

throw关键字使用在方法内部,将异常丢出去,程序执行到这一步,会报错误,

throw一旦进入被执行,程序立即会转入异常处理阶段,后面的语句就不再执行,而且所在的方法不再返回有意义的值!

public  void  m1(){
    if(a > 0){
		throw  new NullPointerException();
    }        
}

2.1.2 throws

throws 关键字使用在方法上,将程序丢给调用者

如果一个方法里面不想有任何的异常处理,则在没有任何代码进行异常处理的时候,必须对这个方法进行声明有可能产生的所有异常

(其实就是,不想自己处理,那就交给别人吧,告诉别人我会出现什么异常,报自己的错,让别人处理去吧)

如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。

例如汽车在运行时可能会出现故障,汽车本身没办法处理这个故障,那就让开车的人来处理。

public void m1() throws NullPointException,FileNotFoundException{
    
}
  • 需要注意的是:
    • throw 是自己处理异常
    • throws 是将异常丢给调用者

2.2 捕获 try

语法:

try {  
	// 可能会发生异常的程序代码  
} catch (Type1 id1){  
	// 捕获并处置try抛出的异常类型Type1  
} catch (Type2 id2){  
	 //捕获并处置try抛出的异常类型Type2  
}finally {  
	// 无论是否发生异常,都将执行的语句块  
} 

执行顺序:

try、catch、finally语句块的执行顺序:
1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;
2)当try捕获到异常,catch语句块里没有处理此异常的情况:此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;
3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句。

注意: finally不执行的情况

finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。

在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。

3. 自定义异常

自定义异常格式:

public class MyException extends RuntimeException {

    public MyException() {
    }

    public MyException(String message) {
        super(message);
    }

    public MyException(String message, Throwable cause) {
        super(message, cause);
    }

    public MyException(Throwable cause) {
        super(cause);
    }

    public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

/*
a.输出异常的信息 
	getMessage() 

b.输出导致异常更为详细的信息 
 	printStackTrace() 
*/

4. try...catch...finally

关于try...catch...finally执行顺序

1. 只在try中返回

public static int m1() {
    int a = 10;
    try {
        System.out.println("try - " + a);
        return a;
    } catch (Exception e) {
        System.out.println("catch - " + a);
        return a = 20;
    } finally {
        a = 15;
        System.out.println("finall - " + a);
    }
}

public static void main(String[] args) {
        System.out.println("main - " + m1());
}

/*
执行结果:
	try - 10
    finall - 15
	main - 10
*/

语句在finally中执行了,但是没有将a的值更改。

解释:
代码顺序执行从try到finally,由于finally是无论如何都会执行的,所以try里的语句并不会直接返回。

​ 在try语句的return块中,return返回的引用变量并不是try语句外定义的引用变量a,

​ 而是系统重新定义了一个局部引用a1,这个引用指向了引用a对应的值,也就是10,即使在finally语句中把引用a指向了值15,

因为return返回的引用已经不是a,而是a1,所以引用a的值和try语句中的返回值无关了。

2. 在finally中也返回

public static int m1() {
    int a = 10;
    try {
        System.out.println("try - " + a);
        return a;
    } catch (Exception e) {
        System.out.println("catch - " + a);
        return a = 20;
    } finally {
        a = 15;
        System.out.println("finall - " + a);
        return a;
    }
}
public static void main(String[] args) {
    System.out.println("main - " + m1());
}


/*
 执行结果:
 	try - 10
	finall - 15
	main - 15
*/
-- 这里是将  返回值更改了

可以看到,是从finally语句块中返回的。可见,JVM是忽略了try中的return语句

3. 返回值是数组或是集合

 public static List m1() {
     List<String> strList = new ArrayList<>();
     try {
         strList.add("try");
         System.out.println("try - ");
         return strList;
     } catch (Exception e) {
         strList.add("catch");
         System.out.println("catch - ");
         return strList;
     } finally {
         strList.add("finally");
         System.out.println("finall - ");
         return strList;
     }
 }

public static void main(String[] args) {
    System.out.println("main - " + m1());
}


/*
执行结果:

try - 
finall - 
main - [try, finally]

*/

4. 总结:

1、finally语句总会执行

2、如果try、catch中有return语句,finally中没有return,那么在finally中修改除包装类型和静态变量、全局变量以外的数据都不会对try、catch中返回的变量有任何的影响(包装类型、静态变量会改变、*全局变量*

3、尽量不要在finally中使用return语句,如果使用的话,会忽略try、catch中的返回语句,也会忽略try、catch中的异常,屏蔽了错误的发生

4、finally中避免再次抛出异常,一旦finally中发生异常,代码执行将会抛出finally中的异常信息,try、catch中的异常将被忽略

所以在实际项目中,finally常常是用来关闭流或者数据库资源的,并不额外做其他操作。

posted @ 2022-01-26 14:38  ABingZ  阅读(75)  评论(0)    收藏  举报