likes
comments
collection
share

Java 核心知识总结 异常

作者站长头像
站长
· 阅读数 27

Exception 和 Error 有什么区别?

Java将程序执行时可能发生的错误(Error)或异常(Exception),都封装成了类,作为java.lang.Throwable的子类,即Throwable是所有错误或异常的超类。Throwable类中定义了子类通用的方法,当错误或异常发生时,则会创建对应异常类型的对象并且抛出。

  • Exception:指其他因编程错误或偶然的外在因素导致的一般性问题,可以通过 catch 来进行捕获。Exception 又可以分为受检查异常和非受检查异常。
  • Error:指的是Java虚拟机无法解决的严重问题,一般不编写针对性的代码进行处理。例如 Java 虚拟机错误、内存溢出错误、栈内存溢出错误、无法找到某个类定义错误等 。这些异常发生时,Java 虚拟机一般会选择线程终止。

受检异常和非受检异常?

Java 核心知识总结 异常

在整个异常体系结构中,除了Error和RuntimeException及其子类属于非受检异常类型,剩下的都是受检异常类型,包括Throwable和Exception两个类型本身。无论是受检异常类型还是非受检异常类型,一旦发生异常又没有代码处理该异常,就会导致程序崩溃。

Java 代码在编译过程中,如果受检查异常没有被 catch 或者 throws 关键字处理的话,就没办法通过编译;不处理非受检查异常也可以正常通过编译。

Throwable 类的常用方法

Throwable类提供了如下一些构造器和方法。

  • Throwable( ):构造一个新的可抛出的异常对象,其详细信息此时为null。
  • Throwable(String message):构造一个具有指定详细信息的新异常对象。
  • Throwable(Throwable cause):构造一个具有指定原因的新异常,用于一个异常是由另一个异常引起的情况。
  • Throwable(String message, Throwable cause):构造一个具有指定详细信息和原因的新异常对象。
  • Throwable getCause( ):获取引起异常的原因。
  • String getMessage( ):获取异常的详细信息。
  • void printStackTrace( ):用标准错误的样式打印异常类型、描述信息及堆栈跟踪信息。

Throwable类的所有方法在各种异常和错误类型中都会被继承。通常情况下,异常对象的创建是由JVM来完成的,但是,如果需要,也可以手动创建异常对象,也可以调用相应的方法来获取和打印异常信息。

try-catch-finally 如何使用?

  • try块:用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
  • catch块:用于处理 try 捕获到的异常。
  • finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。

try-catch-finally,try里有return,finally还执行么?

  1. 当try和catch中有return时,finally仍然会执行,并且finally的执行早于try里面的return;

  2. return语句会把返回的值压进一个存储区里里等待返回给上层方法栈,而finally语句并不会修改这个区域里的值,而是修改当前栈帧里的局部变量,如果这个值是作为值传递的,就不会改变返回值,如果是引用传递,就会改变返回结果

    public static void main(String[] args) {
        System.out.println(testMethod()); // 1
        System.out.println(testMethod2()); // [1, 2]
    }
    
    public static int testMethod() {
        int i = 1;
        try {
            return i;
        } finally {
            i++;
            System.out.println(i); // 2
        }
    }
    
    public static List<Integer> testMethod2() {
        List<Integer> list = new ArrayList<>();
        try {
            list.add(1);
            return list;
        } finally {
            list.add(2);
        }
    }
    
  3. 当 try 语句和 finally 语句中都有 return 语句时,try 语句块中的 return 语句会被忽略。这是因为 try 语句中的 return 返回值会先被暂存在一个本地变量中,当执行到 finally 语句中的 return 之后,这个本地变量的值就变为了 finally 语句中的 return 返回值。因此不要在 finally 语句块中使用 return。

    public static void main(String[] args) {
        System.out.println(testMethod()); // 2
    }
    
    public static int testMethod() {
        try {
            return 1;
        } finally {
            return 2;
        }
    }
    

finally 中的代码一定会执行吗?

不一定。在某些情况下,finally 中的代码不会被执行:

  1. finally 之前虚拟机被终止运行
  2. 程序所在的线程死亡
  3. 关闭 CPU
try {
    System.out.println("Try to do something");
    throw new RuntimeException("RuntimeException");
} catch (Exception e) {
    System.out.println("Catch Exception -> " + e.getMessage());
    // 终止当前正在运行的Java虚拟机
    System.exit(1);
} finally {
    System.out.println("Finally");
}

// 输出:
// Try to do something
// Catch Exception -> RuntimeException

如何使用 try-with-resources 代替 try-catch-finally?

资源是指任何实现 java.lang.AutoCloseable 或者 java.io.Closeable 的对象。在try-with-resources中,我们可以在try关键字后的括号内声明一个或多个资源(多个资源用分号隔开),在try块结束时,这些资源会被自动关闭,无需显式调用close()方法,任何 catch 或 finally 块在声明的资源关闭后运行。面对必须要关闭的资源,我们应该优先使用 try-with-resources 而不是try-catch-finally。因为这样可以简化代码结构,提高可读性。

// try-catch-finally
Scanner scanner = null;
try {
    scanner = new Scanner(new File("test.txt"));
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (scanner != null) {
        scanner.close();
    }
}

// try-with-resources
try (Scanner scanner = new Scanner(new File("test.txt"))) {
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}
转载自:https://juejin.cn/post/7377561821220700160
评论
请登录