文章目录
1. Overview
我总结的 Java中的“比较功能”,涉及如下内容:
- 两个接口:Comparator、Comparable
- 两个方法:compare(T o1, T o2)、compareTo(T o)
- 内置sort方法:Arrays.sort(T[] a)、[instance super collection].sort()
(应用比较功能的一个常见场景 - 升降序判断
- 代码演示
2. 总结
从compare函数说起
- 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
- 包装类:
Byte、Short、Integer、Long、Character、Float、Double、Boolean
compareTo函数 & Comparable接口
- 如果你想让自定义类有比较功能,那就要实现
Comparable
接口,并overwrite其compareTo(T o) : int
方法 - 注意其升降序策略和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
-
函数式接口作为sort的参数,用于扩展sort的功能,主要用在两处:Collections接口和原生数组
例如:
List.sort(Comparator<? super E> c)
Arrays.sort(T[] arr, Comparator<? super T> c) -
Comparator函数式接口只用到函数compare(T o1, T o2) : int,来比较两个相邻元素
o1 < o2 指示负数
o1 == o2 指示0
o1 > o2 指示正数因此返回值可以简记为 sgn(o1 - o2),
sgn(x) 为阶跃信号函数,公式和图像很形象,网上介绍很多啦 -
函数式接口一般用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 方法, 二者不能混淆
升降序判断
- 默认升序ascending
- 对应 默认升序 的code写法是:
- compare(first,second)
- first.attribute - second.attribute
- this.attribute - o.attribute
(就是按从左到右的顺序,从first到second的顺序
(从主属性到参数的顺序
- 对应 降序 的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
---------------------------