Java 核心知识总结 异常
Exception 和 Error 有什么区别?
Java将程序执行时可能发生的错误(Error)或异常(Exception),都封装成了类,作为java.lang.Throwable的子类,即Throwable是所有错误或异常的超类。Throwable类中定义了子类通用的方法,当错误或异常发生时,则会创建对应异常类型的对象并且抛出。
- Exception:指其他因编程错误或偶然的外在因素导致的一般性问题,可以通过 catch 来进行捕获。Exception 又可以分为受检查异常和非受检查异常。
- Error:指的是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还执行么?
-
当try和catch中有return时,finally仍然会执行,并且finally的执行早于try里面的return;
-
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); } }
-
当 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 中的代码不会被执行:
- finally 之前虚拟机被终止运行
- 程序所在的线程死亡
- 关闭 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