JavaSE基础-Java异常处理全解析:从ClassNotFound到IndexOutOfBounds

目录

[1. ClassNotFoundException(类找不到异常)](#1. ClassNotFoundException(类找不到异常))

什么时候发生?

如何解决?

[2. CloneNotSupportedException(克隆不支持异常)](#2. CloneNotSupportedException(克隆不支持异常))

什么时候发生?

如何解决?

三、对比总结

[1. EOFException(End Of File Exception)](#1. EOFException(End Of File Exception))

触发场景

解决方式

[2. FileNotFoundException(文件找不到)](#2. FileNotFoundException(文件找不到))

触发场景

解决方式

[3. MalformedURLException(URL 格式错误)](#3. MalformedURLException(URL 格式错误))

触发场景

解决方式

[4. UnknownHostException(未知主机)](#4. UnknownHostException(未知主机))

触发场景

解决方式

总结对比

[1. ArithmeticException(算术异常)](#1. ArithmeticException(算术异常))

[2. ClassCastException(类型强转异常)](#2. ClassCastException(类型强转异常))

[3. IllegalArgumentException(非法参数异常)](#3. IllegalArgumentException(非法参数异常))

[4. IllegalStateException(非法状态异常)](#4. IllegalStateException(非法状态异常))

[5. IndexOutOfBoundsException(索引越界异常)](#5. IndexOutOfBoundsException(索引越界异常))

[6. NoSuchElementException(无此元素异常)](#6. NoSuchElementException(无此元素异常))

[7. NullPointerException(空指针异常)](#7. NullPointerException(空指针异常))

总结速查表



这两个都是编译时异常(Checked Exception),但触发场景完全不同:

1. ClassNotFoundException(类找不到异常)

通俗解释 :JVM 像图书管理员,你要找一本叫 com.example.User 的书(类),但它在书库(classpath)里查无此人

什么时候发生?

当你用反射类加载器动态加载类,但类路径(classpath)中不存在该类时。

java 复制代码
// 典型场景 1:JDBC 旧版驱动加载(最常见)
Class.forName("com.mysql.jdbc.Driver");  
// 如果 mysql-connector-java.jar 没导入,编译通过,运行时报 ClassNotFoundException

// 典型场景 2:拼写错误
Class.forName("java.utl.Date");  // 应该是 java.util.Date,拼错就找不到

// 典型场景 3:动态加载插件/配置文件中的类名
String className = props.getProperty("implClass");  // 从配置读类名
Class<?> clazz = Class.forName(className);          // 类名配错了或 jar 包丢了

如何解决?

  1. 检查类名拼写 (大小写敏感,Useruser 不同)

  2. 检查依赖包:确保需要的 jar 包已添加到项目(Maven/Gradle 依赖)

  3. 检查类路径 :运行时 -cp-classpath 参数是否包含该类

  4. 检查类加载器:如果是 Web 项目(Tomcat),可能是不同 ClassLoader 导致隔离

2. CloneNotSupportedException(克隆不支持异常)

通俗解释:你想复印一份文件(clone),但该文件贴了封条**"禁止复印"**(未实现 Cloneable 接口),复印机直接拒绝并报警。

什么时候发生?

当你调用 Object.clone() 方法,但对象的类没有实现 Cloneable 接口时。

java 复制代码
public class Person {  // 注意:没有 implements Cloneable
    String name;
}

Person p = new Person();
Person p2 = p.clone();  // ❌ 编译不报错,运行抛 CloneNotSupportedException

为什么需要 Cloneable?

  • Cloneable 是一个标记接口(Marker Interface),里面没有任何方法

  • 它就像"克隆许可证",告诉 JVM:"这个类允许被克隆"

  • 没有许可证就调用 clone(),就是非法操作

如何解决?

方式 1:实现 Cloneable 接口(标准做法)

java 复制代码
public class Person implements Cloneable {  // 办证
    String name;
    
    @Override
    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();  // 现在可以合法调用了
    }
}

方式 2:改用其他拷贝方式(更推荐)

java 复制代码
// 拷贝构造器(避免 clone 的诸多坑)
public Person(Person other) {
    this.name = other.name;
}
Person p2 = new Person(p1);  // 更现代、更安全的做法

三、对比总结

|--------------------------------|-----------------------------------|----------------------------|------------------|
| 异常 | 触发动作 | 根本原因 | 解决关键 |
| ClassNotFoundException | Class.forName() / loadClass() | 外部环境:类文件缺失、拼写错误、依赖未导入 | 检查 classpath 和依赖 |
| CloneNotSupportedException | Object.clone() | 代码设计:类未实现 Cloneable 接口 | 实现接口或改用拷贝构造器 |

一句话记忆

  • ClassNotFoundException = "查无此人"(你要的类不存在)

  • CloneNotSupportedException = "无证克隆"(类不允许被复制)


这4个都是 IOException 的子类 (编译时异常),专用于文件/网络 IO 操作出错场景。

1. EOFException(End Of File Exception)

人话读到文件末尾了还不收手,继续读就会抛这个异常。

触发场景

java 复制代码
// 用 DataInputStream 读文件,文件只有10个字节,但你要读100个
DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"));
while (true) {
    int data = dis.readInt();  // 读到末尾还读,抛 EOFException
}

解决方式

java 复制代码
// 正确做法:先判断有没有可读内容
while (dis.available() > 0) {  // 检查剩余字节数
    int data = dis.readInt();
}
// 或捕获异常作为结束信号(不推荐作为流程控制)

2. FileNotFoundException(文件找不到)

人话指定路径的文件不存在,或者路径是目录而不是文件。

触发场景

java 复制代码
// 场景1:文件确实不存在
FileReader fr = new FileReader("不存在的文件.txt");

// 场景2:路径是目录而非文件
FileReader fr = new FileReader("/usr/local");  // 这是个目录!

解决方式

java 复制代码
File file = new File("data.txt");
if (file.exists() && file.isFile()) {  // 先检查存在且是文件
    FileReader fr = new FileReader(file);
} else {
    System.out.println("文件不存在或路径是目录");
}

3. MalformedURLException(URL 格式错误)

人话网址写错了格式,不符合 URL 规范(如缺少协议、非法字符等)。

触发场景

java 复制代码
// 场景1:协议写错或缺失
URL url = new URL("htp://[www.baidu.com](https://www.baidu.com)");  // 应该是 http

// 场景2:包含非法字符
URL url = new URL("[http://www.baidu.com/中](http://www.baidu.com/中) 文");  // 空格未编码

解决方式

java 复制代码
// 使用 URLEncoder 编码特殊字符
String encoded = URLEncoder.encode("中文路径", "UTF-8");
URL url = new URL("[http://www.baidu.com/](http://www.baidu.com/)" + encoded);

4. UnknownHostException(未知主机)

人话域名解析失败,DNS 找不到这个域名对应的 IP 地址。

触发场景

java 复制代码
// 场景1:拼写错误的域名
Socket socket = new Socket("wwww.baidu.com", 80);  // 多打了个 w

// 场景2:断网/ DNS 故障
URL url = new URL("[http://www.google.com](http://www.google.com)");
URLConnection conn = url.openConnection();  // 没网时抛此异常

解决方式

java 复制代码
// 检查网络连接,或做降级处理
try {
    InetAddress address = InetAddress.getByName("[www.baidu.com](https://www.baidu.com)");
} catch (UnknownHostException e) {
    System.out.println("网络不通或域名错误,请检查网络设置");
    // 使用本地缓存或默认IP兜底
}

总结对比

|---------------------------|----------------------------------------|-------------------------|---------------------------------|
| 异常 | 触发动作 | 核心原因 | 解决关键 |
| EOFException | readInt() / readUTF() 等 | 读过头了,文件已读完还继续读 | 用 available() 检查或正确判断流结束 |
| FileNotFoundException | new FileReader() / FileInputStream | 文件不存在 或路径是目录 | 检查 file.exists()isFile() |
| MalformedURLException | new URL() | 网址格式非法(协议错、特殊字符未编码) | 检查协议,用 URLEncoder 编码 |
| UnknownHostException | Socket / URL.openConnection() | 域名解析失败(拼错/DNS故障/断网) | 检查域名拼写,处理网络不通情况 |

一句话记忆

  • EOF = E nd O f File(读到头了)

  • FileNotFound = 文件"查无此文件"

  • MalformedURL = URL" malformed"(畸形/格式错误)

  • UnknownHost = 主机" unknown"(找不到IP)



这些都是 RuntimeException 的子类(运行时异常),代表代码逻辑错误,可通过严谨编码避免。

1. ArithmeticException(算术异常)

已讲过:整数除以零触发。

java 复制代码
int x = 10 / 0;  // / by zero

2. ClassCastException(类型强转异常)

人话强制类型转换时,对象实际类型与目标类型不匹配

java 复制代码
Object obj = "hello";           // 实际是 String
Integer num = (Integer) obj;    // ❌ 报错:String cannot be cast to Integer

// 正确做法:先判断类型
if (obj instanceof Integer) {
    Integer num = (Integer) obj;
}

3. IllegalArgumentException(非法参数异常)

人话方法入参不符合业务规则(不是空指针或类型错误,而是值本身不合法)。

java 复制代码
public void setAge(int age) {
    if (age < 0 || age > 150) {
        throw new IllegalArgumentException("年龄必须在 0-150 之间");
    }
    this.age = age;
}

setAge(-5);   // 抛出 IllegalArgumentException
setAge(200);  // 抛出 IllegalArgumentException

典型场景

  • Thread.sleep(-1000)(睡眠时间不能为负)

  • ArrayList 初始容量为负数

  • 百分比参数传了 120%

4. IllegalStateException(非法状态异常)

人话对象当前状态不允许执行该操作(时机不对)。

java 复制代码
// 场景:Iterator 迭代过程中修改集合
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");

Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
    list.remove(s);  // ❌ 报错:ConcurrentModificationException(其实是 IllegalState 的变体)
    // 应该用 it.remove() 才是正确做法
}

// 另一个典型场景:Scanner 已关闭还调用
Scanner sc = new Scanner(System.in);
sc.close();
sc.nextLine();  // ❌ IllegalStateException: Scanner closed

5. IndexOutOfBoundsException(索引越界异常)

人话索引超出有效范围(父类,比 ArrayIndexOutOfBoundsException 更通用)。

java 复制代码
// 数组越界(子类 ArrayIndexOutOfBoundsException)
int[] arr = {1,2,3};
arr[5];  // 越界

// 字符串越界(子类 StringIndexOutOfBoundsException)
String s = "abc";
s.charAt(5);  // 越界

// List 越界(子类 IndexOutOfBoundsException)
List<Integer> list = new ArrayList<>();
list.get(0);  // 空列表取第0个,越界

6. NoSuchElementException(无此元素异常)

人话迭代器已经没有元素了,还继续取

java 复制代码
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    it.next();
}
it.next();  // ❌ 迭代器已经到头了,还调用 next()

// 另一个常见场景:Optional 为空时取值
Optional<String> opt = Optional.empty();
opt.get();  // ❌ NoSuchElementException: No value present
// 应该用 opt.orElse("default")

7. NullPointerException(空指针异常)

人话对 null 对象调用方法或访问字段

复制代码
String s = null;
s.length();           // 调用方法
s.toString();         // 调用方法
int[] arr = null;
arr[0] = 1;           // 访问数组元素

避免方式

复制代码
// 方式1:判空
if (s != null) { s.length(); }

// 方式2:Optional(Java 8+)
Optional.ofNullable(s).map(String::length).orElse(0);

// 方式3:Objects.requireNonNull(提前检查)
this.name = Objects.requireNonNull(name, "name 不能为 null");

总结速查表

|-------------------------------|------------|---------------------------|
| 异常 | 触发场景 | 预防方法 |
| ArithmeticException | 除以零 | 检查除数不为0 |
| ClassCastException | 强转类型不匹配 | 先用 instanceof 判断 |
| IllegalArgumentException | 参数值不合法 | 方法入口做参数校验 |
| IllegalStateException | 对象状态不允许操作 | 了解对象生命周期,按规范使用 |
| IndexOutOfBoundsException | 索引超范围 | 检查 size()/length() |
| NoSuchElementException | 迭代器已耗尽还取元素 | 确保 hasNext()next() |
| NullPointerException | 操作 null 对象 | 判空、Optional、注解检查 |

一句话 :这些都是代码逻辑错误,编译器不逼你处理,但运行时必炸,最好通过严谨的编码习惯(判空、判类型、判范围)来避免。

相关推荐
小王不爱笑1321 小时前
LangChain4j 项目实战--1:硅谷小智(医疗智能客服)笔记
java
XiaoLeisj1 小时前
Android Activity 页面导航基础:Manifest 声明、Intent 显式/隐式跳转与数据传递
android·java
忍者必须死2 小时前
JDK1.7的HashMap的环形链表
java·数据结构·算法·链表
鹿角片ljp2 小时前
短信登录:基于 Session 实现(黑马点评实战)
java·服务器·spring boot·mybatis
北风toto2 小时前
JDK8(JAVA)供应商说明
java·开发语言
清水白石0082 小时前
观察者模式全解析:用 Python 构建优雅的事件系统,让组件彻底解耦
java·python·观察者模式
xiaoccii2 小时前
C++(入门版)
java·c++·算法
上下求索,莫负韶华2 小时前
java-(double,BigDecimal),sql-(decimal,nuermic)
java·开发语言·sql
ID_180079054732 小时前
淘宝商品详情 API 接口 item_get: 高效获取商品数据的技术方案
java·前端·数据库