跳到主要内容

Java 集合转换

在Java编程过程中,我们经常需要在不同的集合类型之间进行转换。例如,将数组转换为List,将Set转换为List,或者将Map的键或值提取出来等。掌握这些转换技巧对于高效处理数据结构至关重要。

为什么需要集合转换?

集合转换的需求源于不同集合类型的特点和使用场景:

  1. 不同集合类型有不同的特性和优势
  2. 某些API可能要求特定类型的集合作为输入或输出
  3. 在处理数据时,可能需要利用不同集合类型的功能

数组与集合的转换

数组转换为List

将数组转换为List是最常见的操作之一,有多种方法可以实现:

使用Arrays.asList()

java
String[] array = {"Apple", "Banana", "Orange"};
List<String> list = Arrays.asList(array);

System.out.println("原始数组: " + Arrays.toString(array));
System.out.println("转换后的List: " + list);

输出:

原始数组: [Apple, Banana, Orange]
转换后的List: [Apple, Banana, Orange]
注意

Arrays.asList()返回的List是固定大小的列表,它是数组的视图,不支持添加或删除元素。如果尝试这些操作,会抛出UnsupportedOperationException异常。

如果需要一个可修改的List,可以使用以下方式:

java
String[] array = {"Apple", "Banana", "Orange"};
List<String> list = new ArrayList<>(Arrays.asList(array));
list.add("Grape"); // 这是允许的

System.out.println("可修改的List: " + list);

输出:

可修改的List: [Apple, Banana, Orange, Grape]

使用Java 8及以上的Stream API

java
String[] array = {"Apple", "Banana", "Orange"};
List<String> list = Arrays.stream(array).collect(Collectors.toList());

System.out.println("通过Stream API转换的List: " + list);

输出:

通过Stream API转换的List: [Apple, Banana, Orange]

List转换为数组

java
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");

// 转换为Object数组
Object[] objectArray = list.toArray();
System.out.println("Object数组: " + Arrays.toString(objectArray));

// 转换为指定类型的数组
String[] stringArray = list.toArray(new String[0]);
System.out.println("String数组: " + Arrays.toString(stringArray));

// Java 11及以上可以使用更简洁的写法
// String[] stringArray = list.toArray(String[]::new);

输出:

Object数组: [Apple, Banana, Orange]
String数组: [Apple, Banana, Orange]

集合之间的转换

List转Set

当你需要去除List中的重复元素时,将其转换为Set是很有用的。

java
List<String> fruitList = new ArrayList<>();
fruitList.add("Apple");
fruitList.add("Banana");
fruitList.add("Apple"); // 重复元素
fruitList.add("Orange");

// 将List转换为HashSet
Set<String> fruitSet = new HashSet<>(fruitList);

System.out.println("原始List: " + fruitList);
System.out.println("转换后的Set (去重): " + fruitSet);

输出:

原始List: [Apple, Banana, Apple, Orange]
转换后的Set (去重): [Apple, Orange, Banana]

Set转List

当你需要按特定顺序访问Set中的元素,或者需要使用List特有的方法时,将Set转为List很有用。

java
Set<String> fruitSet = new HashSet<>();
fruitSet.add("Apple");
fruitSet.add("Banana");
fruitSet.add("Orange");

// 将Set转换为ArrayList
List<String> fruitList = new ArrayList<>(fruitSet);
// 现在我们可以对列表进行排序
Collections.sort(fruitList);

System.out.println("原始Set: " + fruitSet);
System.out.println("转换后并排序的List: " + fruitList);

输出:

原始Set: [Apple, Orange, Banana]
转换后并排序的List: [Apple, Banana, Orange]

Map相关转换

Map是特殊的集合类型,它存储键值对。我们可以提取Map的键、值或者键值对进行各种操作。

获取Map的键集合

java
Map<String, Integer> fruitPrices = new HashMap<>();
fruitPrices.put("Apple", 100);
fruitPrices.put("Banana", 50);
fruitPrices.put("Orange", 80);

// 获取键的Set
Set<String> fruitNames = fruitPrices.keySet();
System.out.println("水果名称: " + fruitNames);

输出:

水果名称: [Apple, Orange, Banana]

获取Map的值集合

java
// 获取值的Collection
Collection<Integer> prices = fruitPrices.values();
System.out.println("价格列表: " + prices);

输出:

价格列表: [100, 80, 50]

获取Map的条目集合并转换

java
// 获取键值对的Set
Set<Map.Entry<String, Integer>> entries = fruitPrices.entrySet();

// 将Map转换为包含键值对的List
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(entries);
// 按价格排序
entryList.sort(Map.Entry.comparingByValue());

System.out.println("按价格排序的水果:");
for (Map.Entry<String, Integer> entry : entryList) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}

输出:

按价格排序的水果:
Banana: 50
Orange: 80
Apple: 100

使用Stream API进行高级转换

Java 8引入的Stream API提供了更强大和灵活的集合转换方式。

集合到其他集合的转换

java
List<String> fruits = Arrays.asList("Apple", "Banana", "Orange", "Apple");

// List转Set (去重)
Set<String> uniqueFruits = fruits.stream()
.collect(Collectors.toSet());
System.out.println("去重后的水果: " + uniqueFruits);

// 转换为TreeSet (自然排序)
TreeSet<String> sortedFruits = fruits.stream()
.collect(Collectors.toCollection(TreeSet::new));
System.out.println("排序后的水果: " + sortedFruits);

// 转换为LinkedList
LinkedList<String> linkedListFruits = fruits.stream()
.collect(Collectors.toCollection(LinkedList::new));
System.out.println("LinkedList水果: " + linkedListFruits);

输出:

去重后的水果: [Apple, Orange, Banana]
排序后的水果: [Apple, Banana, Orange]
LinkedList水果: [Apple, Banana, Orange, Apple]

转换为Map

java
List<String> fruits = Arrays.asList("Apple", "Banana", "Orange");

// 转换为Map,键为水果名,值为水果名长度
Map<String, Integer> fruitLengths = fruits.stream()
.collect(Collectors.toMap(
fruit -> fruit, // 键映射函数
String::length // 值映射函数
));

System.out.println("水果名称及其长度: " + fruitLengths);

输出:

水果名称及其长度: {Apple=5, Orange=6, Banana=6}

实际应用场景

场景1: 数据过滤和转换

假设我们有一个员工列表,需要筛选出所有工资超过5000的员工,并按照工资降序排列:

java
// 定义员工类
class Employee {
private String name;
private double salary;

public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}

public String getName() { return name; }
public double getSalary() { return salary; }

@Override
public String toString() {
return name + " ($" + salary + ")";
}
}

// 主程序
public class EmployeeFilter {
public static void main(String[] args) {
// 创建员工列表
List<Employee> employees = Arrays.asList(
new Employee("Alice", 6000),
new Employee("Bob", 4500),
new Employee("Charlie", 7500),
new Employee("David", 5500)
);

// 筛选高薪员工并排序
List<Employee> highPaidEmployees = employees.stream()
.filter(emp -> emp.getSalary() > 5000)
.sorted((e1, e2) -> Double.compare(e2.getSalary(), e1.getSalary()))
.collect(Collectors.toList());

System.out.println("高薪员工(降序排列):");
for (Employee emp : highPaidEmployees) {
System.out.println(emp);
}
}
}

输出:

高薪员工(降序排列):
Charlie ($7500.0)
Alice ($6000.0)
David ($5500.0)

场景2: 分组统计

假设我们有一个订单列表,需要按照客户进行分组并统计每个客户的订单总金额:

java
// 定义订单类
class Order {
private String customer;
private double amount;

public Order(String customer, double amount) {
this.customer = customer;
this.amount = amount;
}

public String getCustomer() { return customer; }
public double getAmount() { return amount; }
}

// 主程序
public class OrderAnalysis {
public static void main(String[] args) {
// 创建订单列表
List<Order> orders = Arrays.asList(
new Order("Customer1", 100.50),
new Order("Customer2", 200.75),
new Order("Customer1", 50.25),
new Order("Customer3", 300.00),
new Order("Customer2", 150.50)
);

// 按客户分组并计算总金额
Map<String, Double> totalByCustomer = orders.stream()
.collect(Collectors.groupingBy(
Order::getCustomer,
Collectors.summingDouble(Order::getAmount)
));

System.out.println("每个客户的订单总金额:");
totalByCustomer.forEach((customer, total) ->
System.out.println(customer + ": $" + total));
}
}

输出:

每个客户的订单总金额:
Customer1: $150.75
Customer2: $351.25
Customer3: $300.0

总结

在Java编程中,集合转换是一项基本且常用的操作:

  1. 数组与集合的转换

    • 数组转List:Arrays.asList(), Stream API
    • List转数组:toArray(), toArray(T[])
  2. 集合之间的转换

    • List转Set:通过构造器创建新集合
    • Set转List:通过构造器创建新集合
    • Map相关转换:keySet(), values(), entrySet()
  3. 使用Stream API进行高级转换

    • 使用collect()搭配各种Collectors方法实现复杂转换

掌握这些转换技巧可以帮助你更高效地操作数据,让代码更简洁、更易读。

练习

  1. 编写代码将一个整数数组转换为List<Integer>,并移除其中的所有偶数。
  2. 有一个字符串列表,将其转换为Map,其中键是字符串本身,值是字符串的长度。
  3. 创建一个包含重复元素的List,将其转换为Set去除重复元素,然后再转换回List并排序。
  4. 使用Stream API将Map的键和值分别提取为两个单独的List。
进阶学习

要深入学习Java集合转换,建议掌握Java 8的Stream API和函数式编程特性,它们提供了更强大和灵活的数据处理方式。