在 List 中根據名字查找對象索引,是典型的「按屬性查找」場景。Java 8+ 推薦 Stream API,傳統循環最直觀,迭代器適用於並發修改場景。
class Person {
private String name;
private String sex;
private int age;
// 構造器、getters、setters、toString
public Person(String name, String sex, int age) { ... }
public String getName() { return name; }
}
List list = Arrays.asList(
new Person("張三", "男", 20),
new Person("李四", "男", 22),
new Person("王五", "男", 24)
);
// 返回 Optional,優雅處理未找到
Optional indexOpt = IntStream.range(0, list.size())
.filter(i -> "李四".equals(list.get(i).getName()))
.findFirst();
// 使用
indexOpt.ifPresentOrElse(
index -> System.out.println("索引: " + index), // 輸出 1
() -> System.out.println("未找到")
);
// 一行寫法 (不推薦生產,調試難)
int index = IntStream.range(0, list.size())
.filter(i -> "李四".equals(list.get(i).getName()))
.findFirst()
.orElse(-1); // -1 表示未找到
int findIndexByName(List list, String targetName) {
for (int i = 0; i < list.size(); i++) {
if (targetName.equals(list.get(i).getName())) { // 防空指針用常量調用 equals
return i;
}
}
return -1; // 未找到
}
// Apache Commons Collections
int index = ListUtils.findIndex(list, p -> "李四".equals(p.getName()));
// 或自己寫通用工具
public static int findIndex(List list, Predicate predicate) {
for (int i = 0; i < list.size(); i++) {
if (predicate.test(list.get(i))) return i;
}
return -1;
}
// 使用
int index = findIndex(list, p -> "李四".equals(p.getName()));
// 注意:並行流有開銷,小列表反而慢
int index = IntStream.range(0, list.size())
.parallel() // 並行
.filter(i -> "李四".equals(list.get(i).getName()))
.findAny() // 並行用 findAny
.orElse(-1);
| 方案 | 時間複雜度 | 空間複雜度 | 可讀性 | 調試 | 適用場景 |
|---|---|---|---|---|---|
| for 循環 | O(n) | O(1) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 所有場景、熱路徑、嵌入式 |
| Stream API | O(n) | O(1) (鏈式) | ⭐⭐⭐⭐ | ⭐⭐⭐ | 業務邏輯、鏈式操作、函數式風格 |
| 工具類封裝 | O(n) | O(1) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 項目通用、團隊統一風格 |
| 並行流 | O(n/p) | O(log n) | ⭐⭐⭐ | ⭐⭐ | 超大列表 (10萬+)、CPU 密集 |
// 如果頻繁按名字查找,構建 Map 索引 O(1) 查找
Map nameToIndex = new HashMap<>();
for (int i = 0; i < list.size(); i++) {
nameToIndex.put(list.get(i).getName(), i);
}
// 查找
Integer index = nameToIndex.get("李四"); // O(1)
// 注意:列表修改時需同步維護 Map
CollectionUtils.findIndex(list, predicate) 通用方法。
3. 防空指針:"李四".equals(obj.getName()) 而非 obj.getName().equals("李四")。
4. 返回 -1 表示未找到:避免 Optional 在簡單邏輯中增加認知負荷。
5. 頻繁查詢建索引:Map/數據庫索引/搜索引擎,勿在列表線性掃描。
核心原則:正確性 > 可讀性 > 效能。對於百元級列表,for 循環是最佳平衡;萬級以上考慮索引優化。