本文介紹了為什么比較返回一個整數的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我最近在SO聊天中看到了一次討論,但沒有明確的結論,所以我最終在那里詢問了一下。
這是出于歷史原因還是與其他語言的一致性?當查看各種語言的compareTo
的簽名時,它返回一個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中,枚舉是在這個概念之后引入的(我不記得C#了),但它可以通過一個額外的類來解決,比如:
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);
}
我之所以這樣問,是因為我認為int
不能很好地表示數據的語義。
例如在C#中
l.Sort(delegate(int x, int y)
{
return Math.Min(x, y);
});
及其在Java 8中的孿生兄弟
l.sort(Integer::min);
編譯兩者是因為Min/min
尊重比較器接口的約定(接受兩個int并返回一個int)。
顯然,這兩種情況的結果都不是預期的。如果返回類型為Compare
,則會導致編譯錯誤,從而迫使您實現”正確”行為(或者至少您知道自己在做什么)。
此返回類型丟失了很多語義(并且可能會導致難以找到的錯誤),那么為什么要這樣設計它?
推薦答案
[此答案適用于C#,但在某種程度上可能也適用于JAVA。]
這是出于歷史、性能和可讀性的原因。它可能會在兩個方面提高性能:
-
實現比較的位置。通常,您只需返回”(lhs-rhs)”(如果值是數值類型)。但這可能很危險:請參見下面的內容!
調用代碼可以使用
<=
和>=
來自然地表示對應的比較。與使用枚舉相比,這將使用單個IL(因此使用處理器)指令(盡管有一種方法可以避免枚舉的開銷,如下所述)。
例如,我們可以按如下方式檢查lhs值是否小于或等于rhs值:
if (lhs.CompareTo(rhs) <= 0)
...
使用枚舉,如下所示:
if (lhs.CompareTo(rhs) == CompareResult.LessThan ||
lhs.CompareTo(rhs) == CompareResult.Equals)
...
這顯然可讀性較差,而且效率也很低,因為它要進行兩次比較。您可以通過使用臨時結果來修復低效:
var compareResult = lhs.CompareTo(rhs);
if (compareResult == CompareResult.LessThan || compareResult == CompareResult.Equals)
...
它的可讀性仍然很差,而且它的效率也更低,因為它執行兩個比較操作而不是一個(盡管我坦率地承認,這樣的性能差異很可能不會有什么問題)。
正如raznagul在下面指出的,你實際上可以通過一個比較來做到這一點:
if (lhs.CompareTo(rhs) != CompareResult.GreaterThan)
...
所以您可以使其相當高效–但當然,可讀性仍然會受到影響。... != GreaterThan
不如... <=
清楚
(當然,如果使用枚舉,則無法避免將比較結果轉換為枚舉值的開銷。)
因此,這樣做主要是出于可讀性的原因,但在某種程度上也是出于效率的原因。
最后,正如其他人所提到的,這也是出于歷史原因。像C的strcmp()
和memcmp()
這樣的函數總是返回整數。
匯編比較指令也傾向于以類似的方式使用。
例如,要在x86匯編程序中比較兩個整數,可以這樣做:
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()的返回值的明顯比較。
附錄:
這里有一個例子,它表明使用從LHS中減去RHS的技巧來獲得比較結果并不總是安全的:
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!
顯然,這是因為算術溢出。如果您為生成打開了checked
,則上面的代碼實際上會引發異常。
因此,最好避免使用減法進行比較的優化。(參見下面Eric Lippert的評論。)
這篇關于為什么比較返回一個整數的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,