概念
-
如果某个方法不能按照正常的途径完成任务,就可以通过另一种路径退出方法。
-
在这种情况下会抛出一个封装了错误信息的对象。
-
此时这个方法会立刻退出同时不返回任何值。
-
调用这个方法的其他代码也无法继续执行,异常处理机制会将代码执行交给异常处理器。
Java异常类层次结构
-
Throwable 是 Java 语言中所有错误或异常的超类。
-
Error 类是指 java 运行时系统的内部错误和资源耗尽错误,应用程序不会抛出该类对象。
-
Exception(RuntimeException、CheckedException)又有两个分支:
-
RuntimeException:运行时异常,如 NullPointerException、ClassCastException。
-
CheckedException:检查异常,如 I/O 错误导致的 IOException、SQLException。
-
-
RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。
-
CheckedException 一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强制程序去捕获此类异常。
Error(错误)
-
Error(错误)是程序无法处理的错误,表示运行应用程序中较严重问题。
-
大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。
-
这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。
-
Error 表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时。
-
这些错误是不可查的,因为它们在应用程序的控制和处理能力之外。
-
对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。
-
在 Java 中,错误通过 Error 的子类描述。
-
例如
public class ErrorExample { public static void main(String[] args) { // 触发 StackOverflowError(Error 的子类) recursiveMethod(0); } // 无限递归导致栈溢出,触发 Error private static void recursiveMethod(int counter) { System.out.println("Counter: " + counter); recursiveMethod(counter + 1); // 无终止条件,最终抛出 StackOverflowError } }
Exception(异常)
-
Exception(异常)是程序本身可以处理的异常。
-
异常和错误的区别:异常能被程序本身处理,错误是无法处理。
-
Exception(RuntimeException、CheckedException)又有两个分支:RuntimeException 和 CheckedException。
-
RuntimeException 是可能在 Java 虚拟机正常运行期间抛出的异常的超类,如 NullPointerException、ClassCastException。
-
例如
public class RuntimeExceptionExample { public static void main(String[] args) { String str = null; try { System.out.println(str.length()); } catch (NullPointerException e) { System.out.println("Caught NullPointerException: " + e.getMessage()); } } }
-
CheckedException 一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强制程序去捕获此类异常,包括试图在文件尾部读取数据、试图打开一个错误格式的 URL、试图根据给定的字符串查找 class 对象,而这个字符串表示的类并不存在等。
-
例如
import java.io.File; import java.io.FileReader; import java.io.IOException; public class CheckedExceptionExample { public static void main(String[] args) { File file = new File("nonexistent.txt"); try { FileReader fr = new FileReader(file); } catch (IOException e) { System.out.println("Caught IOException: " + e.getMessage()); } } }
Throwable 类常用方法
-
Throwable 类常用方法:
-
getMessage():返回异常发生时的详细信息。
-
toString():返回异常发生时的简要描述。
-
getLocalizedMessage():返回异常对象的本地化信息。使用 Throwable 的子类覆盖这个方法,可以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()返回的结果相同。
-
printStackTrace():在控制台上打印 Throwable 对象封装的异常信息。
-
异常处理总结
-
try 块:用于捕获异常,可以接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
-
catch 块:用于处理 try 块捕获到的异常。
-
finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。
-
当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。
-
特殊情况下,finally 块可能不会被执行:
-
在 finally 语句块中发生了异常。
-
在前面的代码中使用了 System.exit() 退出程序。
-
程序所在的线程死亡。
-
关闭 CPU(该情况不太可能发生)。
-
-
例如:
try-catch-finally 基本结构
try { // 可能抛出异常的代码 int result = 10 / 0; } catch (ArithmeticException e) { // 处理特定异常 System.out.println("捕获到算术异常: " + e.getMessage()); } finally { // 无论是否发生异常都会执行 System.out.println("finally 块执行"); }
多个 catch 块
try { String str = null; System.out.println(str.length()); } catch (NullPointerException e) { System.out.println("空指针异常: " + e); } catch (Exception e) { System.out.println("通用异常处理: " + e); }
try-finally 结构
try { // 没有 catch 块 System.out.println("try 块执行"); } finally { System.out.println("finally 块执行"); }
return 与 finally 的执行顺序
public static int testFinally() { try { return 1; } finally { System.out.println("即使有 return,finally 也会执行"); } }
finally 不被执行的情况
try { System.exit(0); // 程序退出,finally 不会执行 } finally { System.out.println("这段代码不会执行"); }
Throw和Throws的区别
-
位置不同:
-
throws 用在函数上,后面跟的是异常类,可以跟多个
-
public class ThrowsExample { // 在方法签名中使用throws声明可能抛出的异常类型 public static void readFile() throws FileNotFoundException { File file = new File("nonexistent.txt"); FileInputStream fis = new FileInputStream(file); // 可能抛出FileNotFoundException } public static void main(String[] args) { try { readFile(); // 调用者需处理声明的异常 } catch (FileNotFoundException e) { System.out.println("文件未找到: " + e.getMessage()); } } }
-
而 throw 用在函数内,后面跟的是异常对象。
-
public class ThrowExample { public static void checkAge(int age) { if (age < 18) { // 在方法体内使用throw抛出具体异常对象 throw new ArithmeticException("年龄未满18岁"); // 抛出运行时异常 } System.out.println("允许访问"); } public static void main(String[] args) { try { checkAge(15); // 抛出异常后,后续代码不会执行 } catch (ArithmeticException e) { System.out.println("捕获异常: " + e.getMessage()); } } }
-
-
功能不同:
-
throws 用来声明异常,让调用者只知道该功能可能出现的问题,可以给出预先的处理方式;throw 抛出具体的问题对象,执行到 throw,功能就已经结束了,跳转到调用者,并将具体的问题对象抛给调用者。也就是说 throw 语句独立存在时,下面不要定义其他语句,因为执行不到。
-
throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw 则是抛出了异常,执行 throw 则一定抛出了某种异常对象。
-
-
两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。