不灭的焱

革命尚未成功,同志仍须努力下载JDK17

作者:Albert.Wen  添加时间:2019-02-18 23:01:21  修改时间:2024-05-19 02:10:10  分类:Java基础  编辑

一、List接口中sort方法

首先来看一下List接口中的sort()方法

从这个描述我们可以看到,我们可以根据具体的Comparator对List结合中的元素进行排序,如果传入的comparator是null的时候,那么集合中的元素必须实现Comparable接口实现自然排序。从上面的一段话我们知道List集合对元素排序的方法有以下两种

方法 方法描述
方法一 List中的元素自己实现一个Comparable接口实现一个自然排序
方法二 我们通过传入一个实现了Comparator接口实现一个排序

顺便提一句:对于集合的排序算法,底层使用的是MergeSort

二、代码实现

2.1、List中的元素自己实现一个Comparable接口实现一个自然排序

这里我实现对Person 中age这个字段进行排序

package CollectionLearn;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * List排序
 */
public class SortList {
    private List<Person> list = new ArrayList<Person>();

    private Person p1 = new Person(2,"name1");
    private Person p2 = new Person(3,"name3");
    private Person p3 = new Person(1,"name4");
    private Person p4 = new Person(4,"name2");


    @Test
    public void testCommonType_I(){
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        list.sort(null); // 传入的Comparator=null,实现自然排序
        
        // 遍历集合
        list.forEach(item->{
            System.out.println(item.toString());
        });
    }
}

class Person implements Comparable{
    int age;
    String name;

    public Person(){};
    public Person(int age,String name){
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        Person p = (Person)o;
        
        if(this.getAge()-p.getAge()<0){
            return -1;
        }

        if(this.getAge()-p.getAge()>0){
            return 1;
        }

        return 0;
    }
}

输出结果:

Person{age=1, name='name4'}
Person{age=2, name='name1'}
Person{age=3, name='name3'}
Person{age=4, name='name2'}

如果Person对象没有实现Comparable接口,那么就会抛出下面的异常:

java.lang.ClassCastException: CollectionLearn.Person cannot be cast to java.lang.Comparable

    at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320)
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:188)
    at java.util.Arrays.sort(Arrays.java:1312)
    at java.util.Arrays.sort(Arrays.java:1506)
    at java.util.ArrayList.sort(ArrayList.java:1460)

2.2、我们通过实现一个Comparator接口的类对Person对象进行排序

/**
 * 用户名 比较器
 */
class PersonNameComparator implements Comparator<Person>{

    @Override
    public int compare(Person o1, Person o2) {
        return o1.compareTo(o2);
    }
}

测试代码:

@Test
public void testCommonType_II() {
    list.add(p1);
    list.add(p2);
    list.add(p3);
    list.add(p4);
    list.sort(new PersonNameComparator());
    
    // 遍历集合
    list.forEach(item->{
        System.out.println(item.toString());
    });
}

 

注意:List排序可以直接采用Collections的sort()方法,也可以使用Arrays的sort()方法,归根结底Collections就是调用Arrays的sort()方法。

@Test
public void testCommonType_II() {
    list.add(p1);
    list.add(p2);
    list.add(p3);
    list.add(p4);
    Collections.sort(list, new PersonNameComparator());
     
    // 遍历集合
    list.forEach(item->{
        System.out.println(item.toString());
    });
}

三、多维度(多字段)排序

有了上述基础后,实现多维度(多字段)排序就非常简单了,举例如下:

1、实体类

package CollectionLearn;
 
/**
 * 学生 实体类
 */
public class Student {
    /**
     * 学号
     */
    int id ;
    
    /**
     * 分数
     */
    int score;
 
    public Student(int id, int score) {
        this.id = id;
        this.score = score;
    }
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public int getScore() {
        return score;
    }
 
    public void setScore(int score) {
        this.score = score;
    }
}

2、实现Comparator接口

package CollectionLearn;
  
import java.util.Comparator;
 
/**
 * 通过实现Comparator接口对List集合进行多维度排序
 * 举例:对学生的成绩进行排名,成绩相同的按照学号大小排序
 */
public class SortUtilForList implements Comparator<Student> {
 
    /**
     * 为学生进行排名
     *
     * @param o1
     * @param o2
     * @return
     */
    @Override
    public int compare(Student o1, Student o2) {
        if (o1 instanceof Student){
            if (o1.getScore() != o2.getScore()) {
                // 如果学生的分数不同,按照分数进行排名
                return compareWithScore(o1.getScore(), o2.getScore());
            } else {
                // 如果学生的分数相同按照学号进行排名
                return compareWithId(o1.getId(), o2.getId());
            }
        }
        return 0;
    }
 
    /**
     * 通过学生的学号进行排序(降序)
     *
     * @param id1
     * @param id2
     * @return
     */
    private int compareWithId(int id1, int id2) {
        if (id1 > id2) {
            return -1;
        }
        return 1;
    }
 
    /**
     * 通过学生的分数进行排序(降序)
     *
     * @param score1
     * @param score2
     * @return
     */
    private int compareWithScore(int score1, int score2) {
        if (score1 > score2) {
            return -1;
        }
        return 1;
    }
}

3、测试

package CollectionLearn;
 
import Student;
import org.junit.Test;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
 
import static org.junit.Assert.*;
 
public class SortUtilForListTest {
 
    @Test
    public void testCompare() throws Exception {
        SortUtilForList sortUtilForList = new SortUtilForList();
        List<Student> students = new ArrayList<Student>();
        students.add(new Student(1, 88));
        students.add(new Student(3, 98));
        students.add(new Student(4, 88));
        students.add(new Student(2, 78));
        students.add(new Student(6, 68));
        students.add(new Student(5, 88));
        Collections.sort(students, sortUtilForList);
        students.toString();
    }
}