Java 入门进阶:异常、泛型、集合与 Stream 流
(适合 Java 8 → Java 21/25 的现代写法,2026 年视角)
这四个主题是 Java Core 中最实用、最常考、最容易写出“优雅 vs 丑陋”代码的分水岭。
下面按逻辑顺序 + 进阶深度给你系统梳理,从“能用”到“用得好”再到“知道为什么这样设计”。
1. 异常(Exception & Error)
核心认知:异常不是“错误处理”,而是“正常流程的非正常分支”。好的异常设计让代码可读、可维护、可追踪。
1.1 异常体系(必须背的图)
Throwable (顶级)
├── Error(严重错误,程序员基本不处理)
│ └── OutOfMemoryError / StackOverflowError / VirtualMachineError ...
└── Exception(可恢复异常,程序员重点处理)
├── RuntimeException(非检查异常/ unchecked)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ ├── IllegalArgumentException
│ ├── ClassCastException
│ └── ...(绝大多数业务异常继承它)
└── Checked Exception(检查异常,必须处理)
├── IOException
├── SQLException
└── ...(必须 try-catch 或 throws)
现代最佳实践(2025+ 共识):
- 业务异常统一继承 RuntimeException(别再到处 throws 了)
- 自定义异常类:
BusinessException、ValidationException、ResourceNotFoundException等,带错误码 + 消息 - 不要用异常做流程控制(性能差 + 难读)
- 不要 catch (Exception e) 或 Throwable(吃掉所有异常,隐藏问题)
- finally 块慎用 return(会覆盖 try/catch 的 return)
1.2 现代写法对比
// 老土写法(到处 throws + catch Exception)
public void process() throws Exception {
try {
// ...
} catch (Exception e) {
log.error("错了", e);
throw e;
}
}
// 推荐写法(Java 7+ try-with-resources + Java 8+ 多 catch)
public void processFile(Path path) {
try (var reader = Files.newBufferedReader(path)) {
// 读文件
} catch (FileNotFoundException e) {
throw new ResourceNotFoundException("文件不存在", e);
} catch (IOException e) {
throw new BusinessException("IO 异常", e);
}
}
// Java 14+ 带预览的模式匹配(Java 21+ 正式)
catch (Exception e) when (e instanceof IOException io) {
// io 是 IOException 类型
}
2. 泛型(Generics)——类型安全的“模板”
核心痛点:类型擦除(Type Erasure)导致运行时泛型信息丢失。
2.1 关键知识点
- 泛型只在编译期有效,运行时被擦除为原始类型(Object 或 上界)
List<String>和List<Integer>在 JVM 层面是同一个类List- 不能
new T()、T[] array = new T[10]、instanceof List<String> - 可以用
<? extends T>(上界通配符,Producer)和<? super T>(下界通配符,Consumer)
PECS 原则(Producer Extends, Consumer Super)——面试必考!
// 生产者(只读)用 extends
void printAnimals(List<? extends Animal> animals) {
for (Animal a : animals) System.out.println(a);
}
// 消费者(只写)用 super
void addCat(List<? super Cat> cats) {
cats.add(new Cat());
}
2.2 泛型擦除的经典坑 & 绕过方式
// 擦除导致的问题
List<String> list = new ArrayList<>();
List raw = list; // 编译通过
raw.add(123); // 运行时不报错,但后续取 String 会 ClassCastException
// 绕过方式(反射,慎用)
((List) list).add(123);
3. 集合框架(Collection Framework)
核心结构(2026 年仍以这个为主):
Collection (接口)
├── List(有序、可重复)
│ ├── ArrayList(数组,查询快)
│ ├── LinkedList(双向链表,增删快)
│ └── Vector(线程安全,已基本淘汰)
├── Set(无序、不可重复)
│ ├── HashSet(哈希表)
│ ├── LinkedHashSet(插入顺序)
│ └── TreeSet(红黑树排序)
└── Queue / Deque
├── PriorityQueue(堆)
└── ArrayDeque(双端队列)
Map(键值对)
├── HashMap(JDK8+ 红黑树优化)
├── LinkedHashMap(插入/访问顺序)
├── TreeMap(红黑树排序)
└── ConcurrentHashMap(高并发首选)
面试常考对比:
| 集合 | 底层结构 | 线程安全 | 允许 null key/value | 顺序 | 适用场景 |
|---|---|---|---|---|---|
| ArrayList | 动态数组 | 否 | value 可 null | 插入顺序 | 普通列表、查询多 |
| LinkedList | 双向链表 | 否 | 可 | 插入顺序 | 频繁头尾增删 |
| HashSet | HashMap | 否 | key 不允许 null | 无序 | 去重 |
| TreeSet | 红黑树 | 否 | 不允许 null | 自然/自定义排序 | 排序 + 去重 |
| HashMap | 数组 + 链表 + 红黑树 | 否 | key/value 允许 null | 无序 | 普通 KV 存储 |
| ConcurrentHashMap | 数组 + 链表 + 红黑树 + 分段锁 | 是(高并发) | key 不允许 null | 无序 | 多线程 KV 存储(首选) |
4. Stream 流(Java 8+ 核心生产力)
核心认知:Stream 是对集合/数组的函数式操作管道,支持惰性求值 + 并行。
4.1 创建 Stream 的 5 种常见方式
// 1. Collection
list.stream()
list.parallelStream()
// 2. 数组
Arrays.stream(arr)
Stream.of(arr) // 注意:如果是对象数组 OK,基本类型数组会包一层
// 3. 直接创建
Stream.of(1, 2, 3)
Stream.iterate(0, n -> n + 2).limit(10) // 偶数序列
Stream.generate(() -> Math.random()).limit(5)
// 4. 文件/正则
Files.lines(Paths.get("file.txt"))
Pattern.compile("\\s+").splitAsStream("a b c")
// 5. 空流
Stream.empty()
4.2 进阶用法(面试/实战高频)
// 1. 收集器高级用法
// 分组 + 统计
Map<String, Long> countByCity = persons.stream()
.collect(Collectors.groupingBy(Person::getCity, Collectors.counting()));
// 分组 + 最大年龄
Map<String, Optional<Person>> maxAgeByCity = persons.stream()
.collect(Collectors.groupingBy(Person::getCity,
Collectors.maxBy(Comparator.comparingInt(Person::getAge))));
// 2. 自定义收集器(partitioningBy + reducing)
Map<Boolean, Integer> sumEvenOdd = IntStream.range(1, 100)
.boxed()
.collect(Collectors.partitioningBy(n -> n % 2 == 0,
Collectors.reducing(0, Integer::sum)));
// 3. flatMap + Optional 组合(处理嵌套结构)
List<Optional<Order>> orders = ...
List<Product> allProducts = orders.stream()
.flatMap(opt -> opt.stream().flatMap(o -> o.getProducts().stream()))
.toList();
// 4. 并行流注意事项(2026 共识)
parallelStream() // 适合 CPU 密集型、大数据量、无状态操作
// 避免:有状态操作(如 sorted、limit、findFirst 在并行下不稳定)
5. 学习进阶路径建议(2026 年版)
- 先把异常体系 + 自定义异常搞定(写 3–5 个业务异常类)
- 掌握泛型擦除 + PECS(写 Producer/Consumer 示例)
- 集合:HashMap 1.7 vs 1.8 红黑树化、ConcurrentHashMap 1.7 vs 1.8 画图背熟
- Stream:每天写 3–5 个真实业务场景的 Stream(分组、统计、过滤、映射、flatMap)
- 目标:能用 Stream + Optional + 记录类(record)写出干净的业务代码
有具体哪一部分想深入代码示例?比如:
- 手写一个带错误码的异常体系?
- 泛型擦除的经典面试题?
- Stream 的 10 个高频业务写法?
- 集合框架的并发安全对比?
告诉我,我可以继续展开对应部分~