## 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);
}
}
直接报错,List集合中存储的是一些学生对象,如何通过某个字段比较呢?
这个报错说Student类不是Comparable的子类,意味着缺少了比较器,无法比较!
解决方案
- 用之前学的外部比较器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());
- 实现内部比较器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); 两个对象比较
- 排序灵活