java-异常、断言和日志

注意
本文档属于个人笔记,个人水平有限,请酌情采纳,有任何错误可在评论区指出
/images/all/java-exception-category.jpg
异常分类

Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。程序不应该抛出这种类型的对象

平时在设计Java程序时,需要关注Exception层次结构。

Java语言规范将派生于Error类或RuntimeException类的所有异常称为不受检查性( unchecked)异常,所有其他的异常称为检查性 (checked)异常。编译器将核查是否为所有的检查性异常提供了异常处理器。

除了RuntimeException及其子类以外,其他的Exception类及其子类都属于检查异常,当程序中可能出现这类异常,要么使用try-catch语句进行捕获,要么用throws子句抛出,否则编译无法通过。

用户自定义异常类,只需继承Exception类即可。

在程序中使用自定义异常类,大体可分为以下几个步骤:

  • 创建自定义异常类。
  • 在方法中通过throw关键字抛出异常对象。
  • 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
  • 在出现异常方法的调用者中捕获并处理异常。
try{
    //code that might generate exceptions    
}catch(Exception e){
    //the code of handling exception1
}catch(Exception e){
    //the code of handling exception2
}

上述try-catch所描述的即是监控区域。java方法在运行过程中发生了异常,则创建异常对象。将异常抛出监控区域之外,由java运行时系统负责寻找匹配的catch子句来捕获异常。若有一个catch语句匹配到了,则执行该catch块中的异常处理代码,就不再尝试匹配别的catch块了。

匹配的原则是:如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获的异常类型相匹配。

当代码抛出一个异常时,就会终止方法中剩余代码的处理,并退出这个方法的执行

  • 不管是否有异常被捕获. finally子句中的代码都被执行
  • try语句可以只有finally子句,而没有catch子句

如果一个方法会导致一个异常但不处理它,它必须声明该异常以使方法的调用者可以保护它们自己而不发生异常。

如果某个方法不想处理所导致的异常,因而它必须声明throws子句来声明可能引发的异常;然后,在方法调用处必须定义try/catch语句来捕获该异常。

  • 当子类在重写父类的一个函数时,不能声明抛出比父类的版本更多的异常
  • 在子类的构造函数中必须声明父类可能抛出的全部异常

Java的异常处理是通过5个关键词来实现的:trycatchthrowthrowsfinally。一般情况下是用try来执行一段程序,如果系统会抛出(throw)一个异常对象,可以通过它的类型来捕获(catch)它,或通过总是执行代码块(finally)来处理;try用来指定一块预防所有异常的程序;catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型;throw语句用来明确地抛出一个异常;throws用来声明一个方法可能抛出的各种异常(当然声明异常时允许无病呻吟);finally为确保一段代码不管发生什么异常状况都要被执行;try语句可以嵌套,每当遇到一个try语句,异常的结构就会被放入异常栈中,直到所有的try语句都完成。如果下一级的try语句没有对某种异常进行处理,异常栈就会执行出栈操作,直到遇到有处理这种异常的try语句或者最终将异常抛给JVM

注意
假设利用return语句从try语句块中退出。在方法返回前finally子句的内容将被执行。如果finally子句中也有一个return语句,这个返回值将会覆盖原始的返回值。
public class Demo {
    public static int f(int n) {
        try {
            int r = n * n;
            return r;
        } finally {
            if (n == 2) return 0;
        }
    }
    public static void main(String[] args) {
        System.out.println(f(2));
    }
}

上述代码的输出为0,原来的r=4被覆盖了

问题扩展:

1、try{} 里有一个 return 语句,那么紧跟在这个 try 后的 finally{} 里的 code 会不会被执行,什么时候被执行,在 return 前还是后?

答案:会执行,在方法返回调用者前执行。

带资源的try语句(try-with-resources)的最简形式为:

try (Resource res = . . .) {
	work with res
}
public class Demo {
    public static void main(String[] args) {
        try(Scanner sc = new Scanner(new FileInputStream("src\\main\\java\\AnonymousInnerClassTest\\1.txt"),
        "UTF-8")) {
            while (sc.hasNext()) {
                System.out.println(sc.next());
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}