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("叶莲娜")
);
我们希望得到一个统一的列表:[安娜, 鲍里斯, 维多利亚, 格列布, 德米特里, 叶莲娜]。
方法 1:使用 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); // [安娜, 鲍里斯, 维多利亚, 格列布, 德米特里, 叶莲娜]
}
}
方法 2:嵌套循环——效果相同,但“手动”实现:
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. 常见错误与陷阱
错误 1:在遍历时修改源集合。 常见问题是尝试在 for-each 循环中直接向源集合添加/删除元素。这会导致错误和不可预测的行为。解决方案:始终为结果创建一个新列表,并只向该列表写入。
错误 2:错误的类型转换。 如果你使用“原始类型”的集合(例如通过 Object)并把元素转换成错误的类型,就会得到 ClassCastException。请使用泛型(List<T>),并注意方法签名。
错误 3:资源使用低效。 对于非常大的集合,频繁创建新列表并拷贝元素,可能在内存和时间上都有明显开销。对大多数日常任务来说这可以接受,但在处理海量数据时要考虑复杂度,并在必要时优化方案。
GO TO FULL VERSION