Bootstrap

Java比较总结(compare、Comparable、compareTo、Comparator、sort+Comparator)


1. Overview

我总结的 Java中的“比较功能”,涉及如下内容:

  • 两个接口:Comparator、Comparable
  • 两个方法:compare(T o1, T o2)、compareTo(T o)
  • 内置sort方法:Arrays.sort(T[] a)、[instance super collection].sort()
    (应用比较功能的一个常见场景
  • 升降序判断
  • 代码演示

2. 总结

从compare函数说起

  1. Java为所有包装类都提供了一个静态的方法:compare(T o1,T o2) : int
    (ascending by default)
compare函数:
public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x > y) ? 1 : 0);
	}

comment:
静态static的话使用时就很方便, 例如:Integer.compare(o1, o2)
另外,对o1、o2来说:asc的话返回-1,dec的话返回1,相等返回0
  1. 包装类:
    Byte、Short、Integer、Long、Character、Float、Double、Boolean

compareTo函数 & Comparable接口

  1. 如果你想让自定义类有比较功能,那就要实现Comparable接口,并overwrite其compareTo(T o) : int方法
  2. 注意其升降序策略和compare函数相同(都 return int 嘛),所以在自己overwriting的时候:
  • 推荐用包装类的compare方法
  • 或者用o1.attribute - o2.attribute表示
    (因为这样默认都是升序ascending,
    (想要倒序descending的话就 o2.attribute-o1.attribute
Comparable接口 & compareTo函数:
class myObject implements Comparable<myObject>{
		
		@Override
		public int compareTo(myObject o) {
			// TODO Auto-generated method stub
			
		}
	}

Comparator

  1. 函数式接口作为sort的参数,用于扩展sort的功能,主要用在两处:Collections接口和原生数组

    例如:
    List.sort(Comparator<? super E> c)
    Arrays.sort(T[] arr, Comparator<? super T> c)

  2. Comparator函数式接口只用到函数compare(T o1, T o2) : int,来比较两个相邻元素

    o1 < o2 指示负数
    o1 == o2 指示0
    o1 > o2 指示正数

    因此返回值可以简记为 sgn(o1 - o2),
    sgn(x) 为阶跃信号函数,公式和图像很形象,网上介绍很多啦

  3. 函数式接口一般用lambda表达式来实现,而lambda表达式是java中少有的可以用到类型推导的地方,即在参数中不用声明类型(作用上可类比c++的auto关键字)

    @FunctionalInterface
    public interface Comparator<T>{
    	int compare(T o1, T o2);
    	// ...
    }
    
    // for Arrays
    int[][] intervals = new int[][]{{1, 6}, {3, 5}, {2, 4}};
    Arrays.sort(arr, (c1, c2) -> c1[0] - c2[0]); // 对区间以首个元素升序排序
    Arrays.sort(arr, (c1, c2) -> -(c1[1] - c2[1])); // 对区间以第二个元素降序排序
    
    // for List
    List<List<Integer>> arr = new ArrayList<>();
    // 插入元素 [[0, -2], [1, -3], [2, -4], [3, -5]]
    arr.sort((c1, c2) -> c1.get(0) - c2.get(0)); // 对区间以首个元素升序排序
    arr.sort((c1, c2) -> c2.get(1) - c1.get(1))); // 对区间以第二个元素降序排
    
    // Note
    Arrays.sort 只能对内置数组 T[] arr 来使用,
    Collection接口类,要使用其内部实现的 sort 方法,
    二者不能混淆
    

升降序判断

  1. 默认升序ascending
  2. 对应 默认升序 的code写法是:
  • compare(first,second)
  • first.attribute - second.attribute
  • this.attribute - o.attribute
    (就是按从左到右的顺序,从first到second的顺序
    (从主属性到参数的顺序
  1. 对应 降序 的code写法是:
  • compare(second,first)
  • second.attribute - first.attribute
  • o.attribute - this.attribute
    (默认的顺序反过来

3. code实例:使用sort方法

import java.util.*;

public class Main {
    public static void main(String[] args) {
        testArraySort();
        System.out.println();
        testListSort();
    }

    /**
     * 可以用 Arrays.sort(int[] arr, Comparator c), 这是专门针对内置类型的
     *
     * 可使用Comparator.comparingInt()
     * lambda expression 类型推导,类似auto关键字
     */
    public static void testArraySort() {
        int[][] intervals = new int[][]{{1, 6}, {3, 5}, {2, 4}};
        print(intervals, "initial sequence");

        Arrays.sort(intervals, (int[] a, int[] b) -> a[0] - b[0]); // 默认顺序对应 ascending
        print(intervals, "sort(asc) with 1st option");

        // equally ToIntFunction<? super T> keyExtractor
        // keyExtractor.applyAsInt(element)
        Arrays.sort(intervals, Comparator.comparingInt(a -> -a[0]));
        print(intervals, "sort(desc) with 1st option");

        Arrays.sort(intervals, (a, b) -> a[1] - b[1]); // 反之,descending
        print(intervals, "sort(asc) with 2nd option");

        Arrays.sort(intervals, (a, b) -> b[1] - a[1]); // 反之,descending
        print(intervals, "sort(desc) with 2nd option");
    }

    public static void print(int[][] intervals, String msg){
        System.out.println(msg);
        for(int[] pr: intervals){
            System.out.print(pr[0] + " " + pr[1] + ", ");
        }
        System.out.println();
    }

    /**
     * 二维List要用内置的 [list_instance].sort(Comparator c)
     * 不可以用 Arrays.sort(int[] arr, Comparator c)啦!这是针对内置类型的
     *
     * 可使用Comparator.comparingInt()
     * lambda expression 类型推导,类似auto关键字
     */
    public static void testListSort(){
        List<List<Integer>> arr = new ArrayList<>();
        for(int i=0; i<4; i++){
            arr.add(new ArrayList<>());
            arr.get(i).add(i);
            arr.get(i).add(-(i+2));
        }

        System.out.println("initial sequence");
        System.out.println(arr);

        // lambda expression 类型推导,类似auto关键字
        arr.sort((c1, c2) -> -(c1.get(0) - c2.get(0)));
        System.out.println("sort(desc) using 1st option");
        System.out.println(arr);

        arr.sort(Comparator.comparingInt(c -> -c.get(1)));
        System.out.println("sort(desc) using 2nd option");
        System.out.println(arr);

        arr.sort(Comparator.comparingInt(c -> c.get(1)));
        System.out.println("sort(asc) using 2nd option");
        System.out.println(arr);

        arr.sort((List<Integer> c1, List<Integer> c2) -> c1.get(0) - c2.get(0));
        System.out.println("sort(asc) using 1st option");
        System.out.println(arr);
    }
}

result:

initial sequence
1 6, 3 5, 2 4, 
---------------------------
sort(asc) with 1st option
1 6, 2 4, 3 5, 
sort(desc) with 1st option
3 5, 2 4, 1 6, 
sort(asc) with 2nd option
2 4, 3 5, 1 6, 
sort(desc) with 2nd option
1 6, 3 5, 2 4, 

initial sequence
[[0, -2], [1, -3], [2, -4], [3, -5]]
---------------------------
sort(desc) using 1st option
[[3, -5], [2, -4], [1, -3], [0, -2]]
sort(desc) using 2nd option
[[0, -2], [1, -3], [2, -4], [3, -5]]
sort(asc) using 2nd option
[[3, -5], [2, -4], [1, -3], [0, -2]]
sort(asc) using 1st option
[[0, -2], [1, -3], [2, -4], [3, -5]]

4. code实例:实现comparable接口

1\ 自定义类 实现 Comparable接口

class myObject implements Comparable<myObject>
{
	
	private int balance;
	
	myObject(int a){
		//功能是返回平方数
		balance=a*a;
	}
	
	int getBalance(){
		return balance;
	}

	@Override
	public int compareTo(myObject o) {
		// TODO Auto-generated method stub
		return Integer.compare(this.getBalance(),o.getBalance());
		
		//ascending
	}
}

2\ 一个比较器 Comparator< String > , 比较的是strlength

class lengComp implements Comparator<String>
{

	@Override
	public int compare(String o1, String o2) {
		// TODO Auto-generated method stub
		return o1.length()-o2.length();
		
		//ascending
	}
}

3\ 测试类

public class Client{

	public static void main(String[] args)
	{
		String[] a={"apple","banana","cat","dog"};
		
			for(String i:a)
				System.out.print(i+" ");
			System.out.println("\n---------------------------");
		
		//1 use Arrays.sort([]T, Comparator tmp)  &  Comparator<Object>
		Arrays.sort(a,new lengComp());
		
			for(String i:a)
				System.out.print(i+" ");
			System.out.println("\n---------------------------");
		
		//2 use Arrays.sort([]T)  &  Comparable<Object> impelemented
		myObject[] b= {new myObject(4),new myObject(3),new myObject(1),new myObject(2)};
		
		Arrays.sort(b);
			for(myObject i:b)
				System.out.print(i.getBalance()+" ");
			System.out.println("\n---------------------------");
		
		
		//ues lambda expression!!
		//3.1
		Arrays.sort(b,
				(first,second)-> second.getBalance()-first.getBalance());
		//descending
		
			for(myObject i:b)
				System.out.print(i.getBalance()+" ");
			System.out.println("\n---------------------------");
		
		//3.2
		Arrays.sort(b,(myObject first,myObject second)->
					{
						//test closure:
						System.out.println(a.length);
						//use return clause
						return first.getBalance()-second.getBalance();
						//ascending
					});
		
			for(myObject i:b)
				System.out.print(i.getBalance()+" ");
			System.out.println("\n---------------------------");
			
		//3.3
		Arrays.sort(a,
				(first,second)->(first.compareTo(second)));
		//ascending
			for(String i:a)
				System.out.print(i+" ");
			System.out.println("\n---------------------------");
		
		//3.4
		Arrays.sort(a,
				(first,second)->Integer.compare(first.length(), second.length()));
			for(String i:a)
				System.out.print(i+" ");
			System.out.println("\n---------------------------");

	}	
}

4\ result

apple banana cat dog 
---------------------------
cat dog apple banana 
---------------------------
1 4 9 16 
---------------------------
16 9 4 1 
---------------------------
4
4
4
1 4 9 16 
---------------------------
apple banana cat dog 
---------------------------
cat dog apple banana 
---------------------------
;