泛型最佳实践
泛型使用遵循一些最佳实践,可提高代码质量和类型安全。
类型参数命名约定
Java
// 推荐:使用标准命名
public class Box<T> {} // Type,任意类型
public class List<E> {} // Element,集合元素
public class Map<K, V> {} // Key, Value
public class Comparator<T> {} // Type
public class Function<T, R> {} // Type, Result
| 命名 | 用途 |
|---|---|
| T | Type,通用类型 |
| E | Element,集合元素 |
| K | Key,键 |
| V | Value,值 |
| N | Number,数值 |
| R | Result,返回类型 |
避免单字母外命名:保持代码一致性,便于理解。
PECS 原则
Producer-Extends, Consumer-Super:
Java
// 生产者(读取):用 extends
public void process(List<? extends Number> source) {
Number n = source.get(0); // 读取
}
// 消费者(写入):用 super
public void add(List<? super Integer> target) {
target.add(1); // 写入
}
// 复制方法
public static <T> void copy(
List<? extends T> src, // 生产者
List<? super T> dest // 消费者
) {
for (int i = 0; i < src.size(); i++) {
dest.set(i, src.get(i));
}
}
PECS 记忆:"Get(读取)用 extends,Put(写入)用 super"。
避免使用原始类型
Java
// 错误:使用原始类型
List list = new ArrayList(); // 无泛型,类型不安全
list.add("Hello");
list.add(100); // 编译通过,运行时可能出错
// 正确:使用泛型
List<String> list = new ArrayList<>();
list.add(100); // 编译错误
原始类型警告:编译器警告 "List is a raw type",应消除。
消除泛型警告
Java
// 错误:泛型警告未处理
List list = new ArrayList(); // 警告
// 正确1:使用泛型
List<String> list = new ArrayList<>();
// 正确2:明确转型时抑制警告
@SuppressWarnings("unchecked")
List<String> list = (List<String>) rawList;
抑制警告原则:仅在明确知道转型安全时使用,注释说明原因。
不要在静态成员使用类泛型参数
Java
// 错误:静态成员不能使用类泛型参数
public class Box<T> {
private static T value; // 错误
public static T method() { return null; } // 错误
}
// 正确:静态方法定义自己的泛型参数
public class Box<T> {
public static <E> E method(E item) {
return item;
}
}
优先泛型方法而非通配符
Java
// 方式1:通配符
public static void process(List<?> list) {
// 只能作为 Object 处理
}
// 方式2:泛型方法(推荐)
public static <T> void process(List<T> list) {
T first = list.get(0); // 类型安全
list.add(first); // 可添加
}
泛型方法优势:保持具体类型,可读写操作。
使用泛型消除转型
Java
// 错误:手动转型
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0); // 转型
// 正确:泛型消除转型
List<String> list = new ArrayList<>();
list.add("Hello");
String s = list.get(0); // 无需转型
避免过度泛型化
Java
// 过度泛型化:不需要泛型
public class Id<T> {
private T value;
public T getValue() { return value; }
}
// Id<Integer> 和 Id<String> 功能完全相同
// 泛型没有带来实际价值
// 适当泛型化:泛型有意义
public class Box<T> {
private T value;
// T 在类中确实发挥作用
}
基本类型使用包装类
Java
// 错误:泛型不支持基本类型
List<int> list = new ArrayList<int>(); // 编译错误
// 正确:使用包装类
List<Integer> list = new ArrayList<>();
泛型与异常
Java
// 错误:不能抛出泛型异常
public class MyException<T> extends Exception {} // 错误
// 错误:catch 不能用泛型
public void method() {
try { }
catch (T e) {} // 错误
}
// 正确:方法签名可用泛型
public <T extends Exception> void method() throws T {}
要点总结
- 类型参数命名:T、E、K、V 等标准命名
- PECS:Producer 用 extends,Consumer 用 super
- 避免原始类型,使用泛型保证类型安全
- 静态成员不能使用类泛型参数
- 优先泛型方法而非通配符
- 使用泛型消除手动转型
- 基本类型使用包装类替代
- 避免过度泛型化,泛型应带来实际价值
- 泛型不能用于异常类和 catch
📝 发现内容有误?点击此处直接编辑