Java入门进阶:异常、泛型、集合与 Stream 流

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 了)
  • 自定义异常类:BusinessExceptionValidationExceptionResourceNotFoundException 等,带错误码 + 消息
  • 不要用异常做流程控制(性能差 + 难读)
  • 不要 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双向链表插入顺序频繁头尾增删
HashSetHashMapkey 不允许 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 年版)

  1. 先把异常体系 + 自定义异常搞定(写 3–5 个业务异常类)
  2. 掌握泛型擦除 + PECS(写 Producer/Consumer 示例)
  3. 集合:HashMap 1.7 vs 1.8 红黑树化ConcurrentHashMap 1.7 vs 1.8 画图背熟
  4. Stream:每天写 3–5 个真实业务场景的 Stream(分组、统计、过滤、映射、flatMap)
  5. 目标:能用 Stream + Optional + 记录类(record)写出干净的业务代码

有具体哪一部分想深入代码示例?比如:

  • 手写一个带错误码的异常体系?
  • 泛型擦除的经典面试题?
  • Stream 的 10 个高频业务写法?
  • 集合框架的并发安全对比?

告诉我,我可以继续展开对应部分~

文章已创建 4725

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部