一、异常的概念总结
-
异常的定义:
- 在Java语言中,异常指的是程序运行过程中遇到的意外情况,例如错误的输入、网络断开、文件不存在等。处理这些异常情况称为异常处理。
-
Throwable类:
- 所有异常和错误都继承自
Throwable
类。它是 Java 异常体系的根类。
- 所有异常和错误都继承自
-
Throwable的两大分支:
- Error:代表严重的错误,通常由系统和虚拟机发出,程序无法恢复,比如内存溢出、虚拟机错误等。
- Exception:代表程序运行中的异常情况,分为运行时异常和检查时异常。
-
异常的处理:
- 运行时异常(RuntimeException):编译时可以不强制处理,通常由程序员的逻辑错误引起,如空指针异常(NullPointerException)、数组越界异常(ArrayIndexOutOfBoundsException)、算术异常(ArithmeticException)等。
- 检查时异常(Checked Exception):编译时必须处理或声明抛出,如文件找不到(FileNotFoundException)、IO异常(IOException)、数据库异常(SQLException)等。
-
异常处理的应用:
- 对于运行时异常,程序员可以选择处理或不处理,但建议进行逻辑判断避免异常发生。
- 对于检查时异常,必须在编译时处理或声明抛出,确保程序在可能发生异常的情况下有所准备。
-
示例说明:
public class ExceptionHandlingExample {
public static void main(String[] args) {
try {
int[] array = new int[3];
System.out.println(array[4]); // 可能抛出 ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常:" + e.getMessage());
}
try {
FileReader file = new FileReader("file.txt"); // 可能抛出 FileNotFoundException
} catch (FileNotFoundException e) {
System.out.println("文件未找到异常:" + e.getMessage());
}
}
}
在上面的示例中,第一个 try-catch
块处理了数组越界异常,第二个 try-catch
块处理了文件未找到异常。这展示了如何针对不同类型的异常进行处理,以确保程序的健壮性和稳定性。
这些总结可以帮助程序员更好地理解和应用异常处理机制,在开发过程中有效地预防和处理各种异常情况。
1. 继承关系
在Java中,异常处理体系主要分为两大类:Error
和Exception
。下面给出了你列出的异常类的继承关系:
Throwable
├── Error
│ ├── AssertionError
│ ├── OutOfMemoryError
│ ├── IOError
│ └── VirtualMachineError
│ ├── StackOverflowError
│ └── ... (其他虚拟机相关错误)
└── Exception
├── RuntimeException
│ ├── NullPointerException
│ ├── IndexOutOfBoundsException
│ │ ├── ArrayIndexOutOfBoundsException
│ │ └── StringIndexOutOfBoundsException
│ ├── IllegalArgumentException
│ ├── IllegalStateException
│ ├── UnsupportedOperationException
│ └── ... (其他运行时异常)
└── IOException
├── FileNotFoundException
├── EOFException
└── ... (其他IO异常)
-
Error 类及其子类:
Error
OutOfMemoryError
:当JVM无法分配更多内存时抛出。VirtualMachineError
:指示JVM遇到了严重错误,可能需要终止。LinkageError
:子类,当类或方法在链接阶段出现问题时抛出。NoClassDefFoundError
:当类在初始化时找不到其依赖的类的定义时抛出。IncompatibleClassChangeError
:当一个类的静态类型和动态类型不兼容时抛出。UnsatisfiedLinkError
:当尝试加载一个不存在或不可访问的本地库时抛出。
ThreadDeath
:当线程结束时抛出。StackOverflowError
:当程序栈溢出时抛出。IOException
:实际上不是Error
的子类,而是Exception
的子类。
-
Exception 类及其子类:
Exception
RuntimeException
:在运行时抛出的异常,通常是由编程错误引起的。NullPointerException
:当应用试图使用null引用时抛出。ArrayStoreException
:当试图向数组中存储不兼容类型的对象时抛出。ClassCastException
:当应用试图将对象强制转换为不兼容的类型时抛出。IllegalArgumentException
:当方法接收到非法参数时抛出。IllegalStateException
:当方法处于不适当的调用状态时抛出。UnsupportedOperationException
:当方法不支持请求的操作时抛出。IndexOutOfBoundsException
:当索引超出数组范围时抛出。ArithmeticException
:当算术运算遇到异常条件时抛出。NumberFormatException
:当字符串不能解析为数字时抛出。StringIndexOutOfBoundsException
:当索引超出字符串范围时抛出。ConcurrentModificationException
:当多线程修改集合时抛出。SecurityException
:当安全策略被违反时抛出。NegativeArraySizeException
:当数组大小为负数时抛出。AssertionError
:当断言失败时抛出。
IOException
:当输入/输出操作中发生问题时抛出。FileNotFoundException
:当尝试读取不存在的文件时抛出。EOFException
:当达到流的末尾但仍有数据需要读取时抛出。
DOMException
:在处理XML文档时抛出。XMLStreamException
:在处理XML流时抛出。SAXException
:在使用SAX解析XML时抛出。ObjectStreamException
:在序列化或反序列化对象时抛出。
Throwable
是所有异常和错误的顶级父类,它有两个直接子类:Error
和 Exception
。Exception
又分为 RuntimeException
和 CheckedException
(例如 IOException
),其中 RuntimeException
不需要在方法签名中声明,而 CheckedException
需要在调用的方法中显式捕获或声明抛出。
注意,Error
类通常表示JVM或系统级别的错误,不应该被程序捕获或处理,而应该让程序终止;Exception
类表示程序可以处理或恢复的异常情况。
2. 解释继承关系
-
Throwable:
- Java中所有异常和错误的根类。
-
Error:
- 表示严重的错误,一般由虚拟机抛出,程序无法处理。常见的有
AssertionError
,OutOfMemoryError
,StackOverflowError
等。
- 表示严重的错误,一般由虚拟机抛出,程序无法处理。常见的有
-
Exception:
- 可由程序员处理的异常类。
-
RuntimeException:
- 运行时异常,编译器不会强制要求处理的异常。常见的有
NullPointerException
,IndexOutOfBoundsException
,IllegalArgumentException
等。
- 运行时异常,编译器不会强制要求处理的异常。常见的有
-
IOException:
- 输入输出异常,通常用于处理文件操作等可能出现的异常。
在继承关系中,每个异常类都继承自更具体的异常或错误类,这种继承关系使得异常处理更加灵活和结构化。
二、异常的处理
异常处理在Java中通过 try
, catch
, finally
, throw
, throws
等关键字实现,下面对它们进行简要总结:
-
try-catch-finally:
- try:包裹可能会抛出异常的代码块。
- catch:捕获并处理 try 块中抛出的异常。
- finally:不论是否发生异常,都会执行的代码块,通常用于资源释放或清理操作。
-
throw:
- throw:用于手动抛出异常对象,指定异常发生的具体情况。
-
throws:
- throws:用于在方法声明中标识可能抛出的异常类型,告知调用方需要处理或继续抛出这些异常。
示例说明:
public class ExceptionHandlingExample {
// 方法示例,声明可能抛出异常
public static void method1() throws IOException {
// 可能抛出 IOException 的代码
FileReader fr = new FileReader("file.txt");
// 其他操作
}
// 方法示例,使用 try-catch-finally 处理异常
public static void method2() {
try {
// 执行可能产生异常的代码
int result = 10 / 0; // 会抛出 ArithmeticException
} catch (ArithmeticException e) {
// 捕获并处理异常
System.out.println("除数不能为0:" + e.getMessage());
} finally {
// 无论是否发生异常,总能执行的代码块
System.out.println("finally 块总是执行");
}
}
// 方法示例,手动抛出异常
public static void method3(int value) {
if (value < 0) {
// 手动抛出异常
throw new IllegalArgumentException("参数不能为负数");
} else {
System.out.println("参数值:" + value);
}
}
public static void main(String[] args) {
try {
method1(); // 调用可能抛出 IOException 的方法,需要处理异常或声明抛出
} catch (IOException e) {
System.out.println("处理 IOException:" + e.getMessage());
}
method2(); // 调用带有 try-catch-finally 的方法
try {
method3(-1); // 调用可能抛出 IllegalArgumentException 的方法,捕获并处理异常
} catch (IllegalArgumentException e) {
System.out.println("处理 IllegalArgumentException:" + e.getMessage());
}
}
}
1. try代码块
将可能产生异常的代码放入try代码块中,可以由catch捕获。
try {
// 可能会抛出异常的代码块
} catch (异常类 异常对象) {
// 异常处理代码
}
2. catch代码块
catch代码块用于捕获try中可能会抛出的异常,可以有多个catch块,按照异常类型从小到大顺序捕获。
try {
// 可能会抛出异常的代码块
} catch (ArithmeticException ae) {
// 算术异常处理
} catch (ArrayIndexOutOfBoundsException ae) {
// 数组越界异常处理
} catch (Exception e) {
// 其他异常处理
}
3. finally代码块
finally代码块不管try语句块是否产生异常,都会在try与catch语句块后执行。
try {
int[] i = new int[5];
System.out.println(i[5]); // 有可能出现异常的代码,访问数组索引越界
System.out.println(a / b); // 有可能出现异常的代码,除法运算可能除数为0
System.out.println(s.length()); // 有可能出现异常的代码,访问字符串长度
} catch (ArithmeticException ae) {
System.out.println("对不起,出现了算术异常,有可能除数是0");
JOptionPane.showMessageDialog(null, "除数不能为0");
} catch (ArrayIndexOutOfBoundsException ae) {
JOptionPane.showMessageDialog(null, "数组下标越界");
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "出现问题");
} finally {
//最终必须执行的代码块
System.out.println("finally语句块...");
}
4. throw手动抛出异常
使用throw语句可以手动抛出异常,通常用于在特定条件下抛出自定义异常。
class PowerNotEnoughException extends Exception
{
//String message ="权限不足!"
public PowerNotEnoughException(){
//调用父类Exception的构造方法
super("权限不足!");
}
}
public class TestException2 {
public static void main(String[] args) {
String adminName = "张三1";
try {
if ("张三".equals(adminName)) {
System.out.println("管理员登录");
} else {
// 手动抛出异常,自定义异常
throw new PowerNotEnoughException("权限不足!");
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
5. throws在方法中声明异常
使用throws关键字在方法声明中指定可能抛出的异常,调用该方法时要求处理或继续抛出。
class A {
public void printName() throws Exception {
// 方法体可能抛出异常
}
}
class B {
public void p() throws Exception {
A a = new A();
a.printName(); // 调用方法时要求处理异常
}
public static void main(String[] args) {
B b = new B();
try {
b.p();
} catch (Exception e) {
System.out.println("处理异常:" + e.getMessage());
}
}
}
6. finally与return语句
在方法中使用return语句时,先执行finally块再返回值
public class TestF {
public static int getValue(){
int i = 0;
try{
i = 10;
//if(i >= 10) throw new Exception("ccc");
return i;//在执行return语句时先检查有没有finally,假如没有直接return返回,
//有的话先把return 10;压入栈中再执行finally,执行完毕,再把return语句出栈执行
}catch(Exception e){
}finally{
i = 20;
System.out.println("finally");
}
return i;//必须保证该方法一定要有返回值
}
public static void main(String[] args){
System.out.println(getValue());
}
---------- 输出结果 ----------
finally
10
输出完成 (耗时 0 秒) - 正常终止
三、总结异常处理需要注意的地方
1. try、catch、finally结构
- try语句不能单独存在,必须与catch、finally组合使用,形成以下三种结构之一:
- try…catch…finally
- try…catch
- try…finally
- catch语句可以有一个或多个,用于捕获不同类型的异常。
- finally语句最多一个,用于无论是否发生异常都必须执行的情况。
2. 变量作用域
- try、catch、finally三个代码块中的变量作用域独立,彼此不能直接访问。如果需要在三个块中都访问同一变量,需要将其定义在这些块的外部。
3. 多个catch块
- 当多个catch块存在时,Java虚拟机会匹配其中一个异常类或其子类,只执行第一个匹配的catch块,而忽略其余的catch块。
4. throw后紧跟语句
- throw语句后不能紧跟其他语句,因为在throw语句后抛出异常,紧跟的语句不会执行。
示例代码:
try {
i = 10;
throw new Exception("ccc");
return i; // 编译器报错,无法执行到此处的return语句
} catch (Exception e) {
// 异常处理代码
}
这些注意事项能帮助开发者更好地理解和使用Java中的异常处理机制,确保程序在面对异常情况时能够正确、可控地处理。