本文介紹了為什么比較返回一個(gè)整數(shù)的處理方法,對(duì)大家解決問(wèn)題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧!
問(wèn)題描述
我最近在SO聊天中看到了一次討論,但沒(méi)有明確的結(jié)論,所以我最終在那里詢(xún)問(wèn)了一下。
這是出于歷史原因還是與其他語(yǔ)言的一致性?當(dāng)查看各種語(yǔ)言的compareTo
的簽名時(shí),它返回一個(gè)int
。
為什么它不返回枚舉。例如,在C#中我們可以這樣做:
enum CompareResult {LessThan, Equals, GreaterThan};
和:
public CompareResult CompareTo(Employee other) {
if (this.Salary < other.Salary) {
return CompareResult.LessThan;
}
if (this.Salary == other.Salary){
return CompareResult.Equals;
}
return CompareResult.GreaterThan;
}
在Java中,枚舉是在這個(gè)概念之后引入的(我不記得C#了),但它可以通過(guò)一個(gè)額外的類(lèi)來(lái)解決,比如:
public final class CompareResult {
public static final CompareResult LESS_THAN = new Compare();
public static final CompareResult EQUALS = new Compare();
public static final CompareResult GREATER_THAN = new Compare();
private CompareResult() {}
}
和
interface Comparable<T> {
Compare compareTo(T obj);
}
我之所以這樣問(wèn),是因?yàn)槲艺J(rèn)為int
不能很好地表示數(shù)據(jù)的語(yǔ)義。
例如在C#中
l.Sort(delegate(int x, int y)
{
return Math.Min(x, y);
});
及其在Java 8中的孿生兄弟
l.sort(Integer::min);
編譯兩者是因?yàn)?code>Min/min尊重比較器接口的約定(接受兩個(gè)int并返回一個(gè)int)。
顯然,這兩種情況的結(jié)果都不是預(yù)期的。如果返回類(lèi)型為Compare
,則會(huì)導(dǎo)致編譯錯(cuò)誤,從而迫使您實(shí)現(xiàn)”正確”行為(或者至少您知道自己在做什么)。
此返回類(lèi)型丟失了很多語(yǔ)義(并且可能會(huì)導(dǎo)致難以找到的錯(cuò)誤),那么為什么要這樣設(shè)計(jì)它?
推薦答案
[此答案適用于C#,但在某種程度上可能也適用于JAVA。]
這是出于歷史、性能和可讀性的原因。它可能會(huì)在兩個(gè)方面提高性能:
-
實(shí)現(xiàn)比較的位置。通常,您只需返回”(lhs-rhs)”(如果值是數(shù)值類(lèi)型)。但這可能很危險(xiǎn):請(qǐng)參見(jiàn)下面的內(nèi)容!
調(diào)用代碼可以使用
<=
和>=
來(lái)自然地表示對(duì)應(yīng)的比較。與使用枚舉相比,這將使用單個(gè)IL(因此使用處理器)指令(盡管有一種方法可以避免枚舉的開(kāi)銷(xiāo),如下所述)。
例如,我們可以按如下方式檢查lhs值是否小于或等于rhs值:
if (lhs.CompareTo(rhs) <= 0)
...
使用枚舉,如下所示:
if (lhs.CompareTo(rhs) == CompareResult.LessThan ||
lhs.CompareTo(rhs) == CompareResult.Equals)
...
這顯然可讀性較差,而且效率也很低,因?yàn)樗M(jìn)行兩次比較。您可以通過(guò)使用臨時(shí)結(jié)果來(lái)修復(fù)低效:
var compareResult = lhs.CompareTo(rhs);
if (compareResult == CompareResult.LessThan || compareResult == CompareResult.Equals)
...
它的可讀性仍然很差,而且它的效率也更低,因?yàn)樗鼒?zhí)行兩個(gè)比較操作而不是一個(gè)(盡管我坦率地承認(rèn),這樣的性能差異很可能不會(huì)有什么問(wèn)題)。
正如raznagul在下面指出的,你實(shí)際上可以通過(guò)一個(gè)比較來(lái)做到這一點(diǎn):
if (lhs.CompareTo(rhs) != CompareResult.GreaterThan)
...
所以您可以使其相當(dāng)高效–但當(dāng)然,可讀性仍然會(huì)受到影響。... != GreaterThan
不如... <=
清楚
(當(dāng)然,如果使用枚舉,則無(wú)法避免將比較結(jié)果轉(zhuǎn)換為枚舉值的開(kāi)銷(xiāo)。)
因此,這樣做主要是出于可讀性的原因,但在某種程度上也是出于效率的原因。
最后,正如其他人所提到的,這也是出于歷史原因。像C的strcmp()
和memcmp()
這樣的函數(shù)總是返回整數(shù)。
匯編比較指令也傾向于以類(lèi)似的方式使用。
例如,要在x86匯編程序中比較兩個(gè)整數(shù),可以這樣做:
CMP AX, BX ;
JLE lessThanOrEqual ; jump to lessThanOrEqual if AX <= BX
或
CMP AX, BX
JG greaterThan ; jump to greaterThan if AX > BX
或
CMP AX, BX
JE equal ; jump to equal if AX == BX
您可以看到與CompareTo()的返回值的明顯比較。
附錄:
這里有一個(gè)例子,它表明使用從LHS中減去RHS的技巧來(lái)獲得比較結(jié)果并不總是安全的:
int lhs = int.MaxValue - 10;
int rhs = int.MinValue + 10;
// Since lhs > rhs, we expect (lhs-rhs) to be +ve, but:
Console.WriteLine(lhs - rhs); // Prints -21: WRONG!
顯然,這是因?yàn)樗阈g(shù)溢出。如果您為生成打開(kāi)了checked
,則上面的代碼實(shí)際上會(huì)引發(fā)異常。
因此,最好避免使用減法進(jìn)行比較的優(yōu)化。(參見(jiàn)下面Eric Lippert的評(píng)論。)
這篇關(guān)于為什么比較返回一個(gè)整數(shù)的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,