引言
在Java开发领域,掌握核心基础知识是构建稳健系统的基石。本教程将系统梳理Java泛型(Generics)、集合框架(Collection Framework)、接口(Comparable/Comparator)及异常处理四大核心模块,结合JDK 8-17特性与工业级实践案例,帮助开发者建立类型安全编程思维、高效数据结构应用能力及健壮的错误处理机制。
第一章 泛型
1.1 泛型本质与演进
Java泛型通过类型参数化实现编译期类型检查,其核心价值在于:
- 类型安全:消除强制类型转换(如
List<String>
无法添加Integer) - 代码复用:同一类/方法可处理多种数据类型(如
Box<T>
可存储任意对象) - 可读性提升:类型参数显式声明(如
Map<K,V>
明确键值类型)
历史演进:
- JDK 5(2004)引入基础泛型
- JDK 7(2011)支持菱形操作符
<>
- JDK 9(2017)增强泛型类型推断
1.2 泛型类型系统
1.2.1 类型参数命名规范
标识符 | 含义 | 典型场景 |
---|---|---|
T | Type | 通用类型参数 |
E | Element | 集合元素类型 |
K | Key | Map键类型 |
V | Value | Map值类型 |
N | Number | 数值类型 |
? | Wildcard | 未知类型(通配符) |
1.2.2 泛型通配符实战
上界通配符 <? extends Number>
:
public double sum(List<? extends Number> numbers) {
return numbers.stream()
.mapToDouble(Number::doubleValue)
.sum();
}
// 可接受:List<Integer>, List<Double>, List<Number>
下界通配符 <? super Integer>
:
public void addIntegers(List<? super Integer> list) {
list.add(1);
list.add(2);
}
// 可接受:List<Integer>, List<Number>, List<Object>
PECS原则(Producer-Extends, Consumer-Super):
- 生产者角色使用
extends
(如read
操作) - 消费者角色使用
super
(如write
操作)
1.3 类型擦除机制解析
Java泛型采用类型擦除实现跨平台兼容性:
// 编译前
List<String> strings = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
// 编译后(字节码层面)
List strings = new ArrayList(); // 类型参数被擦除为Object
List integers = new ArrayList; // 仅保留原始类型
桥方法生成:
当泛型类继承时,编译器会自动生成桥方法保证多态性:
class Node<T> {
T data;
void setData(T data) { this.data = data; }
}
class MyNode extends Node<Integer> {
@Override
void setData(Integer data) { // 实际重写的是泛型方法
super.setData(data);
}
}
// 编译器生成桥方法:
void setData(Object data) {
setData((Integer)data); // 强制类型转换
}
1.4 泛型的补充说明
- 避免原始类型:优先使用
List<String>
而非List
- 类型参数数量控制:单个类不超过3个类型参数
- 递归类型边界(JDK 10+):
static <T extends Comparable<? super T>> T max(List<T> list) {
// 允许T实现Comparable<T>或其父类
}
- Kotlin互操作:使用
@JvmSuppressWildcards
处理泛型差异
第二章 集合框架
2.1 集合体系架构
核心接口对比:
接口 | 特性 | 典型实现 | 时间复杂度(平均) |
---|---|---|---|
List | 有序、可重复 | ArrayList, LinkedList | O(1) add/get |
Set | 无序、唯一 | HashSet, TreeSet | O(1) add (HashSet) |
Queue | FIFO/LIFO | LinkedList, ArrayDeque | O(1) offer/poll |
Map | 键值对 | HashMap, TreeMap | O(1) put/get |
2.2 List实现深度解析
2.2.1 ArrayList扩容机制
// JDK 8 ArrayList.java片段
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
性能优化建议:
- 预估容量时使用
Arrays.copyOf(null, initialCapacity)
- 批量操作优先使用
addAll(Collection)
而非循环add()
- 随机访问使用
get(index)
,顺序遍历使用迭代器
2.2.2 LinkedList双端操作
// JDK 8 LinkedList.java片段
public void addFirst(E e) {
linkFirst(e); // O(1)时间复杂度
}
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
linkLast(e); // O(1)时间复杂度
}
适用场景:
- 频繁插入/删除:
LinkedList
优于ArrayList
- 随机访问:
ArrayList
性能是LinkedList
的500-1000倍
2.3 Set实现原理
2.3.1 HashSet哈希策略
// JDK 8 HashSet.java片段
public boolean add(E e) {
return map.put(e, PRESENT)==null; // PRESENT是静态常量Object
}
// 内部使用HashMap存储元素
private transient HashMap<E,Object> map;
static final Object PRESENT = new Object();
哈希冲突处理:
- 链表法(JDK 7及之前)
- 红黑树法(JDK 8+当链表长度>8时转为树结构)
2.3.2 TreeSet排序机制
// 自然排序示例
Set<String> treeSet = new TreeSet<>();
treeSet.add("banana");
treeSet.add("apple"); // 自动按字母顺序排序
// 定制排序示例
Set<Integer> customSet = new TreeSet<>((a, b) -> b - a);
customSet.add(3);
customSet.add(1); // 降序排列 [3,1]
2.4 Map高级特性
2.4.1 HashMap并发问题
线程不安全示例:
Map<String, Integer> map = new HashMap<>();
// 并发环境下可能导致数据不一致
map.put("key", 1);
解决方案:
Collections.synchronizedMap()
ConcurrentHashMap
(推荐)Map<String, Integer> concurrentMap = new ConcurrentHashMap<>(16, 0.75f); concurrentMap.putIfAbsent("key", 1); // 原子操作
2.4.2 Java 8 Map增强
computeIfAbsent:
Map<String, List<String>> map = new HashMap<>();
map.computeIfAbsent("group1", k -> new ArrayList<>()).add("item1");
merge操作:
Map<String, Integer> scores = new HashMap<>();
scores.merge("Alice", 10, Integer::sum); // {"Alice":10}
scores.merge("Alice", 5, Integer::sum); // {"Alice":15}
第三章 接口
3.1 Comparable自然排序
3.1.1 实现规范
public class Product implements Comparable<Product> {
private String name;
private double price;
@Override
public int compareTo(Product other) {
// 价格升序排列
return Double.compare(this.price, other.price);
// 如需降序:
// return Double.compare(other.price, this.price);
}
}
排序性能对比:
排序算法 | 时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|
TimSort(Arrays.sort) | O(n log n) | O(n) | 稳定 |
DualPivotQuickSort | O(n log n) | O(log n) | 不稳定 |
3.2 Comparator定制排序
3.2.1 Lambda表达式简化
List<String> names = Arrays.asList("John", "Alice", "Bob");
// 按字符串长度排序
names.sort((s1, s2) -> s1.length() - s2.length());
// Java 8+ 方法引用
names.sort(Comparator.comparingInt(String::length));
3.2.2 多条件排序
List<Employee> employees = ...;
// 先按部门升序,再按薪资降序
employees.sort(Comparator.comparing(Employee::getDepartment)
.thenComparing(Employee::getSalary, Comparator.reverseOrder()));
3.3 接口演进
3.3.1 默认方法(JDK 8+)
public interface Cache {
void put(String key, Object value);
default Object getOrDefault(String key, Object defaultValue) {
Object value = get(key); // 假设get是抽象方法
return value != null ? value : defaultValue;
}
// 静态工具方法
static <K,V> Cache<K,V> newInstance() {
return new HashMapCache<>();
}
}
默认方法冲突解决:
interface A { default void foo() { System.out.println("A"); } }
interface B { default void foo() { System.out.println("B"); } }
class C implements A, B {
@Override
public void foo() {
A.super.foo(); // 显式指定调用A的实现
// 或 B.super.foo();
}
}
3.3.2 函数式接口
Java内置函数式接口:
接口 | 参数类型 | 返回类型 | 典型用途 |
---|---|---|---|
Predicate | T | boolean | 条件过滤 |
Function<T,R> | T | R | 类型转换 |
Consumer | T | void | 副作用操作 |
Supplier | None | T | 延迟初始化 |
自定义函数式接口:
@FunctionalInterface
interface TriFunction<T,U,V,R> {
R apply(T t, U u, V v);
}
// 使用示例
TriFunction<Integer, Integer, Integer, Integer> sum = (a,b,c) -> a+b+c;
第四章 异常处理
4.1 异常体系架构
关键分类:
-
Checked Exception:
- 必须显式处理(try-catch或throws)
- 示例:
IOException
,SQLException
-
Unchecked Exception:
- 包括
RuntimeException
及其子类 - 示例:
NullPointerException
,IllegalArgumentException
- 包括
-
Error:
- JVM级严重错误(通常不应捕获)
- 示例:
OutOfMemoryError
,StackOverflowError
4.2 异常处理模式
4.2.1 防御性编程
public double divide(double dividend, double divisor) {
if (divisor == 0) {
throw new ArithmeticException("Divisor cannot be zero");
}
return dividend / divisor;
}
4.2.2 资源管理(try-with-resources)
// JDK 7+ 自动关闭资源
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"));
PrintWriter pw = new PrintWriter("output.txt")) {
String line;
while ((line = br.readLine()) != null) {
pw.println(line.toUpperCase());
}
} catch (IOException e) {
log.error("File processing failed", e);
}
实现AutoCloseable:
public class CustomResource implements AutoCloseable {
private boolean isOpen = true;
public void doWork() {
if (!isOpen) throw new IllegalStateException("Resource closed");
System.out.println("Working...");
}
@Override
public void close() {
isOpen = false;
System.out.println("Resource closed");
}
}
// 使用示例
try (CustomResource res = new CustomResource()) {
res.doWork();
}
4.3 自定义异常设计
4.3.1 异常链
public class DataProcessingException extends Exception {
public DataProcessingException(String message, Throwable cause) {
super(message, cause);
}
}
// 使用场景
try {
parseData(rawInput);
} catch (ParseException e) {
throw new DataProcessingException("Failed to parse input", e);
}
4.3.2 业务异常
-
命名规范:
- 以
Exception
结尾(如InvalidOrderException
) - 避免使用
Error
后缀(保留给JVM错误)
- 以
-
状态码封装:
public class BusinessException extends RuntimeException {
private final int code;
private final String message;
public BusinessException(int code, String message) {
this.code = code;
this.message = message;
}
// getters...
}
// 使用示例
throw new BusinessException(400, "Invalid request parameters");
- 国际化支持:
public class I18nException extends RuntimeException {
private final String messageKey;
private final Object[] args;
public I18nException(String messageKey, Object... args) {
this.messageKey = messageKey;
this.args = args;
}
@Override
public String getMessage() {
return MessageFormat.format(
ResourceBundle.getBundle("messages").getString(messageKey),
args
);
}
}
4.4 异常处理性能优化
4.4.1 异常捕获成本
微基准测试结果(JMH测试):
操作 | 吞吐量(ops/ms) |
---|---|
正常流程 | 12,500 |
捕获异常 | 3,200 |
抛出异常 | 850 |
优化建议:
- 避免在循环中使用异常控制流程
- 优先使用条件判断而非异常处理预期情况
- 缓存频繁抛出的异常对象(如
IllegalArgumentException
实例)
4.4.2 日志记录
// 错误级别记录
log.error("Failed to process order {}", orderId, exception);
// 调试级别记录(避免在生产环境记录敏感数据)
if (log.isDebugEnabled()) {
log.debug("Raw input: {}", sensitiveData);
}
// MDC上下文记录
try (MDC.putCloseable("requestId", requestId)) {
log.info("Processing request");
// 业务逻辑
}
第五章 实践案例
5.1 泛型+集合构建缓存系统
public class LRUCache<K, V> implements AutoCloseable {
private final Map<K, V> cache;
private final int maxSize;
private final Deque<K> accessOrder;
public LRUCache(int maxSize) {
this.maxSize = maxSize;
this.cache = new LinkedHashMap<>(maxSize, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
boolean shouldRemove = size() > maxSize;
if (shouldRemove) {
accessOrder.removeFirst();
}
return shouldRemove;
}
};
this.accessOrder = new ArrayDeque<>();
}
public synchronized V get(K key) {
V value = cache.get(key);
if (value != null) {
accessOrder.remove(key);
accessOrder.addLast(key);
}
return value;
}
public synchronized void put(K key, V value) {
if (cache.containsKey(key)) {
accessOrder.remove(key);
} else if (cache.size() >= maxSize) {
K eldestKey = accessOrder.removeFirst();
cache.remove(eldestKey);
}
cache.put(key, value);
accessOrder.addLast(key);
}
@Override
public void close() {
cache.clear();
accessOrder.clear();
}
}
5.2 接口+异常构建验证框架
public interface Validator<T> {
void validate(T object) throws ValidationException;
default Validator<T> and(Validator<T> other) {
return t -> {
validate(t);
other.validate(t);
};
}
}
public class UserValidator implements Validator<User> {
@Override
public void validate(User user) throws ValidationException {
if (user.getName() == null || user.getName().trim().isEmpty()) {
throw new ValidationException("Username cannot be empty");
}
if (user.getAge() < 0 || user.getAge() > 120) {
throw new ValidationException("Invalid age range");
}
}
}
// 使用示例
Validator<User> userValidator = new UserValidator()
.and(user -> {
if (!user.getEmail().contains("@")) {
throw new ValidationException("Invalid email format");
}
});
try {
userValidator.validate(new User("john", 30, "john@example.com"));
} catch (ValidationException e) {
System.err.println("Validation failed: " + e.getMessage());
}
总结
本教程系统梳理了Java泛型、集合框架、接口及异常处理的核心机制与工业实践:
- 泛型:通过类型参数化实现编译期类型安全,需理解类型擦除机制
- 集合框架:根据数据特征选择合适实现(ArrayList/LinkedList/HashMap等)
- 接口:利用Comparable/Comparator实现灵活排序,掌握默认方法演进
- 异常处理:构建分层异常体系,结合日志实现可观测性