【Java异常】面试官问你Java中的异常,这篇就够了
文章目录
- 1. 什么是Java异常?
- 2. Java异常层次结构
- 3. 常见Java异常类型及处理方法(面试常问)
- 3.1 NullPointerException(空指针异常)
- 3.2 IndexOutOfBoundsException(数组索引越界异常)
- 3.3 ClassNotFoundException(类未找到异常)
- 3.4 NumberFormatException(数字格式异常)
- 3.5 IllegalArgumentException(非法参数异常)
- 3.6 ClassCastException(类转换异常)
- 3.7 FileNotFoundException(文件未找到异常)
- 3.8 NoSuchMethodException(方法不存在异常)
- 4. 异常处理技巧
- 4.1 使用try-catch块
- 4.2 使用finally块
- 4.3 使用try-with-resources语句
- 4.4 多重catch块
- 5. 异常处理最佳实践
1. 什么是Java异常?
Java异常是在程序执行过程中发生的异常事件,它会中断程序的正常流程。异常可以是由于用户输入错误、硬件故障、网络问题等各种原因引起的。Java使用异常处理机制来处理这些运行时错误,使得程序能够更加健壮和可靠。
2. Java异常层次结构
Java的所有异常都是java.lang.Throwable
类的子类。Throwable有两个直接子类:Error
和Exception
。
- Error:表示严重的问题,通常是不可恢复的。例如
OutOfMemoryError
。 - Exception:表示可以被程序处理的问题。又分为两类:
- 检查型异常(Checked Exceptions):必须在代码中显式处理或声明抛出。
- 非检查型异常(Unchecked Exceptions):运行时异常,不需要显式处理。
3. 常见Java异常类型及处理方法(面试常问)
3.1 NullPointerException(空指针异常)
这可能是Java中最常见的异常之一。当试图使用一个值为null的对象引用时,就会抛出这个异常。
示例:
String str = null;
System.out.println(str.length()); // 抛出NullPointerException
防范措施:
- 在使用对象之前进行null检查
- 使用Java 8引入的Optional类来处理可能为null的值
3.2 IndexOutOfBoundsException(数组索引越界异常)
当试图访问数组中不存在的索引时,会抛出此异常。
示例:
int[] arr = new int[5];
System.out.println(arr[5]); // 抛出ArrayIndexOutOfBoundsException
防范措施:
- 在访问数组元素前检查索引是否有效
- 使用集合类(如ArrayList)代替数组,它们提供了更安全的操作方法
3.3 ClassNotFoundException(类未找到异常)
当试图加载类,但找不到相应的类定义时,就会抛出这个异常。
示例:
Class.forName("com.example.NonExistentClass"); // 抛出ClassNotFoundException
防范措施:
- 仔细检查类名的拼写
- 确保类路径(classpath)设置正确
3.4 NumberFormatException(数字格式异常)
当试图将一个字符串转换为数字,但该字符串不能表示一个有效的数字时,会抛出此异常。
示例:
int num = Integer.parseInt("123abc"); // 抛出NumberFormatException
防范措施:
- 在转换之前验证字符串的格式
- 使用正则表达式检查字符串是否只包含数字
3.5 IllegalArgumentException(非法参数异常)
当方法接收到一个不适当的参数时,会抛出这个异常。
示例:
public void setAge(int age) {if (age < 0) {throw new IllegalArgumentException("Age cannot be negative");}this.age = age;
}
防范措施:
- 在方法开始处验证参数的有效性
- 为公共API提供清晰的文档,说明参数的有效范围
3.6 ClassCastException(类转换异常)
当试图将对象强制转换为不是其子类型的类时,会抛出ClassCastException。这是一个运行时异常,通常由于程序逻辑错误导致。
示例:
Object obj = new Integer(123);
String str = (String) obj; // 抛出ClassCastException
防范措施:
- 在进行类型转换之前,使用instanceof运算符检查对象的实际类型
- 使用泛型来避免不必要的类型转换
3.7 FileNotFoundException(文件未找到异常)
当试图访问一个不存在的文件时,会抛出FileNotFoundException。这是一个检查型异常,需要显式处理。
示例:
try {FileInputStream fis = new FileInputStream("nonexistent.txt");
} catch (FileNotFoundException e) {System.out.println("File not found: " + e.getMessage());
}
防范措施:
- 在访问文件之前,使用File类的exists()方法检查文件是否存在
- 使用相对路径时,确保路径是相对于正确的基础目录
- 在处理文件操作时,始终使用try-catch块或throws声明
3.8 NoSuchMethodException(方法不存在异常)
当试图通过反射调用一个不存在的方法时,会抛出NoSuchMethodException。这是一个检查型异常。
示例:
try {Class<?> cls = Class.forName("java.lang.String");Method method = cls.getMethod("nonexistentMethod");
} catch (NoSuchMethodException e) {System.out.println("Method not found: " + e.getMessage());
} catch (ClassNotFoundException e) {System.out.println("Class not found: " + e.getMessage());
}
防范措施:
- 在使用反射调用方法之前,仔细检查方法名称和参数类型
- 如果可能,优先使用编译时检查而不是反射
- 在使用反射时,总是捕获并适当处理NoSuchMethodException
4. 异常处理技巧
4.1 使用try-catch块
try-catch是Java中处理异常的基本方式。将可能抛出异常的代码放在try块中,然后在catch块中处理异常。
try {// 可能抛出异常的代码
} catch (ExceptionType e) {// 异常处理代码
}
4.2 使用finally块
finally块中的代码无论是否发生异常都会执行,通常用于资源清理。
try {// 可能抛出异常的代码
} catch (Exception e) {// 异常处理代码
} finally {// 清理代码,总是执行
}
4.3 使用try-with-resources语句
Java 7引入的try-with-resources语句可以自动关闭实现了AutoCloseable接口的资源。
try (BufferedReader br = new BufferedReader(new FileReader(path))) {return br.readLine();
} catch (IOException e) {// 异常处理
}
4.4 多重catch块
可以使用多个catch块来处理不同类型的异常。
try {// 可能抛出多种异常的代码
} catch (IOException e) {// 处理IO异常
} catch (SQLException e) {// 处理SQL异常
} catch (Exception e) {// 处理其他类型的异常
}
5. 异常处理最佳实践
-
不要捕获顶层异常: 避免直接捕获Exception或Throwable,而应该捕获具体的异常类型。
-
不要忽视异常: 始终在catch块中至少记录异常信息,不要使用空的catch块。
-
及时释放资源: 使用try-with-resources或在finally块中释放资源。
-
抛出有意义的异常: 当抛出异常时,提供有意义的错误消息和相关的上下文信息。
-
使用自定义异常: 为特定的业务逻辑错误创建自定义异常类,以提高代码的可读性。
-
合理使用checked和unchecked异常: 对于调用者应该处理的错误使用checked异常,对于程序错误使用unchecked异常。
-
记录异常: 使用日志框架(如Log4j或SLF4J)来记录异常,而不是简单地打印到控制台。