企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 如何在 Java 中对数组,列表,映射和集合进行排序 > 原文: [https://howtodoinjava.com/java-sorting-guide/](https://howtodoinjava.com/java-sorting-guide/) 学习使用 Java 对数组或集合进行排序。 我们将学习对包含原始类型和自定义对象的集合,列表和映射进行排序。 我们还将学习升序排序。 ## 1\. 排序数组 #### 1.1 升序排序数组 Java 程序使用[`Arrays.sort()`](https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#sort(byte[]))方法以升序对整数数组进行排序。 ```java import java.util.Arrays; public class JavaSortExample { public static void main(String[] args) { //Unsorted array Integer[] numbers = new Integer[] { 15, 11, 9, 55, 47, 18, 520, 1123, 366, 420 }; //Sort the array Arrays.sort(numbers); //Print array to confirm System.out.println(Arrays.toString(numbers)); } } ``` 程序输出。 ```java [9, 11, 15, 18, 47, 55, 366, 420, 520, 1123] ``` #### 1.2 降序排序数组 Java 提供`Collections.reverseOrder()`比较器,以在一行中反转默认的排序行为。 使用此命令以降序对数组进行排序。 ```java //Unsorted array Integer[] numbers = new Integer[] { 15, 11, 9, 55, 47, 18, 520, 1123, 366, 420 }; //Sort the array in reverse order Arrays.sort(numbers, Collections.reverseOrder()); //Print array to confirm System.out.println(Arrays.toString(numbers)); ``` 程序输出: ```java [1123, 520, 420, 366, 55, 47, 18, 15, 11, 9] ``` #### 1.3 排序数组范围 `Arrays.sort()`方法是重载方法,它采用两个附加参数,即`fromIndex`(包括)和`toIndex`(排除)。 提供时,数组将在从位置`fromIndex`到位置`toIndex`的指定范围内排序。 给定示例对元素 9 到 18 之间的数组进行排序,即{9,55,47,18}将被排序,其余元素将不会被触摸。 ```java //Unsorted array Integer[] numbers = new Integer[] { 15, 11, 9, 55, 47, 18, 1123, 520, 366, 420 }; //Sort the array Arrays.sort(numbers, 2, 6); //Print array to confirm System.out.println(Arrays.toString(numbers)); ``` 程序输出: ```java [15, 11, 9, 18, 47, 55, 1123, 520, 366, 420] ``` #### 1.4 Java 8 并行排序 Java 8 引入了许多用于并行处理数据集和流的新 API。 一种此类 API 是`Arrays.parallelSort()`。 它将数组分为不同的子数组,并且每个子数组在**不同线程**中以`Arrays.sort()`进行排序。 最终,所有排序的子数组将合并为一个数组。 两个 API 的`parallelSort()`和`sort()`的输出最终将相同。 这只是利用多线程的问题。 ```java Arrays.parallelSort(numbers); Arrays.parallelSort(numbers, 2, 6); Arrays.parallelSort(numbers, Collections.reverseOrder()); ``` ## 2\. 排序列表 可以使用[`Collections.sort()`](https://docs.oracle.com/javase/7/docs/api/java/util/List.html) API 在 Java 中对列表进行排序。 它使用修改后的**归并排序**,并提供有保证的`nlog(n)`性能。 #### 2.1 升序排序列表 ```java //Unsorted list Integer[] numbers = new Integer[] { 15, 11, 9, 55, 47, 18, 1123, 520, 366, 420 }; List<Integer> numbersList = Arrays.asList(numbers); //Sort the list Collections.sort(numbersList); //Print list to confirm System.out.println(numbersList); ``` 程序输出: ```java [9, 11, 15, 18, 47, 55, 366, 420, 520, 1123] ``` #### 2.2 降序排序列表 与数组类似,使用`Collections.reverseOrder()`可以反转默认的排序行为。 ```java //Unsorted list Integer[] numbers = new Integer[] { 15, 11, 9, 55, 47, 18, 1123, 520, 366, 420 }; List<Integer> numbersList = Arrays.asList(numbers); //Sort the list Collections.sort(numbersList, Collections.reverseOrder()); //Print list to confirm System.out.println(numbersList); ``` 程序输出: ```java [1123, 520, 420, 366, 55, 47, 18, 15, 11, 9] ``` ## 3\. 排序集合 不直接支持对 Java 中的集合进行排序。 要对集合进行排序,请按照下列步骤操作: 1. 将集转换为列表。 2. 使用`Collections.sort()` API 排序列表。 3. 将列表转换回集合。 ```java //Unsorted list HashSet<Integer> numbersSet = new LinkedHashSet<>( Arrays.asList(15, 11, 9, 55, 47, 18, 1123, 520, 366, 420) ); List<Integer> numbersList = new ArrayList<Integer>(numbersSet) ; //set -> list //Sort the list Collections.sort(numbersList); numbersSet = new LinkedHashSet<>(numbersList); //list -> set //Print set to confirm System.out.println(numbersSet); ``` 程序输出: ```java [9, 11, 15, 18, 47, 55, 366, 420, 520, 1123] ``` ## 4\. 排序映射 映射是键值对的集合。 因此,映射可以通过两种方式进行排序,即**按键**排序或**按值**排序。 #### 4.1 按键排序映射 按键对映射进行排序的最好,最有效的方法是在`TreeMap`对象中添加所有映射项。 `TreeMap`按键对条目集进行排序。 ```java HashMap<Integer, String> map = new HashMap<>(); map.put(50, "Alex"); map.put(20, "Charles"); map.put(60, "Brian"); map.put(70, "Edwin"); map.put(120, "George"); map.put(10, "David"); TreeMap<Integer, String> treeMap = new TreeMap<>(map); System.out.println(treeMap); ``` 程序输出: ```java {10=David, 20=Charles, 50=Alex, 60=Brian, 70=Edwin, 120=George} ``` #### 4.2 按值排序映射 在 Java 8 中,`Map.Entry`类具有静态方法`compareByValue()`,可帮助您按值排序。 此方法返回一个**比较器**,该比较器以自然顺序比较值上的`Map.Entry`。 ```java HashMap<Integer, String> unSortedMap = new HashMap<>(); unSortedMap.put(50, "Alex"); unSortedMap.put(20, "Charles"); unSortedMap.put(60, "Brian"); unSortedMap.put(70, "Edwin"); unSortedMap.put(120, "George"); unSortedMap.put(10, "David"); //LinkedHashMap preserve the ordering of elements in which they are inserted LinkedHashMap<Integer, String> sortedMap = new LinkedHashMap<>(); unSortedMap.entrySet() .stream() .sorted(Map.Entry.comparingByValue()) .forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue())); System.out.println(sortedMap); ``` 程序输出: ```java {50=Alex, 60=Brian, 20=Charles, 10=David, 70=Edwin, 120=George} ``` ## 5\. 对自定义对象进行排序 自定义对象是**用户定义的类**,它们保存域数据,例如 `Employee`,`Department`,`Account`等。 为了对自定义对象列表进行排序,我们有两种流行的方法,即`Comparable`和`Comparator`。 在给定的示例中,我们将对`Employee`类的实例的集合进行排序。 ```java import java.time.LocalDate; public class Employee implements Comparable<Employee> { private Long id; private String name; private LocalDate dob; public Employee(Long id, String name, LocalDate dob) { super(); this.id = id; this.name = name; this.dob = dob; } @Override public int compareTo(Employee o) { return this.getId().compareTo(o.getId()); } //Getters and Setters @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", dob=" + dob + "]"; } } ``` #### 5.1 `Comparable` [`Comparable`](https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html)接口启用其实现的类的**自然排序**。 它使类与其实例具有可比性。 实现`Comparable`接口的类必须覆盖`compareTo()`方法,在该方法中,它可以指定同一类的两个实例之间的比较逻辑。 可以通过`Collections.sort()`和`Arrays.sort()`自动对实现此接口的对象的列表(和数组)进行排序。 当将实现此接口的对象放入已排序的映射(作为键)或已排序的集合(作为元素)时,将自动对其进行排序。 强烈建议(尽管不是必需的)自然顺序应与`equals`一致。 实际上,所有实现`Comparable`的 Java 核心类都具有与`equals`一致的自然顺序。 ```java ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee(1l, "Alex", LocalDate.of(2018, Month.APRIL, 21))); list.add(new Employee(4l, "Brian", LocalDate.of(2018, Month.APRIL, 22))); list.add(new Employee(3l, "Piyush", LocalDate.of(2018, Month.APRIL, 25))); list.add(new Employee(5l, "Charles", LocalDate.of(2018, Month.APRIL, 23))); list.add(new Employee(2l, "Pawan", LocalDate.of(2018, Month.APRIL, 24))); Collections.sort(list); System.out.println(list); ``` 程序输出: ```java [Employee [id=1, name=Alex, dob=2018-04-21], ] Employee [id=2, name=Pawan, dob=2018-04-24], Employee [id=3, name=Piyush, dob=2018-04-25], Employee [id=4, name=Brian, dob=2018-04-22], Employee [id=5, name=Charles, dob=2018-04-23]] ``` #### 5.2 `Comparator` 很多时候,我们会遇到这样的情况,即由于遗留代码问题,我们不会寻求自然排序或类文件而无法进行编辑。 在这种情况下,我们可以利用[比较器](https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html)接口。 比较器不需要修改该类的源代码。 我们可以在单独的类中创建比较逻辑,以实现`Comparator`接口并覆盖其`compare()`方法。 然后将此比较器以及自定义对象列表传递给`sort()`方法。 例如,在比较器下面,按员工列表的**名称**对其排序。 ```java import java.util.Comparator; public class NameSorter implements Comparator<Employee> { @Override public int compare(Employee e1, Employee e2) { return e1.getName().compareToIgnoreCase( e2.getName() ); } } ``` Java 程序使用`Comparator`接口实现对列表进行排序。 注意在`sort()`方法中使用`NameSorter`作为第二个参数。 ```java ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee(1l, "Alex", LocalDate.of(2018, Month.APRIL, 21))); list.add(new Employee(4l, "Brian", LocalDate.of(2018, Month.APRIL, 22))); list.add(new Employee(3l, "Piyush", LocalDate.of(2018, Month.APRIL, 25))); list.add(new Employee(5l, "Charles", LocalDate.of(2018, Month.APRIL, 23))); list.add(new Employee(2l, "Pawan", LocalDate.of(2018, Month.APRIL, 24))); Collections.sort(list, new NameSorter()); System.out.println(list); ``` 程序输出: ```java [Employee [id=1, name=Alex, dob=2018-04-21], Employee [id=4, name=Brian, dob=2018-04-22], Employee [id=5, name=Charles, dob=2018-04-23], Employee [id=2, name=Pawan, dob=2018-04-24], Employee [id=3, name=Piyush, dob=2018-04-25]] ``` #### 5.3 用 Java 8 Lambda 排序 Java 8 Lambda 表达式有助于即时编写`Comparator`实现。 我们不需要创建单独的类来提供一次性比较逻辑。 ```java Comparator<Employee> nameSorter = (a, b) -> a.getName().compareToIgnoreCase(b.getName()); Collections.sort(list, nameSorter); ``` #### 5.4 分组排序 要使用**链中的多个比较器**对不同字段上的对象集合进行分组排序。 可以使用`Comparator.comparing()`和`Comparator.thenComparing()`方法创建比较器的链接。 例如,我们按姓名对员工列表进行排序,然后再按其年龄进行排序。 ```java ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee(1l, "Alex", LocalDate.of(2018, Month.APRIL, 21))); list.add(new Employee(4l, "Brian", LocalDate.of(2018, Month.APRIL, 01))); list.add(new Employee(3l, "Alex", LocalDate.of(2018, Month.APRIL, 25))); list.add(new Employee(5l, "Charles", LocalDate.of(2018, Month.APRIL, 23))); list.add(new Employee(2l, "Alex", LocalDate.of(2018, Month.APRIL, 30))); Collections.sort(list, Comparator .comparing(Employee::getName) .thenComparing(Employee::getDob)); System.out.println(list); ``` 程序输出: ```java [Employee [id=1, name=Alex, dob=2018-04-21], Employee [id=3, name=Alex, dob=2018-04-25], Employee [id=2, name=Alex, dob=2018-04-30], Employee [id=4, name=Brian, dob=2018-04-01], Employee [id=5, name=Charles, dob=2018-04-23]] ``` ## 6\. 总结 在上面给出的示例中,我们学习了对数组,列表,映射和集合进行排序。 我们看到了用于初始化和使用`Comparator`接口(包括 lambda 表达式)的不同方法。 欢迎分享您对 **Java** 排序的看法。 学习愉快!