异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。
错误描述:当试图访问一个空引用对象的属性或调用空引用对象的方法时,会抛出NullPointer异常。
复现示例:
String str = null;
System.out.println(str.length());
解决方案:在使用对象之前,确保对象不为null。可以通过添加null检查或使用条件语句来避免该错误。
if (str != null) {
System.out.println(str.length());
}
错误描述:当试图将一个对象强制转换为与其实际类型不兼容的类型时,会抛出ClassCastException异常。
复现示例:
Object obj = “Java”;
Integer num = (Integer) obj;
解决方案:在进行类型转换前,先使用instanceof运算符进行类型检查,确保对象可以成功转换。或者使用合适的类型转换操作来避免该错误。
if (obj instanceof Integer) {
Integer num = (Integer) obj;
// 进一步处理
}
错误描述:当试图访问数组中超出有效索引范围的位置时,会抛出ArrayIndexOutOfBoundsException异常。
复现示例:
int[] arr = {1, 2, 3};
int element = arr[3];
解决方案:确保访问数组时,索引值在有效范围内。要注意Java数组的索引从0开始,因此最大索引是数组长度减1。
if (index >= 0 && index < arr.length) {
int element = arr[index];
// 进一步处理
}
错误描述:当进行整数除法或取模运算时,除数为零会抛出ArithmeticException异常。
复现示例:
int a = 5;
int b = 0;
int result = a / b;
解决方案:在进行除法或取模运算时,要确保除数不为零,可以使用条件语句预先检查除数是否为零。
if (b != 0) {
int result = a / b;
// 进一步处理
}
错误描述:在处理输入输出操作时,如果出现读取或写入失败、文件不存在或无法访问等情况,会抛出IOException异常。
复现示例:
FileReader reader = new FileReader(“path/to/nonexistent-file.txt”);
int data = reader.read();
解决方案:在进行输入输出操作时,要确保文件存在、路径正确、权限足够,并且进行异常处理,例如使用try-catch块捕获和处理IOException异常。
try {
FileReader reader = new FileReader(“path/to/existing-file.txt”);
int data = reader.read();
// 进一步处理
} catch (IOException e) {
e.printStackTrace();
}
错误描述:当试图加载某个类,但找不到该类时,会抛出ClassNotFoundException异常。
复现示例:
try {
Class.forName(“com.example.NonExistentClass”);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
解决方案:确保引用的类存在于正确的位置,并且类路径设置正确。如果使用外部库或框架,确保将相关的jar文件添加到类路径中。
错误描述:当在进行迭代操作时,试图并发修改集合(如ArrayList)的结构时,会抛出ConcurrentModificationException异常。
复现示例:
List list = new ArrayList<>();
list.add(“Java”);
for (String item : list) {
if (item.equals(“Java”)) {
list.remove(item);
}
}
解决方案:避免在迭代时修改集合的结构。可以使用Iterator进行迭代,并使用Iterator的remove()方法删除元素,或者创建一个临时副本进行修改操作。
List list = new ArrayList<>();
list.add(“Java”);
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (item.equals(“Java”)) {
iterator.remove();
}
}
解决方案:避免在迭代时修改集合的结构。可以使用Iterator进行迭代,并使用Iterator的remove()方法删除元素,或者创建一个临时副本进行修改操作。
List list = new ArrayList<>();
list.add(“Java”);
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (item.equals(“Java”)) {
iterator.remove();
}
}
错误描述:当方法调用的嵌套层级过深,导致栈空间耗尽时,会抛出StackOverflowError错误。
复现示例:
public static void recursiveMethod() {
recursiveMethod();
}
public static void main(String[] args) {
recursiveMethod();
}
解决方案:确保递归方法具有退出条件,避免无限递归调用。每次递归调用时,问题规模应该减小,直到达到退出条件。
public static void recursiveMethod(int n) {
if (n <= 0) {
return;
}
// 进行递归操作
recursiveMethod(n - 1);
}
错误描述:在使用JSON库(如Jackson)反序列化时,如果JSON数据与目标类型不匹配,会抛出MismatchedInputException异常。
复现示例:
ObjectMapper mapper = new ObjectMapper();
String json = “{“username”: “Alice”, “age”: 25}”;
MyPojo pojo = mapper.readValue(json, MyPojo.class);
解决方案:确保JSON数据与目标类型匹配,包括字段名称和数据类型。可以使用@JsonProperty注解或自定义反序列化器来处理不匹配的字段。
public class MyPojo {
@JsonProperty(“username”)
private String username;
// 其他字段和getter/setter
}
错误描述:当尝试将字符串解析为日期或时间时,如果字符串格式与指定的格式不匹配,会抛出DateTimeParseException异常。
复现示例:
String dateStr = “2023-07-20”;
LocalDate date = LocalDate.parse(dateStr);
解决方案:确保提供的字符串符合指定的日期或时间格式。可以使用DateTimeFormatter指定解析格式,并使用try-catch块来捕获并处理解析异常。
String dateStr = “2023-07-20”;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(“yyyy-MM-dd”);
try {
LocalDate date = LocalDate.parse(dateStr, formatter);
// 进一步处理
} catch (DateTimeParseException e) {
e.printStackTrace();
}
错误描述:当尝试将一个无法转换为数字的字符串转换为数字类型时,会抛出NumberFormatException异常。
复现示例:
String numberStr = “ABC123”;
int number = Integer.parseInt(numberStr);
解决方案:在进行字符串转换为数字的操作之前,确保字符串仅包含有效的数字字符。可以使用正则表达式或合适的校验方法来验证字符串是否为有效的数字。
String numberStr = “123”;
if (numberStr.matches(“\d+”)) {
int number = Integer.parseInt(numberStr);
// 进一步处理
}
错误描述:当对象无法被垃圾回收机制回收,长时间驻留在内存中,导致内存泄漏时,会出现性能下降甚至内存溢出等问题。
复现示例:
public static List list = new ArrayList<>();
public static void main(String[] args) {
while (true) {
Object obj = new Object();