天天看点

Java 异常从精通到陌生Java 异常从精通到陌生

Java 异常从精通到陌生

一.什么的异常?

异常(不同于寻常的)指的是在程序运行过程中发生的异常事件,通常是由外部问题(如硬件错误、输入错误)所导致的。在Java等面向对象的编程语言中异常属于对象。

在Java中通过Throwable类的各种子类来描述不同的异常。

二.为什么使用异常机制

  • 可读性
  • 可靠性
  • 可维护性

三.Java异常层次结构

Java 异常从精通到陌生Java 异常从精通到陌生

Throwable

Throwable 是 Java 语言中所有错误与异常的超类。表示任何可以作为异常被抛出的类。

Error

编译时和系统错误,程序中无法处理。

Exception

程序本身可以捕获并且可以处理的异常。

  • RuntimeException

四.使用

声明 throws

用于声明改方法可能抛出异常

public  void throwsException() throws IOException{
   
}

           

抛出 throw

public  void throwsException() throws IOException {
       throw new IOException();
}
           

捕获 catch

catch 语句块中可以捕获多个异常类型,并对不同类型的异常做出不同的处理

public void catchException(){
    try {
        throwsException();
    } catch (IOException e) { 
        //如果不处理可以声明异常继续抛出
        e.printStackTrace(); 
    }catch (Exception e) { 
        e.printStackTrace(); 
    }
}
           

同一个 catch 也可以捕获多种类型异常,用 | 隔开

public void catchException(){
    try {
        throwsException();
    } catch (IOException | Exception e) { 
        //如果不处理可以声明异常继续抛出
        e.printStackTrace(); 
    }
}
           

最后 finally

finally用于将资源恢复到它们的初始状态。如:以打开的文件或者网络链接

public void BufferedWriter() {
    final File file = new File("C:/Users/TheBlindM/Desktop/gbk.txt");
    FileWriter fileWriter =null; 
    PrintWriter printWriter = null;
    try  {
        fileWriter = new FileWriter(file);
        printWriter = new PrintWriter(fileWriter);
        while (true) {
            printWriter.println("hhh");
            printWriter.flush();
        }

    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if(fileWriter!=null) {
            try {
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (printWriter!=null){
            printWriter.close();
        }
            
    }

}
           

finally总是被执行(不过凡事都有例外) 。

finally遇见如下情况不会执行

  • 在前面的代码中用了System.exit()退出程序。
  • finally语句块中发生了异常。
  • 程序所在的线程死亡。
  • 关闭CPU。

try-finally可直接使用

finally内部不建议写return,会覆盖原先的return

try-with-resource

try-with-resource是Java 7中引入的

JAVA 7 提供了更优雅的方式来实现资源的自动释放,自动释放的资源需要是实现了 AutoCloseable 接口的类。

public void BufferedWriter() {
	final File file = new File("C:/Users/TheBlindM/Desktop/gbk.txt");
	try (FileWriter fileWriter = new FileWriter(file); 
	     final PrintWriter printWriter = new PrintWriter(fileWriter);) {
         while (true) {
             printWriter.println("hhh");
             printWriter.flush();
         }
	} catch (IOException e) {
       e.printStackTrace();
	}

}
           

流程

Java 异常从精通到陌生Java 异常从精通到陌生

五.实现机制

异常表

行号
20  public static int throwException() {
21  	int x;
22  	try {
23  		x=1;
24  		return x;
25  	}catch (Exception e){
26  		x=2;
27  		return x;
28  	}finally {
29  	 	x=3;
30     	}
31  }
           
public static int throwException();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=4, args_size=0
         0: iconst_1 //1(int)值入栈。 对应23行 x=1
         1: istore_0 //将栈顶int类型值保存到局部变量0中。
         2: iload_0  //从局部变量0中装载int类型值入栈。 对应24行
         3: istore_1
         4: iconst_3 //3(int)值入栈。 对应23行 x=1
         5: istore_0
         6: iload_1 //从局部变量1中装载int类型值入栈。 值为1
         7: ireturn
         8: astore_1 // 将栈顶引用类型值保存到局部变量1中。
         9: iconst_2 //2(int)值入栈。 对应26行 x=2
        10: istore_0 //将栈顶int类型值保存到局部变量0中
        11: iload_0  //从局部变量0中装载int类型值入栈。 对应27行
        12: istore_2 //
        13: iconst_3 
        14: istore_0 //
        15: iload_2
        16: ireturn 
        17: astore_3 //将栈顶引用类型值保存到局部变量3中。
        18: iconst_3 //1(int)值入栈。 对应27行 x=1
        19: istore_0
        20: aload_3
        21: athrow
      Exception table:
         from    to  target type
             0     4     8   Class java/lang/Exception
             0     4    17   any
             8    13    17   any

           

Exception table:异常表

  • from 可能会发生异常的起点
  • to 可能会发生异常的结束点
  • target from to之间发生异常后处理的位置
  • type 可以处理的类型

3条异常表对应三条

  • 如果try语句块中出现属于Exception或其子类的异常,则转到catch语句处理
  • 如果try语句块中出现不属于Exception或其子类的异常,则转到finally语句处理
  • 如果catch语句块中出现异常,则转到finally语句处理

问题:

1.如果finally中带return或者catch中带return,会怎样?

如果带return 在字节码中会转化为ireturn(返回int类型值,返回栈顶)

六.编写建议

1.异常应该用于异常的情况下,永远不要应该用于正常的控制流程

2.对于可恢复的情况使用受检异常,对于编程错误使用运行时异常

3. 优先使用标准异常

异常 使用场合
IllegalArgumentException 参数的值不合适
IllegalStateException 参数的状态不合适
NullPointerException 在null被禁止的情况下参数值为null
IndexOutOfBoundsException 下标越界
ConcurrentModificationException 在禁止并发修改的情况下,对象检测到并发修改
UnsupportedOperationException 对象不支持客户请求的方法

4.优先捕获最具体的异常

5.不要记录并抛出异常

欢迎关注公众号

Java 异常从精通到陌生Java 异常从精通到陌生

参考

深入理解JVM虚拟机

Effective Java

https://www.pdai.tech/md/java/basic/java-basic-x-exception.html