Câu hỏi Java Integer compareTo () - tại sao sử dụng so sánh so với phép trừ?


Tôi đã tìm thấy java.lang.Integer thực hiện compareTo phương thức trông như sau:

public int compareTo(Integer anotherInteger) {
    int thisVal = this.value;
    int anotherVal = anotherInteger.value;
    return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
}

Câu hỏi đặt ra là tại sao sử dụng so sánh thay vì trừ:

return thisVal - anotherVal;

76
2018-04-28 10:59


gốc


Khi chúng tôi quá lo lắng về việc tối ưu hóa vi mô, chúng tôi thường kết thúc bằng mã lỗi. - Kevin Bourrillion
Tính đến JDK 7, người ta có thể sử dụng Integer.compare(thisVal, anotherVal) thay vì viết ra biểu thức thứ ba. - Stuart Marks


Các câu trả lời:


Điều này là do tràn số nguyên. Khi nào thisVal là rất lớn và anotherVal là số âm, sau đó trừ đi giá trị thứ hai từ lợi nhuận trước đó là kết quả lớn hơn thisVal có thể tràn vào phạm vi phủ định.


85
2018-04-28 11:02



Vâng, cách họ đã làm ở đây có lẽ hiệu quả hơn việc kiểm tra tràn và cộng sự - rogerdpack
Sử dụng So sánh ổiChain. Nó rất tiện dụng! google.github.io/guava/releases/22.0/api/docs/com/google/common/… - Andrea Bergonzo
thisVal không cần phải lớn. thisVal có thể bằng 0 và anotherVal được Integer.MIN_VALUE và bạn đã có tràn. Và tâm trí, tất nhiên, nó cũng có thể là cách khác, thisValue rất nhỏ và anotherVal khá lớn, để có khoảng cách tràn ngập int phạm vi giá trị. - Holger


Phép trừ "lừa" để so sánh hai giá trị số bị hỏng !!!

        int a = -2000000000;
        int b =  2000000000;
        System.out.println(a - b);
        // prints "294967296"

Đây, a < b, chưa a - b tích cực.

KHÔNG sử dụng thành ngữ này. Nó không hoạt động.

Hơn thế nữa, ngay cả khi nó hoạt động, nó sẽ KHÔNG PHẢI cung cấp bất kỳ cải thiện đáng kể nào về hiệu suất và thực tế có thể dễ đọc.

Xem thêm

  • Trình gỡ rối Java Câu đố 65: Một Saga kỳ lạ của sự phân loại đáng ngờ

    Câu đố này có một số bài học. Cụ thể nhất là: Không sử dụng phép so sánh dựa trên phép trừ khi bạn chắc chắn rằng sự khác biệt giữa các giá trị sẽ không bao giờ lớn hơn  Integer.MAX_VALUE. Nói chung, hãy cẩn thận int tràn ra. Một bài học khác là bạn nên tránh mã "thông minh". Cố gắng viết mã rõ ràng, chính xác và không tối ưu hóa nó trừ khi nó chứng minh cần thiết.


60
2018-04-28 11:09



Nó không thực sự bị hỏng chút nào. Nếu bạn biết bất cứ điều gì về những con số bạn đang so sánh, có thể bạn sẽ biết rằng họ đang an toàn để so sánh. Thậm chí không biết, chỉ ((long)a - b) nên làm việc. Mặc dù bạn đúng; nó rất hiếm khi hữu ích. - amara
@naiad đang làm ((long)a - b)không giúp đỡ, vì bạn phải đưa kết quả trở lại int, vì đó là những gì mà người so sánh phải trả lại, kết thúc lần nữa với tràn. Bạn sẽ phải làm một cái gì đó như Long.signum về kết quả, rất dễ quên, như bình luận của bạn cho thấy. Và nó thậm chí còn không hiệu quả hơn Integer.compare, mà JVM có thể xử lý nội tại… - Holger


Nói một cách đơn giản, int loại không đủ lớn để lưu trữ sự khác biệt giữa hai tùy ý int giá trị. Ví dụ, sự khác biệt giữa 1,5 tỷ và 1,5 tỷ là 3,0 tỷ, nhưng int không thể giữ giá trị lớn hơn 2,1 tỷ.


9
2018-04-28 12:03





Có lẽ nó là để tránh tràn / tràn.


3
2018-04-28 11:02





Ngoài điều tràn, bạn nên lưu ý rằng phiên bản có chất nền không đưa ra kết quả tương tự.

  • Phiên bản compareTo đầu tiên trả về một trong ba giá trị có thể: -1, 0 hoặc 1.
  • Nếu bạn thay thế dòng cuối cùng bằng chất nền, kết quả có thể là bất kỳ giá trị số nguyên nào.

Nếu bạn biết sẽ không có tràn, bạn có thể sử dụng một cái gì đó như thế này:

public int compareTo(Integer anotherInteger) {
    return sign(this.value - anotherInteger.valuel);
}

1
2018-04-28 13:23



Bạn đúng là kết quả không giống nhau. Nhưng họ không bắt buộc phải! compareTo chỉ được yêu cầu trả lại giá trị âm, 0 hoặc giá trị dương, tùy thuộc vào thứ tự sắp xếp của this và đối tượng khác. Xem java.sun.com/j2se/1.5.0/docs/api/java/lang/… - Christian Semrau