返回

玩转List集合,Java大师的排序、去重、分组、过滤指南

后端

Java 集合操作进阶:排序、去重、分组、过滤、合并、截取

排序

在编程中,排序是一种至关重要的操作,它允许我们根据特定规则对元素进行排列。在 Java 中,可以通过多种方法对 List 集合进行排序:

  • 自然排序: 使用 Collections.sort(List list),对数字按大小排序,对字符串按字典顺序排序。
  • 自定义排序: 使用 List.sort(Comparator comparator),通过自定义比较器实现特定的排序规则。
  • 空元素处理: 使用 List.sort(nullsFirst/nullsLast),控制空元素的位置。

去重

去重是指从集合中移除重复元素。Java 提供了两种去重方法:

  • Set 转换: 将 List 转换为 Set,然后使用 Set.stream().distinct() 去除重复元素。
  • 流操作: 直接使用 List.stream().distinct() 去重,效率更高。

分组

分组将集合中的元素根据特定规则划分到不同的组中。Java 提供了两种分组方法:

  • 按键值分组: 使用 Collectors.groupingBy(Function<? super T, ? extends K> classifier),按分类器映射的键值分组。
  • 按键值收集: 使用 Collectors.groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, ?, ? extends V> downstream),按键值分组并对每个组使用指定的收集器收集元素。

过滤

过滤从集合中删除不满足指定条件的元素。Java 提供了两种过滤方法:

  • 流过滤: 使用 List.stream().filter(Predicate<? super T> predicate),通过谓词条件过滤元素。
  • 直接过滤: 使用 List.removeIf(Predicate<? super T> filter),直接从集合中移除不满足条件的元素。

合并

合并将多个集合合并成一个新的集合。Java 提供了两种合并方法:

  • addAll 方法: 使用 Collections.addAll(List list1, List list2) 将 list2 的元素添加到 list1。
  • List 合并: 使用 List.addAll(List list) 将 list 的元素添加到当前集合。

截取

截取从集合中提取指定范围内的元素。Java 提供了两种截取方法:

  • 子列表: 使用 List.subList(int fromIndex, int toIndex) 从指定位置开始截取元素。
  • 流操作: 使用 List.stream().skip(int n).limit(int m) 截取从第 n 个元素开始的 m 个元素。

代码示例

import java.util.*;

public class ListOperations {

    public static void main(String[] args) {
        // Sorting
        List<Integer> numbers = List.of(3, 1, 4, 2, 5);
        Collections.sort(numbers); // Natural sorting
        System.out.println(numbers); // [1, 2, 3, 4, 5]

        // De-duplication
        List<String> names = List.of("John", "Mary", "John", "Bob");
        List<String> uniqueNames = names.stream().distinct().toList();
        System.out.println(uniqueNames); // [John, Mary, Bob]

        // Grouping
        List<Employee> employees = List.of(
                new Employee("John", "Sales"),
                new Employee("Mary", "Marketing"),
                new Employee("Bob", "Sales")
        );
        Map<String, List<Employee>> employeesByDepartment = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment));
        System.out.println(employeesByDepartment); // {Sales=[John, Bob], Marketing=[Mary]}

        // Filtering
        List<Integer> evenNumbers = numbers.stream()
                .filter(n -> n % 2 == 0)
                .toList();
        System.out.println(evenNumbers); // [2, 4]

        // Merging
        List<Integer> numbers1 = List.of(1, 2, 3);
        List<Integer> numbers2 = List.of(4, 5, 6);
        List<Integer> mergedNumbers = new ArrayList<>();
        mergedNumbers.addAll(numbers1);
        mergedNumbers.addAll(numbers2);
        System.out.println(mergedNumbers); // [1, 2, 3, 4, 5, 6]

        // Sub-listing
        List<Integer> sublist = numbers.subList(1, 3); // From index 1 (inclusive) to index 3 (exclusive)
        System.out.println(sublist); // [2, 3]
    }

    private static class Employee {
        private String name;
        private String department;

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

        public String getName() {
            return name;
        }

        public String getDepartment() {
            return department;
        }
    }
}

常见问题解答

  1. 什么是自然排序?
    自然排序是根据元素本身的性质(例如数字大小、字符串字典顺序)进行排序。

  2. 如何使用自定义比较器进行排序?
    自定义比较器是一个实现了 Comparator 接口的类,可以根据特定的规则比较两个元素。

  3. 如何使用流操作进行过滤?
    流操作通过使用 Predicate 接口来过滤元素,返回一个包含符合条件元素的新流。

  4. addAll 和 List.addAll 有什么区别?
    addAll 方法将一个集合的元素添加到另一个集合,而 List.addAll 方法将另一个集合的元素添加到当前 List 中。

  5. subList 和 stream().skip(n).limit(m) 有什么区别?
    subList 返回一个包含指定范围元素的新 List,而 stream().skip(n).limit(m) 返回一个包含指定范围元素的流。