Làm cách nào để đơn giản hóa việc triển khai so sánh null () an toàn?


156

Tôi đang triển khai compareTo()phương thức cho một lớp đơn giản như thế này (để có thể sử dụng Collections.sort()và các tính năng khác được cung cấp bởi nền tảng Java):

public class Metadata implements Comparable<Metadata> {
    private String name;
    private String value;

// Imagine basic constructor and accessors here
// Irrelevant parts omitted
}

Tôi muốn thứ tự tự nhiên cho các đối tượng này là: 1) được sắp xếp theo tên và 2) được sắp xếp theo giá trị nếu tên giống nhau; cả hai so sánh nên không phân biệt chữ hoa chữ thường. Đối với cả hai trường, giá trị null là hoàn toàn chấp nhận được, vì vậy compareTokhông được phá vỡ trong các trường hợp này.

Giải pháp nảy sinh trong tâm trí là dọc theo các dòng sau (Tôi đang sử dụng "mệnh đề bảo vệ" ở đây trong khi các giải pháp khác có thể thích một điểm quay lại duy nhất, nhưng đó là điểm bên cạnh):

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(Metadata other) {
    if (this.name == null && other.name != null){
        return -1;
    }
    else if (this.name != null && other.name == null){
        return 1;
    }
    else if (this.name != null && other.name != null) {
        int result = this.name.compareToIgnoreCase(other.name);
        if (result != 0){
            return result;
        }
    }

    if (this.value == null) {
        return other.value == null ? 0 : -1;
    }
    if (other.value == null){
        return 1;
    }

    return this.value.compareToIgnoreCase(other.value);
}

Điều này thực hiện công việc, nhưng tôi không hoàn toàn hài lòng với mã này. Phải thừa nhận rằng nó không quá phức tạp, nhưng khá dài dòng và tẻ nhạt.

Câu hỏi là, làm thế nào bạn sẽ làm cho điều này ít dài dòng hơn (trong khi vẫn giữ được chức năng)? Vui lòng tham khảo các thư viện tiêu chuẩn Java hoặc Apache Commons nếu chúng giúp. Liệu lựa chọn duy nhất để làm cho điều này (một chút) đơn giản hơn là triển khai "NullSafeStringComparator" của riêng tôi và áp dụng nó để so sánh cả hai trường?

Chỉnh sửa 1-3 : Quyền của Eddie; đã sửa trường hợp "cả hai tên đều null" ở trên

Về câu trả lời được chấp nhận

Tôi đã hỏi câu hỏi này vào năm 2009, trên Java 1.6, và tại thời điểm đó , giải pháp JDK thuần túy của Eddie là câu trả lời được chấp nhận ưa thích của tôi. Tôi chưa bao giờ có vòng để thay đổi điều đó cho đến bây giờ (2017).

Ngoài ra còn có các giải pháp thư viện của bên thứ 3 Tập hợp Bộ sưu tập Apache Commons 2009 và Bộ sưu tập năm 2013, cả hai đều được đăng bởi tôi mà tôi thích vào một lúc nào đó.

Bây giờ tôi đã làm cho giải pháp Java 8 sạch của Lukasz Wiktor là câu trả lời được chấp nhận. Điều đó chắc chắn nên được ưu tiên nếu trên Java 8 và ngày nay Java 8 sẽ có sẵn cho gần như tất cả các dự án.


Câu trả lời:


173

Sử dụng Java 8 :

private static Comparator<String> nullSafeStringComparator = Comparator
        .nullsFirst(String::compareToIgnoreCase); 

private static Comparator<Metadata> metadataComparator = Comparator
        .comparing(Metadata::getName, nullSafeStringComparator)
        .thenComparing(Metadata::getValue, nullSafeStringComparator);

public int compareTo(Metadata that) {
    return metadataComparator.compare(this, that);
}

7
Tôi hỗ trợ sử dụng các công cụ tích hợp Java 8 có lợi cho Apache Commons Lang, nhưng mã Java 8 đó khá xấu và vẫn dài dòng. Tôi sẽ gắn bó với org.apache.commons.lang3.builder.CompareToBuilder trong thời điểm này.
jschreiner

1
Điều này không hoạt động đối với Collections.sort (Arrays.asList (null, val1, null, val2, null)) vì nó sẽ cố gắng gọi so sánh () trên một đối tượng null. Có vẻ như một vấn đề với khung bộ sưu tập phải trung thực, cố gắng tìm ra cách để vượt qua điều này.
Pedro Borges

3
@PedroBorges Tác giả đã hỏi về việc sắp xếp các đối tượng chứa có các trường có thể sắp xếp (trong đó các trường đó có thể là null), không phải về sắp xếp các tham chiếu vùng chứa null. Vì vậy, trong khi nhận xét của bạn là chính xác, trong đó Collections.sort(List)không hoạt động khi Danh sách chứa null, bình luận không liên quan đến câu hỏi.
Scrubbie

211

Bạn chỉ có thể sử dụng Apache Commons Lang :

result = ObjectUtils.compare(firstComparable, secondComparable)

4
(@Kong: Điều này quan tâm đến an toàn vô hiệu nhưng không phân biệt chữ hoa chữ thường là một khía cạnh khác của câu hỏi ban đầu. Do đó, không thay đổi câu trả lời được chấp nhận.)
Jonik

3
Ngoài ra, trong suy nghĩ của tôi, Apache Commons không nên là câu trả lời được chấp nhận vào năm 2013. (Ngay cả khi một số tiểu dự án được duy trì tốt hơn các dự án khác.) Có thể sử dụng ổi để đạt được điều tương tự ; xem nullsFirst()/ nullsLast().
Jonik

8
@Jonik Tại sao bạn nghĩ rằng Apache Commons không nên là câu trả lời được chấp nhận trong năm 2013?
thực sự là

1
Phần lớn của Apache Commons là di sản / bảo trì kém / chất lượng thấp. Có nhiều lựa chọn thay thế tốt hơn cho hầu hết mọi thứ mà nó cung cấp, ví dụ như trong Guava , đó là một lib chất lượng rất cao xuyên suốt và ngày càng tăng trong chính JDK. Khoảng năm 2005, vâng, Apache Commons là thứ rác rưởi, nhưng ngày nay không cần nó trong hầu hết các dự án. (Chắc chắn, có một số trường hợp ngoại lệ; ví dụ: nếu tôi cần một ứng dụng khách FTP vì một số lý do, có lẽ tôi sẽ sử dụng một ứng dụng trong Apache Commons Net, v.v.)
Jonik

6
@Jonik, bạn sẽ trả lời câu hỏi bằng Guava như thế nào? Sự khẳng định của bạn rằng Apache Commons Lang (gói org.apache.commons.lang3) là "di sản / bảo trì kém / chất lượng thấp" là sai hoặc tốt nhất là vô căn cứ. Commons Lang3 rất dễ hiểu và dễ sử dụng, và nó được duy trì tích cực. Đây có lẽ là thư viện được sử dụng nhiều nhất của tôi (ngoài Spring Framework và Spring Security) - lớp StringUtils với các phương thức an toàn null của nó làm cho việc chuẩn hóa đầu vào trở nên tầm thường, chẳng hạn.
Paul

93

Tôi sẽ thực hiện một so sánh an toàn null. Có thể có một triển khai ngoài kia, nhưng điều này rất đơn giản để thực hiện mà tôi luôn tự mình thực hiện.

Lưu ý: Công cụ so sánh của bạn ở trên, nếu cả hai tên đều rỗng, thậm chí sẽ không so sánh các trường giá trị. Tôi không nghĩ rằng đây là những gì bạn muốn.

Tôi sẽ thực hiện điều này với một cái gì đó như sau:

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(final Metadata other) {

    if (other == null) {
        throw new NullPointerException();
    }

    int result = nullSafeStringComparator(this.name, other.name);
    if (result != 0) {
        return result;
    }

    return nullSafeStringComparator(this.value, other.value);
}

public static int nullSafeStringComparator(final String one, final String two) {
    if (one == null ^ two == null) {
        return (one == null) ? -1 : 1;
    }

    if (one == null && two == null) {
        return 0;
    }

    return one.compareToIgnoreCase(two);
}

EDIT: Đã sửa lỗi chính tả trong mẫu mã. Đó là những gì tôi nhận được khi không thử nghiệm nó đầu tiên!

EDIT: Quảng cáo nullSafeStringComparator thành tĩnh.


2
Về lồng nhau "nếu" ... Tôi thấy lồng nhau nếu không thể đọc được trong trường hợp này, vì vậy tôi tránh nó. Vâng, đôi khi sẽ có một so sánh không cần thiết do điều này. cuối cùng cho các tham số là không cần thiết, nhưng là một ý tưởng tốt.
Eddie

31
Công dụng ngọt ngào của XOR
James McMahon

9
@phihag - Tôi biết đã hơn 3 năm, NHƯNG ... finaltừ khóa không thực sự cần thiết (mã Java đã dài dòng như vậy.) Tuy nhiên, nó ngăn chặn việc sử dụng lại các tham số như các vars cục bộ (một cách thực hành mã hóa khủng khiếp.) sự hiểu biết tập thể của chúng tôi về phần mềm trở nên tốt hơn theo thời gian, chúng tôi biết rằng mọi thứ nên là cuối cùng / const / không thể thay đổi theo mặc định. Vì vậy, tôi thích tính chi tiết hơn một chút trong việc sử dụng finaltrong khai báo tham số (tuy nhiên chức năng có thể tầm thường) để có được inmutability-by-quasi-default.) Tính dễ hiểu / chi phí bảo trì của nó là không đáng kể trong sơ đồ lớn của mọi thứ.
luis.espinal

24
@James McMahon Tôi phải không đồng ý. Xor (^) đơn giản có thể được thay thế bằng không bằng (! =). Nó thậm chí còn biên dịch thành cùng mã byte. Việc sử dụng! = Vs ^ chỉ là vấn đề về hương vị và khả năng đọc. Vì vậy, đánh giá bằng việc bạn ngạc nhiên tôi sẽ nói rằng nó không thuộc về nơi này. Sử dụng xor khi bạn đang cố gắng tính toán tổng kiểm tra. Trong hầu hết các trường hợp khác (như thế này), hãy bám vào! =.
bvdb

5
Thật dễ dàng để mở rộng câu trả lời này bằng cách thay thế Chuỗi bằng T, T được khai báo là <T kéo dài so sánh <T >> ... và sau đó chúng ta có thể so sánh một cách an toàn bất kỳ đối tượng có thể so sánh nào
Thierry

20

Xem phần dưới của câu trả lời này để biết giải pháp cập nhật (2013) bằng Guava.


Đây là những gì tôi cuối cùng đã đi với. Hóa ra chúng ta đã có một phương thức tiện ích để so sánh Chuỗi không an toàn, vì vậy giải pháp đơn giản nhất là sử dụng điều đó. (Đây là một cơ sở mã lớn; dễ bỏ lỡ loại điều này :)

public int compareTo(Metadata other) {
    int result = StringUtils.compare(this.getName(), other.getName(), true);
    if (result != 0) {
        return result;
    }
    return StringUtils.compare(this.getValue(), other.getValue(), true);
}

Đây là cách người trợ giúp được xác định (nó bị quá tải để bạn cũng có thể xác định liệu null đến trước hay cuối, nếu bạn muốn):

public static int compare(String s1, String s2, boolean ignoreCase) { ... }

Vì vậy, đây về cơ bản giống như câu trả lời của Eddie (mặc dù tôi sẽ không gọi phương thức trợ giúp tĩnh là so sánh ) và uzhin cũng vậy.

Dù sao, nói chung, tôi rất thích giải pháp của Patrick , vì tôi nghĩ rằng đó là một cách thực hành tốt để sử dụng các thư viện đã được thiết lập bất cứ khi nào có thể. ( Biết và sử dụng các thư viện như Josh Bloch nói.) Nhưng trong trường hợp này sẽ không mang lại mã sạch nhất, đơn giản nhất.

Chỉnh sửa (2009): Phiên bản Bộ sưu tập Apache Commons

Trên thực tế, đây là một cách để làm cho giải pháp dựa trên Apache Commons NullComparatorđơn giản hơn. Kết hợp nó với trường hợp không nhạy cảmComparator được cung cấp trong Stringlớp:

public static final Comparator<String> NULL_SAFE_COMPARATOR 
    = new NullComparator(String.CASE_INSENSITIVE_ORDER);

@Override
public int compareTo(Metadata other) {
    int result = NULL_SAFE_COMPARATOR.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return NULL_SAFE_COMPARATOR.compare(this.value, other.value);
}

Bây giờ điều này là khá thanh lịch, tôi nghĩ. (Chỉ còn một vấn đề nhỏ: Commons NullComparatorkhông hỗ trợ thuốc generic, vì vậy có một nhiệm vụ không được kiểm soát.)

Cập nhật (2013): Phiên bản ổi

Gần 5 năm sau, đây là cách tôi giải quyết câu hỏi ban đầu của mình. Nếu mã hóa bằng Java, tôi (dĩ nhiên) sẽ sử dụng Guava . (Và hoàn toàn chắc chắn không phải là Apache Commons.)

Đặt hằng số này ở đâu đó, ví dụ như trong lớp "StringUtils":

public static final Ordering<String> CASE_INSENSITIVE_NULL_SAFE_ORDER =
    Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast(); // or nullsFirst()

Sau đó, trong public class Metadata implements Comparable<Metadata>:

@Override
public int compareTo(Metadata other) {
    int result = CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.value, other.value);
}    

Tất nhiên, điều này gần giống với phiên bản Apache Commons (cả hai đều sử dụng CASE_INSENSITIVE_ORDER của JDK ), việc sử dụng nullsLast()là thứ duy nhất dành riêng cho ổi. Phiên bản này được ưu tiên đơn giản vì Guava thích hợp hơn, như là một phụ thuộc, cho Bộ sưu tập Commons. (Như mọi người đồng ý .)

Nếu bạn đã tự hỏi về Ordering, lưu ý rằng nó thực hiện Comparator. Nó khá tiện dụng đặc biệt cho các nhu cầu sắp xếp phức tạp hơn, ví dụ cho phép bạn xâu chuỗi một số Đơn hàng bằng cách sử dụng compound(). Đọc Đặt hàng Giải thích để biết thêm!


2
String.CASE_INSENSITIVE_ORDER thực sự làm cho giải pháp sạch hơn nhiều. Cập nhật tốt đẹp.
Patrick

2
Nếu bạn sử dụng Apache Commons, thì ComparatorChainbạn không cần một compareTophương thức riêng .
amoebe

13

Tôi luôn khuyên bạn nên sử dụng Apache commons vì nó rất có thể sẽ tốt hơn so với cái mà bạn có thể tự viết. Ngoài ra, sau đó bạn có thể thực hiện công việc 'thực tế' thay vì phát minh lại.

Lớp bạn quan tâm là Bộ so sánh Null . Nó cho phép bạn tạo null cao hoặc thấp. Bạn cũng cung cấp cho nó bộ so sánh của riêng bạn để sử dụng khi hai giá trị không phải là null.

Trong trường hợp của bạn, bạn có thể có một biến thành viên tĩnh thực hiện so sánh và sau đó compareTophương thức của bạn chỉ tham chiếu đến đó.

Một cái gì đó như

class Metadata implements Comparable<Metadata> {
private String name;
private String value;

static NullComparator nullAndCaseInsensitveComparator = new NullComparator(
        new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                // inputs can't be null
                return o1.compareToIgnoreCase(o2);
            }

        });

@Override
public int compareTo(Metadata other) {
    if (other == null) {
        return 1;
    }
    int res = nullAndCaseInsensitveComparator.compare(name, other.name);
    if (res != 0)
        return res;

    return nullAndCaseInsensitveComparator.compare(value, other.value);
}

}

Ngay cả khi bạn quyết định tự lăn, hãy ghi nhớ lớp này vì nó rất hữu ích khi sắp xếp các danh sách có chứa các phần tử null.


Cảm ơn, tôi đã hy vọng sẽ có một cái gì đó như thế này trong Commons! Tuy nhiên, trong trường hợp này, tôi đã không sử dụng nó: stackoverflow.com/questions/481813/
Khăn

Chỉ cần nhận ra cách tiếp cận của bạn có thể được đơn giản hóa bằng cách sử dụng String.CASE_INSENSITIVE_ORDER; xem câu trả lời tiếp theo được chỉnh sửa của tôi.
Jonik

Điều này là tốt nhưng kiểm tra "if (other == null) {" không nên có. Javadoc cho so sánh nói rằng so sánh nên ném NullPulumException nếu khác là null.
Daniel Alexiuc

7

Tôi biết rằng nó có thể không trả lời trực tiếp cho câu hỏi của bạn, bởi vì bạn nói rằng các giá trị null phải được hỗ trợ.

Nhưng tôi chỉ muốn lưu ý rằng việc hỗ trợ null trong so sánh không phù hợp với hợp đồng so sánh được mô tả trong javadocs chính thức cho So sánh :

Lưu ý rằng null không phải là một thể hiện của bất kỳ lớp nào và e.compareTo (null) sẽ ném NullPulumException ngay cả khi e.equals (null) trả về false.

Vì vậy, tôi sẽ ném NullPulumException một cách rõ ràng hoặc chỉ để nó được ném lần đầu tiên khi đối số null đang bị hủy đăng ký.


4

Bạn có thể trích xuất phương pháp:

public int cmp(String txt, String otherTxt)
{
    if ( txt == null )
        return otjerTxt == null ? 0 : 1;

    if ( otherTxt == null )
          return 1;

    return txt.compareToIgnoreCase(otherTxt);
}

public int compareTo(Metadata other) {
   int result = cmp( name, other.name); 
   if ( result != 0 )  return result;
   return cmp( value, other.value); 

}


2
"0: 1" không phải là "0: -1"?
Rolf Kristensen

3

Bạn có thể thiết kế lớp của mình thành bất biến (Java Java Ed hiệu quả có một phần tuyệt vời về điều này, Mục 15: Giảm thiểu khả năng biến đổi) và đảm bảo khi xây dựng không có null (và sử dụng mẫu đối tượng null nếu cần). Sau đó, bạn có thể bỏ qua tất cả các kiểm tra đó và giả sử một cách an toàn các giá trị không phải là null.


Vâng, đó thường là một giải pháp tốt và đơn giản hóa nhiều thứ - nhưng ở đây tôi quan tâm nhiều hơn đến trường hợp cho phép giá trị null, vì lý do này hay lý do khác, và phải được tính đến :)
Jonik

2

Tôi đang tìm kiếm một cái gì đó tương tự và điều này có vẻ hơi phức tạp vì vậy tôi đã làm điều này. Tôi nghĩ nó dễ hiểu hơn một chút. Bạn có thể sử dụng nó như một bộ so sánh hoặc như một lớp lót. Đối với câu hỏi này, bạn sẽ thay đổi thành soToIgnoreCase (). Như là, nulls nổi lên. Bạn có thể lật 1, -1 nếu bạn muốn chúng chìm.

StringUtil.NULL_SAFE_COMPARATOR.compare(getName(), o.getName());

.

public class StringUtil {
    public static final Comparator<String> NULL_SAFE_COMPARATOR = new Comparator<String>() {

        @Override
        public int compare(final String s1, final String s2) {
            if (s1 == s2) {
                //Nulls or exact equality
                return 0;
            } else if (s1 == null) {
                //s1 null and s2 not null, so s1 less
                return -1;
            } else if (s2 == null) {
                //s2 null and s1 not null, so s1 greater
                return 1;
            } else {
                return s1.compareTo(s2);
            }
        }
    }; 

    public static void main(String args[]) {
        final ArrayList<String> list = new ArrayList<String>(Arrays.asList(new String[]{"qad", "bad", "sad", null, "had"}));
        Collections.sort(list, NULL_SAFE_COMPARATOR);

        System.out.println(list);
    }
}

2

chúng ta có thể sử dụng java 8 để thực hiện so sánh thân thiện giữa các đối tượng. giả sử tôi có một lớp Boy với 2 trường: Tên chuỗi và tuổi Integer và trước tiên tôi muốn so sánh tên và sau đó là tuổi nếu cả hai đều bằng nhau.

static void test2() {
    List<Boy> list = new ArrayList<>();
    list.add(new Boy("Peter", null));
    list.add(new Boy("Tom", 24));
    list.add(new Boy("Peter", 20));
    list.add(new Boy("Peter", 23));
    list.add(new Boy("Peter", 18));
    list.add(new Boy(null, 19));
    list.add(new Boy(null, 12));
    list.add(new Boy(null, 24));
    list.add(new Boy("Peter", null));
    list.add(new Boy(null, 21));
    list.add(new Boy("John", 30));

    List<Boy> list2 = list.stream()
            .sorted(comparing(Boy::getName, 
                        nullsLast(naturalOrder()))
                   .thenComparing(Boy::getAge, 
                        nullsLast(naturalOrder())))
            .collect(toList());
    list2.stream().forEach(System.out::println);

}

private static class Boy {
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Boy(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "name: " + name + " age: " + age;
    }
}

và kết quả:

    name: John age: 30
    name: Peter age: 18
    name: Peter age: 20
    name: Peter age: 23
    name: Peter age: null
    name: Peter age: null
    name: Tom age: 24
    name: null age: 12
    name: null age: 19
    name: null age: 21
    name: null age: 24


1

Đối với trường hợp cụ thể mà bạn biết dữ liệu sẽ không có giá trị null (luôn là ý tưởng tốt cho chuỗi) và dữ liệu thực sự lớn, bạn vẫn thực hiện ba so sánh trước khi thực sự so sánh các giá trị, nếu bạn biết chắc đây là trường hợp của bạn , bạn có thể tối ưu hóa một chút. YMMV như mã có thể đọc được tối ưu hóa nhỏ hơn:

        if(o1.name != null && o2.name != null){
            return o1.name.compareToIgnoreCase(o2.name);
        }
        // at least one is null
        return (o1.name == o2.name) ? 0 : (o1.name != null ? 1 : -1);

1
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Comparator;

public class TestClass {

    public static void main(String[] args) {

        Student s1 = new Student("1","Nikhil");
        Student s2 = new Student("1","*");
        Student s3 = new Student("1",null);
        Student s11 = new Student("2","Nikhil");
        Student s12 = new Student("2","*");
        Student s13 = new Student("2",null);
        List<Student> list = new ArrayList<Student>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s11);
        list.add(s12);
        list.add(s13);

        list.sort(Comparator.comparing(Student::getName,Comparator.nullsLast(Comparator.naturalOrder())));

        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            Student student = (Student) iterator.next();
            System.out.println(student);
        }


    }

}

đầu ra là

Student [name=*, id=1]
Student [name=*, id=2]
Student [name=Nikhil, id=1]
Student [name=Nikhil, id=2]
Student [name=null, id=1]
Student [name=null, id=2]

1

Một trong những cách đơn giản để sử dụng Trình so sánh NullSafe là sử dụng triển khai Spring của nó, dưới đây là một trong những ví dụ đơn giản để tham khảo:

public int compare(Object o1, Object o2) {
        ValidationMessage m1 = (ValidationMessage) o1;
        ValidationMessage m2 = (ValidationMessage) o2;
        int c;
        if (m1.getTimestamp() == m2.getTimestamp()) {
            c = NullSafeComparator.NULLS_HIGH.compare(m1.getProperty(), m2.getProperty());
            if (c == 0) {
                c = m1.getSeverity().compareTo(m2.getSeverity());
                if (c == 0) {
                    c = m1.getMessage().compareTo(m2.getMessage());
                }
            }
        }
        else {
            c = (m1.getTimestamp() > m2.getTimestamp()) ? -1 : 1;
        }
        return c;
    }

0

Một ví dụ khác về ObjectUtils của Apache. Có thể sắp xếp các loại đối tượng khác.

@Override
public int compare(Object o1, Object o2) {
    String s1 = ObjectUtils.toString(o1);
    String s2 = ObjectUtils.toString(o2);
    return s1.toLowerCase().compareTo(s2.toLowerCase());
}

0

Đây là triển khai của tôi mà tôi sử dụng để sắp xếp ArrayList của mình. các lớp null được sắp xếp đến cuối cùng.

đối với trường hợp của tôi, EntityPhone mở rộng Entity Ab khu vực và vùng chứa của tôi là Danh sách <Entity Ab khu vực>.

phương thức "notify IfNull ()" được sử dụng để sắp xếp an toàn null. Các phương thức khác là để hoàn thiện, cho thấy cách so sánh có thể được sử dụng.

@Nullable
private static Integer compareIfNull(EntityPhone ep1, EntityPhone ep2) {

    if (ep1 == null || ep2 == null) {
        if (ep1 == ep2) {
            return 0;
        }
        return ep1 == null ? -1 : 1;
    }
    return null;
}

private static final Comparator<EntityAbstract> AbsComparatorByName = = new Comparator<EntityAbstract>() {
    @Override
    public int compare(EntityAbstract ea1, EntityAbstract ea2) {

    //sort type Phone first.
    EntityPhone ep1 = getEntityPhone(ea1);
    EntityPhone ep2 = getEntityPhone(ea2);

    //null compare
    Integer x = compareIfNull(ep1, ep2);
    if (x != null) return x;

    String name1 = ep1.getName().toUpperCase();
    String name2 = ep2.getName().toUpperCase();

    return name1.compareTo(name2);
}
}


private static EntityPhone getEntityPhone(EntityAbstract ea) { 
    return (ea != null && ea.getClass() == EntityPhone.class) ?
            (EntityPhone) ea : null;
}

0

Nếu bạn muốn một Hack đơn giản:

arrlist.sort((o1, o2) -> {
    if (o1.getName() == null) o1.setName("");
    if (o2.getName() == null) o2.setName("");

    return o1.getName().compareTo(o2.getName());
})

Nếu bạn muốn đặt null vào cuối danh sách, chỉ cần thay đổi điều này trong metod ở trên

return o2.getName().compareTo(o1.getName());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.