JAVA异常处理

目录

一、RunTimeException和其他Exception 

二、捕获异常

三、多重捕获块

四、Catch捕获异常顺序

五、throws/throw 关键字

1、throws关键字

2、throw关键字

3、throw关键字与throws关键字的区别

六、finally关键字 

七、finally块和return

1、一个不容易理解的事实:在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。

2、finally中的return会抑制(消灭)前面try或者catch块中的异常

3、finally中throw的异常会覆盖(消灭)前面try或者catch中的异常

4、try catch 语句中的return逻辑​编辑


Throwable是Error和Exception的父类,用来定义所有可以作为异常被抛出来的类。 

Error是编译时错误和系统错误,系统错误在除特殊情况下,都不需要你来关心,基本不会出现。而编译时错误,如果你使用了编译器,那么编译器会提示。

Exception则是可以被抛出的基本类型,我们需要主要关心的也是这个类。
Exception又分为RunTimeException其他Exception (Checked Exception)。

一、RunTimeException和其他Exception 

  • RuntimeException:是运行时异常: 如 : NullPointerException 、 ClassCastException ;当出现这些异常时,可以不用程序员进行处理,不影响程序的鲁棒性。
  • 其他Exception:一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强制程序去捕获此类异常,即会出现要求你把这段可能出现异常的程序进行 try catch,或者是throw到上一层进行处理。
     

二、捕获异常

使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。

try/catch代码块中的代码称为保护代码,使用 try/catch 的语法如下:

try
{
   // 程序代码
}catch(ExceptionName e1)
{
   //Catch 块
}

Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。

如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。

下面的例子中声明有两个元素的一个数组,当代码试图访问数组的第四个元素的时候就会抛出一个异常。

// 文件名 : ExcepTest.java
import java.io.*;
public class ExcepTest{
 
   public static void main(String args[]){
      try{
         int a[] = new int[2];
         System.out.println("Access element three :" + a[3]);
      }catch(ArrayIndexOutOfBoundsException e){
         System.out.println("Exception thrown  :" + e);
      }
      System.out.println("Out of the block");
   }
}

我们可以在编译器里面运行后可以看到运行结果 

三、多重捕获块

一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获。

多重捕获块的语法如下所示:

try{
   // 程序代码
}catch(异常类型1 异常的变量名1){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}catch(异常类型3 异常的变量名3){
  // 程序代码
}

上面的代码段包含了 3 个 catch块。

可以在 try 语句后面添加任意数量的 catch 块。

如果保护代码中发生异常,异常被抛给第一个 catch 块。

如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。

如果不匹配,它会被传递给第二个 catch 块。

如此,直到异常被捕获或者通过所有的 catch 块。

try {
    file = new FileInputStream(fileName);
    x = (byte) file.read();
} catch(FileNotFoundException f) { // Not valid!
    f.printStackTrace();
    return -1;
} catch(IOException i) {
    i.printStackTrace();
    return -1;
}

如果无法正常编译很正常,保护代码中的错误比较多。

四、Catch捕获异常顺序

  1. 抛出异常对象与catch子句参数类型相同
  2. 抛出异常对象为catch子句参数类的子类
  3. 按照先后顺序捕获抛出异常对象,只捕获一次

示例二,因为抛出的ArithmeticException异常是父类Exception的子类,所以示例2可以正常编译。同样因为Exception是父类,所以示例3也可以通过。但是示例4会报错,因为第二个catch语句永远无法正常运行。

五、throws/throw 关键字

1、throws关键字

throws关键字用在方法声明上,明确告诉调用者本方法可能产生的的异常,但方法本身不处理,用throws向上层抛出。

//throws关键字的简单使用
public class Test{
    public static void main(String[] args) {
        try{
            System.out.println(print(10,0));
        }catch (Exception e){//程序中出现错误的所有具体异常均是由Exception继承而来,e为Exception类的一个对象,该类对象由IVM产生,不需new就可直接使用
            e.printStackTrace();
        }
    }
    public static int print(int x,int y)throws Exception{//在方法声明上使用,但不做任何处理,将异常抛回上层
        return x/y;
    }
}

其他方法若想调用throws关键字声明的方法,在调用时必须使用try…catch进行异常捕获。因该方法可能出现异常,故必须按照异常方法进行处理。

public class ExcepTest{
    public static void main(String[] args) {
        try{
            System.out.println(print(10,0));
        }catch (Exception e){
            e.printStackTrace();
        }
        fun();
    }
    public static int print(int x,int y)throws Exception{
        return x/y;
    }
    public static void fun(){
        try{
            System.out.println(print(12,3));
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。

例如,下面的方法声明抛出 RemoteException 和 InsufficientFundsException:

import java.io.*;
public class className
{
   public void withdraw(double amount) throws RemoteException,
                              InsufficientFundsException
   {
       // Method implementation
   }
   //Remainder of class definition
}

2、throw关键字

 throw是直接编写在语句中,表示人为进行异常抛出。如果异常类对象实例化不希望由JVM产生而由用户产生,此时使用throw关键字来完成。

//throw关键字的简单使用
public class Test{
    public static void main(String[] args){
        try{
            throw new Exception("你今天真好看!");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

3、throw关键字与throws关键字的区别

1.throw关键字用于方法内部,表示人为异常抛出。

2.throws关键字用于方法声明上,明确告诉用户本方法可能产生的异常,同时该方法可能不处理该异常。

六、finally关键字 

finally 关键字用来创建在 try 代码块后面执行的代码块。

无论是否发生异常,finally 代码块中的代码总会被执行。

在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。

finally 代码块出现在 catch 代码块最后,语法如下:

try{
  // 程序代码
}catch(异常类型1 异常的变量名1){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}finally{
  // 程序代码
}
public class ExcepTest{
  public static void main(String args[]){
    int a[] = new int[2];
    try{
       System.out.println("Access element three :" + a[3]);
    }catch(ArrayIndexOutOfBoundsException e){
       System.out.println("Exception thrown  :" + e);
    }
    finally{
       a[0] = 6;
       System.out.println("First element value: " +a[0]);
       System.out.println("The finally statement is executed");
    }
  }
}

注意:在 try/catch 后面添加 finally 块并非强制性要求的 

七、finally块和return

1、一个不容易理解的事实:在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。

public class ExcepTest{
	public static void main(String[] args){
	    int re = bar();
	    System.out.println(re);
	}
	private static int bar() {
	    try{
	        return 5;
	    } finally{
	        System.out.println("finally");
	    }
	}


}

 finally中的return 会覆盖 try 或者catch中的返回值。

2、finally中的return会抑制(消灭)前面try或者catch块中的异常

class TestException {
    public static void main(String[] args) {
        int result;
        try {
            result = foo();
            System.out.println(result);           //输出100
        } catch (Exception e) {
            System.out.println(e.getMessage());    //没有捕获到异常
        }
 
 
        try {
            result = bar();
            System.out.println(result);           //输出100
        } catch (Exception e) {
            System.out.println(e.getMessage());    //没有捕获到异常
        }
    }
 
    //catch中的异常被抑制
    @SuppressWarnings("finally")
    public static int foo() throws Exception {
        try {
            int a = 5 / 0;
            return 1;
        } catch (ArithmeticException amExp) {
            throw new Exception("我将被忽略,因为下面的finally中使用了return");
        } finally {
            return 100;
        }
    }
 
    //try中的异常被抑制
    //J2SE 提供的最后一个批注是 @SuppressWarnings。该批注的作用是给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默。
    @SuppressWarnings("finally")
    public static int bar() throws Exception {
        try {
            int a = 5 / 0;
            return 1;
        } finally {
            return 100;
        }
    }
}

结果会是正常打印finally语句块中的两个"return  100"

 ​​​​​​

3、finally中throw的异常会覆盖(消灭)前面try或者catch中的异常

public class TestException {
    public static void main(String[] args) {
        int result;
        try {
            result = foo();
        } catch (Exception e) {
            System.out.println(e.getMessage());    //输出:我是finaly中的Exception
        }
 
 
        try {
            result = bar();
        } catch (Exception e) {
            System.out.println(e.getMessage());    //输出:我是finaly中的Exception
        }
    }
 
    //catch中的异常被抑制
    @SuppressWarnings("finally")
    public static int foo() throws Exception {
        try {
            int a = 5 / 0;
            return 1;
        } catch (ArithmeticException amExp) {
            throw new Exception("我将被忽略,因为下面的finally中抛出了新的异常");
        } finally {
            throw new Exception("我是finally中的Exception");
        }
    }
 
    //try中的异常被抑制
    @SuppressWarnings("finally")
    public static int bar() throws Exception {
        try {
            int a = 5 / 0;
            return 1;
        } finally {
            throw new Exception("我是finally中的Exception");
        }
 
    }
}

 

4、try catch 语句中的return逻辑

我们需要思考一下最后的结果会是43还是35?

答案是43:在try中执行到return语句时,不会真正的return,而是计算return中的表达式(本例为
执行a+b)结果保存到一个临时栈中,继续执行finally中的语句,最后才会从临时栈中取出之前的结果返回。

try catch return 逻辑关系汇总

1try{}catch(){}finally{}return;顺序执行
2try{return;}catch(){}finally{}return;即执行完try语句块,将return的值保存在临
时栈中,再执行finally语句块,之后返回临时
栈中的值。
3try{}catch(){return;}finally{}return;执行try,执行finally,再执行return;
4try{}catch(){}finally{return;}执行finally中的return语句
5try{return;}catch(){return;}finally{};根据有无异常执行情况二或情况三。
6try{return;}catch(){}finally{return;}执行完try语句块,将return的值保存在临时
栈中,再执行finally语句块,因为finally中有
return,所以返回finally中的return值
7try{}catch(){return;}finally{return;}执行完catch语句块,将return的值保存在临
时栈中,再执行finally语句块,因为finally中
有return,所以返回finally中的return值
8try{return;}catch(){return;}finally{return;}有异常:执行情况七。
无异常:执行情况六。

return语句优先级: finally > catch > try

  • 当try catch中的代码执行到return语句时,会先把该return的值存入临时栈中,继续执行finally, 执行完finally语句后才返回临时栈中的值。
  • 如果finally中有return那就把finally中的返回值当作方法体的返回值返回。
  • 如果finally中没有return返回catch中的return值,如果catch中也没有就返回try中的值,如果都没有方法体继续向下执行。

上面的4个例子都异于常人的编码思维,因此我建议:

        不要在fianlly中使用return。

        不要在finally中抛出异常。

        减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的。

        将尽量将所有的return写在函数的最后面,而不是try ... catch ... finally中。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WHS-_-2022

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值