Java?中的排序Comparable?與?Comparator?的使用與區(qū)別對(duì)比解析
1. 背景
在 Java 中,如果我們希望自定義類能夠進(jìn)行排序(例如在集合、數(shù)組中排序),就需要定義對(duì)象的比較規(guī)則。
Java 提供了兩種方式:
Comparable<T>接口 → 在類內(nèi)部實(shí)現(xiàn),定義對(duì)象的“自然順序”。Comparator<T>接口 → 在類外部定義比較器,可以靈活指定不同的排序規(guī)則。
2.Comparable接口
Java 中很多常用類都實(shí)現(xiàn)了 Comparable 接口,例如 String、Integer。
public class CompareToDemo {
public static void main(String[] args) {
// String 按字典序比較
System.out.println("apple".compareTo("banana")); // -1
System.out.println("dog".compareTo("dog")); // 0
System.out.println("zoo".compareTo("apple")); // 正數(shù)
// Integer 按數(shù)值大小比較
Integer a = 10, b = 20;
System.out.println(a.compareTo(b)); // -1
System.out.println(b.compareTo(a)); // 1
System.out.println(a.compareTo(10));// 0
}
}2.1 定義
public interface Comparable<T> {
int compareTo(T o);
}
2.2 返回值含義
- 負(fù)數(shù):當(dāng)前對(duì)象 < 參數(shù)對(duì)象
- 0:當(dāng)前對(duì)象 == 參數(shù)對(duì)象
- 正數(shù):當(dāng)前對(duì)象 > 參數(shù)對(duì)象
2.3 使用場(chǎng)景
當(dāng)一個(gè)類本身就有固定的“自然排序規(guī)則”,可以直接實(shí)現(xiàn) Comparable。
3.Comparator接口
3.1 定義
public interface Comparator<T> {
int compare(T o1, T o2);
}3.2 返回值含義
與 Comparable 相同:
- 負(fù)數(shù) → o1 < o2
- 0 → o1 == o2
- 正數(shù) → o1 > o2
3.3 使用場(chǎng)景
當(dāng)我們不想修改類本身,或者需要定義多種排序規(guī)則時(shí),使用 Comparator 更靈活。
4.ComparablevsComparator區(qū)別表
| 特性 | Comparable | Comparator |
|---|---|---|
| 方法 | int compareTo(T o) | int compare(T o1, T o2) |
| 定義位置 | 類 內(nèi)部(實(shí)現(xiàn)接口) | 類 外部(單獨(dú)寫比較器) |
| 排序規(guī)則數(shù)量 | 一種(自然順序) | 多種(可定義多個(gè) Comparator) |
| 修改類代碼需求 | 需要修改類本身 | 不需要修改類本身 |
| 常見(jiàn)使用場(chǎng)景 | Collections.sort(list) | Collections.sort(list, comparator) |
5. Comparable 與 Comparator的使用示例:對(duì)List<Student>按age排序
5.1 使用Comparable
class Student implements Comparable<Student> {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 定義“自然順序”:按年齡升序
@Override
public int compareTo(Student other) {
return Integer.compare(this.age, other.age);
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
public class ComparableDemo {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student("Alice", 22));
list.add(new Student("Bob", 18));
list.add(new Student("Charlie", 20));
// 使用 Comparable 定義的 compareTo 方法排序
Collections.sort(list);
System.out.println(list);
// 輸出: [Bob(18), Charlie(20), Alice(22)]
}
}5.2 使用Comparator
如果我們不想修改 Student 類,或者想要不同的排序規(guī)則,可以使用 Comparator。
方式一:匿名內(nèi)部類
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return Integer.compare(s1.getAge(), s2.getAge());
}
});
方式二:Lambda 表達(dá)式(Java 8+推薦)
list.sort((s1, s2) -> Integer.compare(s1.getAge(), s2.getAge()));
方式三:方法引用(更簡(jiǎn)潔)
list.sort(Comparator.comparing(Student::getAge));
?? 輸出結(jié)果同樣是:
[Bob(18), Charlie(20), Alice(22)]
6. 多條件排序(進(jìn)階)
6.1使用Comparator實(shí)現(xiàn)多條件排序
使用 Comparator 時(shí),可以輕松實(shí)現(xiàn)多條件排序。
例如:先按年齡升序,再按名字字母序升序
//方式一、方法引用 + 鏈?zhǔn)?Comparator
list.sort(
Comparator.comparing(Student::getAge)
.thenComparing(Student::getName)
);
//方式二、匿名內(nèi)部類寫法
list.sort(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 先按年齡排序
int result = Integer.compare(s1.getAge(), s2.getAge());
// 如果年齡相同,則按姓名排序
if (result == 0) {
result = s1.getName().compareTo(s2.getName());
}
return result;
}
});
//方式三、Lambda 表達(dá)式寫法(Java 8+ 推薦)
list.sort((s1, s2) -> {
int result = Integer.compare(s1.getAge(), s2.getAge());
if (result == 0) {
result = s1.getName().compareTo(s2.getName());
}
return result;
});6.2 那是不是不能使用Comparable完成多條件呢?
1??Comparable的特點(diǎn)
Comparable是 自然排序(對(duì)象自己規(guī)定的排序規(guī)則)。- 一個(gè)類 只能實(shí)現(xiàn)一次
compareTo方法,也就是說(shuō)只能有一種排序邏輯。 - 例子:
public class Student implements Comparable<Student> {
private int age;
private String name;
@Override
public int compareTo(Student other) {
// 先按年齡,再按姓名
int result = Integer.compare(this.age, other.age);
if (result == 0) {
result = this.name.compareTo(other.name);
}
return result;
}
}?? 這樣就能實(shí)現(xiàn) 多條件排序,但限制是 Student 這個(gè)類就被固定死了,始終用這一套排序規(guī)則(先按年齡升序,再按名字字母序升序),如果后續(xù)想先按照名字字母就要改這個(gè)compareTo方法。
2??Comparator的特點(diǎn)
Comparator是 外部比較器,不修改實(shí)體類本身。- 可以定義多個(gè)不同的排序規(guī)則,根據(jù)需要隨時(shí)切換。
- 例子(用的上面使用
Comparator實(shí)現(xiàn)多條件排序的方式一):
Comparator<Student> byAgeThenName =
Comparator.comparing(Student::getAge)
.thenComparing(Student::getName);
Comparator<Student> byNameThenAge =
Comparator.comparing(Student::getName)
.thenComparing(Student::getAge);?? 這樣一個(gè)類(Student)就可以有 多種排序方式,靈活性更高。
3?? 多條件的對(duì)比
- Comparable:類內(nèi)部定義,固定一種排序邏輯(可以寫多條件,但只能有這一種)。
- Comparator:類外部定義,可以有多種排序邏輯,靈活組合,推薦用于多條件排序。
?? 這樣就能實(shí)現(xiàn) 多條件排序,但限制是 Student 這個(gè)類就被固定死了,始終用這一套排序規(guī)則。
? 多條件排序,Comparable 也能實(shí)現(xiàn)(在 compareTo 里寫多條件邏輯)。
? 但是 Comparable 只能有這一種排序方式,靈活性差。
?? 真正業(yè)務(wù)里,一般 多條件排序都會(huì)用 Comparator。
7. 總結(jié)
Comparable:讓類具備自然排序能力,適合“唯一固定規(guī)則”的場(chǎng)景。Comparator:外部比較器,適合需要定義多種排序規(guī)則的場(chǎng)景。- 對(duì)于
List<Student>: - 如果
Student類實(shí)現(xiàn)了Comparable,直接用Collections.sort(list)。 - 如果不想改
Student類,可以用Comparator方式排序。
- 對(duì)于
- 推薦使用
Comparator.comparing(...)+ Lambda/方法引用,更簡(jiǎn)潔靈活。
到此這篇關(guān)于java--Java 中的排序:Comparable 與 Comparator 的使用與區(qū)別的文章就介紹到這了,更多相關(guān)java Comparable 與 Comparator使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中Comparator與Comparable排序的區(qū)別詳解
- Java排序之Comparable和Comparator比較器詳解
- Java去重排序之Comparable與Comparator的使用及說(shuō)明
- java中實(shí)現(xiàn)對(duì)象排序的兩種方法(Comparable,Comparator)
- java?集合工具類Collections及Comparable和Comparator排序詳解
- Java元素排序Comparable與Comparator的區(qū)別
- java中元素排序Comparable和Comparator的區(qū)別
- 對(duì)比Java中的Comparable排序接口和Comparator比較器接口
相關(guān)文章
Java API學(xué)習(xí)教程之正則表達(dá)式詳解
正則表達(dá)式的強(qiáng)大眾所周知,它令程序員的頭痛程度也數(shù)一數(shù)二的。下面這篇文章主要給大家介紹了關(guān)于Java API學(xué)習(xí)教程之正則表達(dá)式的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-07-07
Java全局異常處理器實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了Java全局異常處理器實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
Spring中網(wǎng)絡(luò)請(qǐng)求客戶端WebClient的使用詳解
作為替代,Spring 官方已在 Spring 5 中引入了 WebClient 作為非阻塞式 Reactive HTTP 客戶端,本文將通過(guò)樣例演示如何使用 WebClient,希望對(duì)大家有所幫助2024-04-04
Java基于HttpClient實(shí)現(xiàn)RPC的示例
HttpClient可以實(shí)現(xiàn)使用Java代碼完成標(biāo)準(zhǔn)HTTP請(qǐng)求及響應(yīng)。本文主要介紹了Java基于HttpClient實(shí)現(xiàn)RPC,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
使用Spring boot標(biāo)記一個(gè)方法過(guò)時(shí)
這篇文章主要介紹了使用Spring boot標(biāo)記一個(gè)方法過(guò)時(shí),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
解析Oracle數(shù)據(jù)庫(kù)中的對(duì)象集合schema
這篇文章主要介紹了Oracle數(shù)據(jù)庫(kù)中的對(duì)象集合schema,是Oracle數(shù)據(jù)庫(kù)入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-11-11
IDEA?Error:java:無(wú)效的源發(fā)行版:13的解決過(guò)程
之前用idea運(yùn)行時(shí),也會(huì)出現(xiàn)這種情況,后面通過(guò)網(wǎng)上的資料解決了這個(gè)問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于IDEA?Error:java:無(wú)效的源發(fā)行版:13的解決過(guò)程,需要的朋友可以參考下2023-01-01
Java線程讓步_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
yield()的作用是讓步。它能讓當(dāng)前線程由“運(yùn)行狀態(tài)”進(jìn)入到“就緒狀態(tài)”,從而讓其它具有相同優(yōu)先級(jí)的等待線程獲取執(zhí)行權(quán)。下面通過(guò)本文給大家介紹Java線程讓步的相關(guān)知識(shí),需要的朋友參考下吧2017-05-05
VSCode?配置?Spring?Boot?項(xiàng)目開(kāi)發(fā)環(huán)境的全過(guò)程
兩三年前曾經(jīng)試過(guò)配置Java環(huán)境, 存在不少問(wèn)題作罷. 最近搜了下相關(guān)的文章, 感覺(jué)VSCode對(duì)Java項(xiàng)目的支持比三年前完善了不少. 今天實(shí)際配置了一下環(huán)境, 把自己常用的功能過(guò)了一遍, 基本能跑通開(kāi)發(fā)流程, 做個(gè)筆記,需要的朋友可以參考下2024-03-03

