1. 轉換集合的元素
在程式設計中,最常見的操作之一就是 集合轉換:我們手上有一個某種型別的資料集合,並需要在此基礎上建立另一個不同型別的新集合。比如,從型別為 User 的物件清單取得它們的名稱(String),或者從數字清單得到它們的平方清單。
在 Java 中最基礎也最直觀的方法是採用命令式作法,也就是使用一般的 for 迴圈(常見的是 for-each)。
範例:由字串清單取得其長度清單
假設我們有一個城市名稱的清單:
List<String> cities = List.of("倫敦", "巴黎", "東京", "紐約");
我們的任務是建立一個新清單,包含每個名稱的長度。最終結果應為:[2, 2, 2, 2]。
使用迴圈 for 的解法:
import java.util.ArrayList;
import java.util.List;
public class CollectionTransform {
public static void main(String[] args) {
List<String> cities = List.of("倫敦", "巴黎", "東京", "紐約");
List<Integer> lengths = new ArrayList<>(); // 建立一個新的空清單來儲存結果
for (String city : cities) {
// 對於 cities 中的每個元素,計算其長度...
int length = city.length();
// ...並將結果加入新的清單
lengths.add(length);
}
System.out.println(lengths); // 輸出: [2, 2, 2, 2]
}
}
我們先建立一個新的空集合來存放結果——轉換不會修改原始集合。為了走訪原始集合,我們使用 for-each 迴圈,並在迴圈內對每個元素套用所需的邏輯(length()),然後將結果透過 add 加入新清單。
2. 物件的轉換
我們經常會處理更複雜的資料型別。假設有一個類別 Product,需要取得其名稱(或價格)的清單。
public class Product {
private String name;
private double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
現在,基於產品清單,來取得它們的名稱清單:
import java.util.ArrayList;
import java.util.List;
public class ProductExample {
public static void main(String[] args) {
List<Product> products = List.of(
new Product("筆電", 1200.0),
new Product("滑鼠", 25.5),
new Product("鍵盤", 75.0)
);
// 建立一個用來存放名稱的新清單
List<String> productNames = new ArrayList<>();
for (Product product : products) {
// 對於每個 Product 物件,取得其名稱
productNames.add(product.getName());
}
System.out.println(productNames); // 輸出: [筆電, 滑鼠, 鍵盤]
}
}
邏輯相同:走訪原始集合,對每個元素呼叫所需的方法(例如 getName()),並把結果加入新的集合。
3. 處理巢狀集合
考慮一個清單的清單:有多個部門,每個部門都有自己的員工清單。目標是取得一個共同(「扁平」)的所有員工清單。
範例:合併員工清單
List<List<String>> departments = List.of(
List.of("安娜", "鮑里斯"),
List.of("維多利亞", "格列布", "德米特里"),
List.of("葉蓮娜")
);
我們希望得到單一清單:[安娜, 鮑里斯, 維多利亞, 格列布, 德米特里, 葉蓮娜]。
方法一:使用 addAll()
import java.util.ArrayList;
import java.util.List;
public class NestedCollectionExample {
public static void main(String[] args) {
List<List<String>> departments = List.of(
List.of("安娜", "鮑里斯"),
List.of("維多利亞", "格列布", "德米特里"),
List.of("葉蓮娜")
);
List<String> allEmployees = new ArrayList<>();
// 逐一走訪每個清單(部門)
for (List<String> department : departments) {
// 將當前清單中的所有元素加入總清單
allEmployees.addAll(department);
}
System.out.println(allEmployees); // [安娜, 鮑里斯, 維多利亞, 格列布, 德米特里, 葉蓮娜]
}
}
方法二:巢狀迴圈——手動完成相同的事情:
List<List<String>> departments = List.of(...);
List<String> allEmployees = new ArrayList<>();
for (List<String> department : departments) { // 外層迴圈:部門
for (String employee : department) { // 內層迴圈:員工
allEmployees.add(employee);
}
}
System.out.println(allEmployees);
兩種方式在結果上等價。方法 addAll() 本質上封裝了巢狀迴圈的邏輯,使程式碼更精簡。
4. 複雜情況與帶條件的轉換
有時轉換只需要對滿足條件的元素執行。比如,取得以字首「紐」開頭的城市名稱,並取其長度。這裡我們把過濾與轉換結合:if + 方法呼叫(length())。
import java.util.ArrayList;
import java.util.List;
public class ConditionalTransform {
public static void main(String[] args) {
List<String> cities = List.of("倫敦", "巴黎", "東京", "紐約", "紐倫堡");
List<Integer> lengths = new ArrayList<>();
for (String city : cities) {
// 先檢查條件
if (city.startsWith("紐")) {
// 若條件成立,執行轉換
lengths.add(city.length());
}
}
System.out.println(lengths); // 輸出: [2, 3]
}
}
模式如下:在迴圈內先透過條件(startsWith、比較、範圍檢查等)過濾元素,然後套用所需的轉換,最後把結果放進新清單。
5. 常見錯誤與陷阱
錯誤一:在遍歷期間修改原始集合。 常見錯誤——嘗試在 for-each 迴圈中直接向原始集合新增/刪除元素。這會導致錯誤與不可預期的行為。解法:一律建立新的結果清單並加以填充。
錯誤二:不正確的型別轉換。 如果你使用「未泛型化」的集合(例如透過 Object)並把元素轉成錯誤的型別,會得到 ClassCastException。請使用泛型(List<T>),並留意簽章。
錯誤三:資源使用效率不佳。 對於非常大的集合,不斷建立新清單與複製元素可能在記憶體與時間上都有明顯成本。多數日常情境下這是可接受的,但在處理大量資料時請評估複雜度,必要時優化作法。
GO TO FULL VERSION