JAVA异常处理

JAVA异常处理_第1张图片

目录

一、RunTimeException和其他Exception 

二、捕获异常

三、多重捕获块

四、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中的异常


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

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

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

JAVA异常处理_第2张图片

一、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");
   }
}

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

JAVA异常处理_第3张图片

三、多重捕获块

一个 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;
}

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

四、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();
        }
    }
}

JAVA异常处理_第4张图片

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");
    }
  }
}

JAVA异常处理_第5张图片

注意:在 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");
	    }
	}


}

JAVA异常处理_第6张图片

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

JAVA异常处理_第7张图片

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"

 ​​​​​​JAVA异常处理_第8张图片

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");
        }
 
    }
}

 JAVA异常处理_第9张图片

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

        不要在fianlly中使用return。

        不要在finally中抛出异常。

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

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

你可能感兴趣的:(JAVA,java,开发语言)