## Collections

java.util.Collections是集合工具类,可以对集合进行多种操作。

注意,工具类的大多方法都是静态方法,通过类名.方法直接使用!

常用功能

方法

描述

boolean addAll(Collection c, T... elements)

将所有指定的元素添加到指定的集合

void shuffle(List<?> list)

打乱集合顺序

void sort(List list)

将集合中元素按照默认规则排序(一般为升序)

void sort(List list,Comparator<? super T> )

将集合中元素按照指定规则排序。

测试代码

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

public class TestCollections {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        // 可变参数添加多个元素
        // public static <T> boolean addAll(Collection<? super T> c, T... elements)
        Collections.addAll(list, 3, 2, 1, 0, 4, 5);
        System.out.println("初始数据" + list);
        // 打乱顺序的方法shuffle
        Collections.shuffle(list);
        System.out.println("乱序数据" + list);
        // 默认按升序排序
        Collections.sort(list);
        System.out.println("默认排序" + list);
        // 自定义排序
        Collections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                // 前减后升序,后减前降序
                return o2 - o1;
            }
        });
        System.out.println("降序排序" + list);
    }
}

运行结果

初始数据[3, 2, 1, 0, 4, 5]
乱序数据[1, 2, 4, 5, 3, 0]
默认排序[0, 1, 2, 3, 4, 5]
降序排序[5, 4, 3, 2, 1, 0]

注意:sort方法使用的前提,list存储的元素必须实现比较器。

比较器

Java中提供了两种比较实现的方式

  • java.lang.Comparable 接口
  • java.util.Comparator 接口

Comparator

排序是comparator能实现的功能之一,比较器具有可比性!

顾名思义就是做排序的,通俗地讲需要比较两个对象谁排在前谁排在后,那么比较的方法就是:

public int compare(String o1, String o2) :比较其两个参数的顺序。

两个对象比较的结果有三种:大于,等于,小于。

  • 升序 :o1 - o2
  • 降序: o2 - o1

在前面的例子中,自定义排序时,创建了一个匿名的比较器对象。

这里将Comparator 理解为外部比较器,灵活多变,可以自己编写多种规则,而且还满足Lambda表达式

Collections.sort(list, new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        // 前减后升序,后减前降序
        return o2 - o1;
    }
});
// 将以上代码改写成lambda表达式,传入两个参数,返回后者减前者的值
Collections.sort(list, (o1, o2) -> o2 - o1);

Comparable

在之前的排序,都是Java封装好的Integer类型或String类型,自己编写的实体类能否通过某些属性排序呢

比如下面的Student类,包含学号、姓名、年龄三个字段,如何实现按年龄排序呢?

Student.java

public class Student {
    private int id;
    private String name;
    private int age;

    public Student() {
    }

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

测试代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestComparable {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student(1001, "张三", 18));
        list.add(new Student(1002, "李四", 17));
        list.add(new Student(1003, "王五", 19));
        list.add(new Student(1004, "赵六", 18));
        list.add(new Student(1005, "钱七", 18));
        System.out.println("原列表的数据:\n" + list);
        // 在没有实现自定义比较器时会报错
        Collections.sort(list);
        System.out.println("排序后的数据:\n" + list);
    }
}

java的集合如何按排序并分组_比较器

直接报错,List集合中存储的是一些学生对象,如何通过某个字段比较呢?

这个报错说Student类不是Comparable的子类,意味着缺少了比较器,无法比较!

解决方案

  1. 用之前学的外部比较器comparator,自己编写比较规则,灵活多变
Collections.sort(list, new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getAge() - o2.getAge();
    }
});

// lambda
Collections.sort(list, (o1, o2)->o1.getAge() - o2.getAge());
  1. 实现内部比较器Comparable接口,编写默认规则
public class Student implements Comparable<Student>{
    private int id;
    private String name;
    private int age;

    public Student() {
    }

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

	// ...中间get/set代码省略

    @Override
    public int compareTo(Student o) {
        return this.getAge() - o.getAge();
    }
}

在Student类上实现了Comparable接口,并重写了compareTo方法,这个方法与前面外部比较器的compare方法非常相似,

只不过compareTo方法只传入了一个参数,用this对象本身与传进来的对象比较。

小口诀:前减后,默认升序

在修改代码之后,继续测试排序功能

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestComparable {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student(1001, "张三", 18));
        list.add(new Student(1002, "李四", 17));
        list.add(new Student(1003, "王五", 19));
        list.add(new Student(1004, "赵六", 18));
        list.add(new Student(1005, "钱七", 18));
        System.out.println("原列表的数据:\n" + list);
        // 在没有实现自定义比较器时会报错
        Collections.sort(list);
        System.out.println("排序后的数据:\n" + list);
    }
}

运行结果

原列表的数据:
[Student{id=1001, name='张三', age=18}, Student{id=1002, name='李四', age=17}, Student{id=1003, name='王五', age=19}, Student{id=1004, name='赵六', age=18}, Student{id=1005, name='钱七', age=18}]
排序后的数据:
[Student{id=1002, name='李四', age=17}, Student{id=1001, name='张三', age=18}, Student{id=1004, name='赵六', age=18}, Student{id=1005, name='钱七', age=18}, Student{id=1003, name='王五', age=19}]

得到的结果确实是按照年龄从小到大排序的顺序。

比较器的实际运用

需求:首先按学生的年龄升序排序,在年龄相同的情况下,再按学号降序排序

  • 主排序:年龄 升
  • 次排序:学号 降

这时候可以修改默认的内部比较器,但是会影响到以后的默认排序。

所以编写外部比较器,仅用一次。

// 先通过年龄升序排序,年龄相等时再通过学号降序排序
Collections.sort(list, new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        int res = o1.getAge() - o2.getAge();
        if (res == 0) {
            res = o2.getId() - o1.getId();
        }
        return res;
    }
});
// lambda ,如果年龄相等返回id比较,否则返回年龄比较
Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge() == 0 ? o2.getId() - o1.getId() : o1.getAge() - o2.getAge());

两者区别

Comparable(内部排序)

  • int compareTo(Object obj); 自己和别的对象比较
  • 默认升序排序

Comparator(外部排序)

  • int compare(Object ob1,Object obj2); 两个对象比较
  • 排序灵活