2009-03-03 32 views
17

Tôi có một lớp, mà tôi đã đơn giản hóa như sau:Tại sao bộ so sánh đơn giản của tôi bị hỏng?

final class Thing { 
    private final int value; 
    public Thing(int value) { 
     this.value = value; 
    } 
    public int getValue() { 
     return value; 
    } 
    @Override public String toString() { 
     return Integer.toString(value); 
    } 
} 

Tôi muốn sắp xếp một mảng của điều này. Vì vậy, tôi đã tạo một máy copmarator đơn giản:

private static final Comparator<Thing> reverse = new Comparator<Thing>() { 
    public int compare(Thing a, Thing b) { 
     return a.getValue() - b.getValue(); 
    } 
}; 

Tôi sau đó sử dụng hai loại đối số là Arrays.sort.

Điều này làm việc tốt cho các trường hợp thử nghiệm của tôi, nhưng đôi khi nó đi sai với mảng kết thúc theo một thứ tự kỳ lạ nhưng có thể lặp lại. Làm thế nào điều này có thể?

+0

Tìm mọi cách sai? – MarkusQ

+0

Đó là câu đố! – erickson

Trả lời

20

tràn số nguyên & hellip; hoặc chính xác hơn, tràn.

Thay vào đó, làm một sự so sánh rõ ràng:

private static final Comparator<Thing> reverse = new Comparator<Thing>() { 
    public int compare(Thing a, Thing b) { 
     int av = a.getValue(), bv = b.getValue(); 
     return (av == bv) ? 0 : ((av < bv) ? -1 : +1); 
    } 
}; 

Sử dụng phép trừ là tốt nếu bạn chắc chắn rằng sự khác biệt sẽ không "quấn xung quanh". Ví dụ: khi các giá trị được đề cập bị ràng buộc là không âm.

15

Bạn không thể sử dụng dấu trừ để tạo so sánh. Bạn sẽ tràn khi chênh lệch tuyệt đối vượt quá Integer.MAX_VALUE.

Thay vào đó, sử dụng thuật toán này:

int compareInts(int x, int y) { 
    if (x < y) return -1; 
    if (x > y) return 1; 
    return 0; 
} 

Tôi muốn có chức năng này trong một thư viện cho các mục đích như vậy.

+0

Trong giây lát, tôi sẽ chỉ cho bạn phương pháp tĩnh trong Integer. Nhưng nó không có ở đó ... –

+1

@Tom: 'Integer.valueOf (x) .compareTo (y);' là cách ngắn gọn nhất mà tôi có thể nghĩ đến. Strange cách Double có phương thức 'compare()' tĩnh và các kiểu số khác thì không. – Grundlefleck

+2

@Grundlefleck: Đúng vậy! Nhưng tất nhiên phương pháp của tôi là nhanh hơn nhiều để thực thi vì nó không tạo ra một thể hiện 'Integer' mới. –

2

Bạn ném số nào vào đó? Nếu các con số của bạn đủ lớn, bạn có thể quấn qua các giá trị MIN/MAX cho các số nguyên và kết thúc trong một mớ hỗn độn.

1

Nếu giá trị của một giá trị âm và giá trị của b rất dương, câu trả lời của bạn sẽ rất sai.

IIRC, Int tràn âm thầm kết thúc tốt đẹp xung quanh trong JVM

- MarkusQ

5

thử

System.out.println(Integer.MAX_Value - Integer.MIN_VALUE); 

này cần phải trả về một số nguyên dương như MAX_VALUE> MIN_VALUE nhưng thay vì in -1

+0

+1 cho trường hợp không rõ ràng nhất "gói" không thành công. –

4

Khi so sánh nguyên thủy Java, bạn nên chuyển đổi chúng thành đối tượng Đối tượng của chúng và dựa vào phương thức compareTo() của chúng.

Trong trường hợp này bạn có thể làm:

return Integer.valueOf(a.getValue()).compareTo(b.getValue()) 

Khi nghi ngờ, sử dụng một thư viện được kiểm tra kỹ.

+3

Bit của chi phí ở đó (đối với các giá trị không nhỏ). –

Các vấn đề liên quan