
目录
[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 包丢了
如何解决?
-
检查类名拼写 (大小写敏感,
User和user不同) -
检查依赖包:确保需要的 jar 包已添加到项目(Maven/Gradle 依赖)
-
检查类路径 :运行时
-cp或-classpath参数是否包含该类 -
检查类加载器:如果是 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、注解检查 |
一句话 :这些都是代码逻辑错误,编译器不逼你处理,但运行时必炸,最好通过严谨的编码习惯(判空、判类型、判范围)来避免。