Java基础:Collections.sort的两种用法详解

简介: Java基础:Collections.sort的两种用法详解

Collections


sort函数定义


Collections是⼀个⼯具类,sort是其中的静态⽅法,是⽤来对List类型进⾏排序的,它有两种参数形式:


public static <T extends Comparable<? super T>> void sort(List<T> list) { 
  list.sort(null);
}
public static <T> void sort(List<T> list, Comparator<? super T> c) { 
  list.sort(c);
}


基本使用


第一种方法


⾸先使⽤基本类型(此处使⽤Integer)来演示第⼀个⽅法:


static List<Integer> intList = Arrays.asList(2, 3, 1);
private static void sortBaseTypeByDefaultMode() {
    System.out.println("before sort:");
    System.out.println(Arrays.toString(intList.toArray()));
    System.out.println("=========================");
    Collections.sort(intList);
    System.out.println("after sort:");
    System.out.println(Arrays.toString(intList.toArray()));
}
public static void main(String[] args) {
    leetcode.sortBaseTypeByDefaultMode();
}


运行结果如下:



第一种方法


可以看到,默认的排序是正序,那么如何实现逆序呢,这就要使⽤第⼆种⽅式了,即通过实现Comparator接⼝的compare⽅法来完成⾃定义排序,代码如下:


static List<Integer> intList = Arrays.asList(2, 3, 1);
private static void sortBaseTypeByIDefineMode() {
    System.out.println("before sort:");
    System.out.println(Arrays.toString(intList.toArray()));
    System.out.println("=========================");
    Collections.sort(intList, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            // 返回值为int类型,⼤于0表⽰正序,⼩于0表⽰逆序
            return o2 - o1;
        }
    });
    System.out.println("after sort:");
    System.out.println(Arrays.toString(intList.toArray()));
}
public static void main(String[] args) {
// leetcode.sortBaseTypeByDefaultMode();
    leetcode.sortBaseTypeByIDefineMode();
}


可以看到,已经实现了逆序的排序了。


⾃定义类的排序


接下来看看⾃定义类的排序:


定义⼀个Emp类:


public class Emp {
    private int empno;
    private String ename;
    public int getEmpno() {
        return empno;
    }
    public void setEmpno(int empno) {
        this.empno = empno;
    }
    public String getEname() {
        return ename;
    }
    public void setEname(String ename) {
        this.ename = ename;
    }
    public Emp(int empno, String ename) {
        super();
        this.empno = empno;
        this.ename = ename;
    }
    @Override
    public String toString() {
        return "empno:\t" + empno + "\tename:\t" + ename;
    }
}


⾸先使⽤同样的⽅式来使⽤Collections.sort⽅法:


定义泛型违Emp类型的List,使⽤sort⽅法的第⼆种形式:


static List<Emp> empList;
static {
    Emp emp1 = new Emp(2, "Guan YunChang");
    Emp emp2 = new Emp(3, "Zhang Fei");
    Emp emp3 = new Emp(1, "Liu Bei");
    empList = Arrays.asList(emp1, emp2, emp3);
}
private static void sortEmpByIDefineMode() {
    System.out.println("before sort:");
    System.out.println(Arrays.toString(empList.toArray()));
    System.out.println("=========================");
    Collections.sort(empList, new Comparator<Emp>() {
        @Override
        public int compare(Emp o1, Emp o2) {
            /*按员⼯编号正序排序*/
            return o1.getEmpno() - o2.getEmpno();
            /*按员⼯编号逆序排序*/
            //return o2.getEmpno()-o1.getEmpno();
            /*按员⼯姓名正序排序*/
            //return o1.getEname().compareTo(o2.getEname());
            /*按员⼯姓名逆序排序*/
            //return o2.getEname().compareTo(o1.getEname());
        }
    });
    System.out.println("after sort:");
    System.out.println(Arrays.toString(empList.toArray()));
}
public static void main(String[] args) {
//        leetcode.sortBaseTypeByDefaultMode();
//        leetcode.sortBaseTypeByIDefineMode();
    leetcode.sortEmpByIDefineMode();
}


运行结果如下:



那么使用第一种方式能不能行呢,答案是可以的,但是不是直接的使用sort,例如下面是要报错的:


Collections.sort(empList);


我们需要这样做:⾸先让Emp类继承Comparable接⼝并重写compareTo⽅法(为了和上⾯的排序⽅式区别开,此次按照员⼯姓名逆序排列):



@Override
public int compareTo(Emp emp) {
    /*按员⼯编号正序排序*/
    //return this.getEmpno()-emp.getEmpno();
    /*按员⼯编号逆序排序*/
    //return emp.getEmpno()-this.getEmpno();
    /*按员⼯姓名正序排序*/
    //return this.getEname().compareTo(emp.getEname());
    /*按员⼯姓名逆序排序*/
    return emp.getEname().compareTo(this.getEname());
}


main函数中调用方法


private static void sortEmpByIDafaultMode() {
    System.out.println("before sort:");
    System.out.println(Arrays.toString(empList.toArray()));
    System.out.println("=========================");
    Collections.sort(empList);
    System.out.println("after sort:");
    System.out.println(Arrays.toString(empList.toArray()));
}
public static void main(String[] args) {
//        leetcode.sortBaseTypeByDefaultMode();
//        leetcode.sortBaseTypeByIDefineMode();
//        leetcode.sortEmpByIDefineMode();
    leetcode.sortEmpByIDafaultMode();
}


运行结果如下:



总结:


1.对于String或Integer这些已经实现Comparable接⼝的类来说,可以直接使⽤Collections.sort⽅法传⼊list参数来实现默认⽅式(正序)排序;


2.如果不想使⽤默认⽅式(正序)排序,可以通过Collections.sort传⼊第⼆个参数类型为Comparator来⾃定义排序规则;


3.对于⾃定义类型(如本例⼦中的Emp),如果想使⽤Collections.sort的⽅式⼀进⾏排序,可以通过实现Comparable接⼝的compareTo⽅法来进⾏,如果不实现,则参考第2点;


4.jdk1.8的Comparator接⼝有很多新增⽅法,其中有个⽅法⽐较实⽤,是⽤来切换正序和逆序的:reversed(),代码如下:


private static void sortEmpByIDefineMode() {
    System.out.println("before sort:");
    System.out.println(Arrays.toString(empList.toArray()));
    System.out.println("=========================");
    Comparator<Emp> comparator = new Comparator<Emp>() {
        @Override
        public int compare(Emp o1, Emp o2) {
            /*按员⼯编号正序排序*/
            return o1.getEmpno() - o2.getEmpno();
            /*按员⼯编号逆序排序*/
            //return o2.getEmpno()-o1.getEmpno();
            /*按员⼯姓名正序排序*/
            //return o1.getEname().compareTo(o2.getEname());
            /*按员⼯姓名逆序排序*/
            //return o2.getEname().compareTo(o1.getEname());
        }
    };
    /* 新 的 逆 序 实 现 ⽅ 式 */
    Collections.sort(empList, comparator.reversed());
    System.out.println("after sort:");
    System.out.println(Arrays.toString(empList.toArray()));
}


复写的compare⽅法定义的是按员⼯编号正序排序,在使⽤reversed翻转后结果如下:



Comparator是个接⼝,可重写compare()及equals()这两个⽅法,⽤于⽐价功能;如果是null的话,就是使⽤元素的默认顺序,如a,b,c,d,e,f,g,就是a,b,c,d,e,f,g这样,当然数字也是这样的。


compare(a,b)⽅法:根据第⼀个参数⼩于、等于或⼤于第⼆个参数分别返回负整数、零或正整数。


equals(obj)⽅法:仅当指定的对象也是⼀个 Comparator,并且强⾏实施与此 Comparator 相同的排序时才返回 true。


Collections.sort(list, new PriceComparator());的第⼆个参数返回⼀个int型的值,就相当于⼀个标志,告诉sort⽅法按什么顺序来对list进⾏排序。


具体实现代码⽅法如下:


package com.leetcode.www;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.TreeMap;
/**
 * 书实体类
 *
 * @author yjd
 */
public class Book implements Comparable { // 定义名为Book的类,默认继承⾃Object类
    public int id;// 编号
    public String name;// 名称
    public double price; // 价格
    private String author;// 作者
    public GregorianCalendar calendar;// 出版⽇期
    public Book() {
        this(0, "X", 0.0, new GregorianCalendar(), "");
    }
    public Book(int id, String name, double price, GregorianCalendar calender, String author) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.calendar = calender;
        this.author = author;
    }
    // 重写继承⾃⽗类Object的⽅法,满⾜Book类信息描述的要求
    public String toString() {
        String showStr = id + "\t" + name; // 定义显⽰类信息的字符串
        DecimalFormat formatPrice = new DecimalFormat("0.00");// 格式化价格到⼩数点后两位
        showStr += "\t" + formatPrice.format(price);// 格式化价格
        showStr += "\t" + author;
        SimpleDateFormat formatDate = new SimpleDateFormat("yyyy年MM⽉dd⽇");
        showStr += "\t" + formatDate.format(calendar.getTime()); // 格式化时间
        return showStr; // 返回类信息字符串
    }
    public int compareTo(Object obj) {
        // Comparable接⼝中的⽅法
        Book b = (Book) obj;
        return this.id - b.id; // 按书的id⽐较⼤⼩,⽤于默认排序
    }
    public static void main(String[] args) {
        Book b1 = new Book(10000, "红楼梦", 150.86, new GregorianCalendar(2009, 01, 25), "曹雪芹、⾼鄂");
        Book b2 = new Book(10001, "三国演义", 99.68, new GregorianCalendar(2008, 7, 8), "罗贯中 ");
        Book b3 = new Book(10002, "⽔浒传", 100.8, new GregorianCalendar(2009, 6, 28), "施耐庵 ");
        Book b4 = new Book(10003, "西游记", 120.8, new GregorianCalendar(2011, 6, 8), "吴承恩");
        Book b5 = new Book(10004, "天龙⼋部", 10.4, new GregorianCalendar(2011, 9, 23), "搜狐");
        TreeMap tm = new TreeMap();
        tm.put(b1, new Integer(255));
        tm.put(b2, new Integer(122));
        tm.put(b3, new Integer(688));
        tm.put(b4, new Integer(453));
        tm.put(b5, new Integer(40));
        Iterator it = tm.keySet().iterator();
        Object key = null, value = null;
        Book bb = null;
        while (it.hasNext()) {
            key = it.next();
            bb = (Book) key;
            value = tm.get(key);
            System.out.println(bb.toString() + "\t库存:" + tm.get(key));
        }
    }
}



⾃定义⽐较器和测试类:


package com.leetcode.www;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
public class UseComparator {
    public static void main(String args[]) {
        List<Book> list = new ArrayList<Book>(); // 数组序列
        Book b1 = new Book(10000, "红楼梦", 150.86, new GregorianCalendar(2009, 01, 25), "曹雪芹、⾼鄂");
        Book b2 = new Book(10001, "三国演义", 99.68, new GregorianCalendar(2008, 7, 8), "罗贯中 ");
        Book b3 = new Book(10002, "⽔浒传", 100.8, new GregorianCalendar(2009, 6, 28), "施耐庵 ");
        Book b4 = new Book(10003, "西游记", 120.8, new GregorianCalendar(2011, 6, 8), "吴承恩");
        Book b5 = new Book(10004, "天龙⼋部", 10.4, new GregorianCalendar(2011, 9, 23), "搜狐");
        list.add(b1);
        list.add(b2);
        list.add(b3);
        list.add(b4);
        list.add(b5);
        // Collections.sort(list); //没有默认⽐较器,不能排序
        System.out.println(" 数 组 序 列 中 的 元 素 :");
        myprint(list);
        Collections.sort(list, new PriceComparator()); // 根据价格排序
        System.out.println("按书的价格排序:");
        myprint(list);
        Collections.sort(list, new PriceComparator().reversed()); // 根据价格排序
        System.out.println("按书的价格降序排序:");
        myprint(list);
        Collections.sort(list, new CalendarComparator()); // 根据时间排序
        System.out.println("按书的出版时间排序:");
        myprint(list);
    }
    // ⾃定义⽅法:分⾏打印输出list中的元素
    public static void myprint(List<Book> list) {
        Iterator it = list.iterator(); // 得到迭代器,⽤于遍历list中的所有元素
        while (it.hasNext()) {
            // 如果迭代器中有元素,则返回true
            System.out.println("\t" + it.next());// 显⽰该元素
        }
    }
    // ⾃定义⽐较器:按书的价格排序
    static class PriceComparator implements Comparator {
        public int compare(Object object1, Object object2) {// 实现接⼝中的⽅法
            Book p1 = (Book) object1; // 强制转换
            Book p2 = (Book) object2;
            return new Double(p1.price).compareTo(new Double(p2.price));
        }
    }
    // ⾃定义⽐较器:按书出版时间来排序
    static class CalendarComparator implements Comparator {
        public int compare(Object object1, Object object2) {// 实现接⼝中的⽅法
            Book p1 = (Book) object1; // 强制转换
            Book p2 = (Book) object2;
            return p2.calendar.compareTo(p1.calendar);
        }
    }
}



相关文章
|
4月前
|
Java
Java中的equals()与==的区别与用法
【7月更文挑战第28天】
67 12
|
1月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
67 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
23天前
|
存储 安全 Java
深入理解Java中的FutureTask:用法和原理
【10月更文挑战第28天】`FutureTask` 是 Java 中 `java.util.concurrent` 包下的一个类,实现了 `RunnableFuture` 接口,支持异步计算和结果获取。它可以作为 `Runnable` 被线程执行,同时通过 `Future` 接口获取计算结果。`FutureTask` 可以基于 `Callable` 或 `Runnable` 创建,常用于多线程环境中执行耗时任务,避免阻塞主线程。任务结果可通过 `get` 方法获取,支持阻塞和非阻塞方式。内部使用 AQS 实现同步机制,确保线程安全。
|
5月前
|
Java
【Java基础】输入输出流(IO流)
Java基础、输入输出流、IO流、流的概念、输入输出流的类层次结构图、使用 InputStream 和 OutputStream流类、使用 Reader 和 Writer 流类
168 2
|
2月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
2月前
|
Java
Java 正则表达式高级用法
Java 中的正则表达式是强大的文本处理工具,用于搜索、匹配、替换和分割字符串。`java.util.regex` 包提供了 `Pattern` 和 `Matcher` 类来高效处理正则表达式。本文介绍了高级用法,包括使用 `Pattern` 和 `Matcher` 进行匹配、断言(如正向和负向前瞻/后顾)、捕获组与命名组、替换操作、分割字符串、修饰符(如忽略大小写和多行模式)及 Unicode 支持。通过这些功能,可以高效地处理复杂文本数据。
|
2月前
|
存储 Java 数据处理
Java 数组的高级用法
在 Java 中,数组不仅可以存储同类型的数据,还支持多种高级用法,如多维数组(常用于矩阵)、动态创建数组、克隆数组、使用 `java.util.Arrays` 进行排序和搜索、与集合相互转换、增强 for 循环遍历、匿名数组传递以及利用 `Arrays.equals()` 比较数组内容。这些技巧能提升代码的灵活性和可读性,适用于更复杂的数据处理场景。
|
2月前
|
安全 Java
Java switch case隐藏用法
在 Java 中,`switch` 语句是一种多分支选择结构,常用于根据变量值执行不同代码块。除基本用法外,它还有多种进阶技巧,如使用字符串(Java 7 开始支持)、多个 `case` 共享代码块、不使用 `break` 实现 “fall-through”、使用枚举类型、使用表达式(Java 12 及以上)、组合条件以及使用标签等。这些技巧使代码更加简洁、清晰且高效。
|
3月前
|
Java 数据处理
Java IO 接口(Input)究竟隐藏着怎样的神秘用法?快来一探究竟,解锁高效编程新境界!
【8月更文挑战第22天】Java的输入输出(IO)操作至关重要,它支持从多种来源读取数据,如文件、网络等。常用输入流包括`FileInputStream`,适用于按字节读取文件;结合`BufferedInputStream`可提升读取效率。此外,通过`Socket`和相关输入流,还能实现网络数据读取。合理选用这些流能有效支持程序的数据处理需求。
46 2
|
4月前
|
Java
java中return,break以及continue的用法
java中return,break以及continue的用法
47 10