如何简化空安全比较To()实现?

2022-08-31 06:34:15

我正在为像这样的简单类实现方法(以便能够使用Java平台提供的其他好东西):compareTo()Collections.sort()

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

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

我希望这些对象的自然排序是:1)按名称排序,2)如果名称相同,则按值排序;两种比较都应不区分大小写。对于这两个字段,空值是完全可以接受的,因此在这些情况下不得中断。compareTo

我想到的解决方案是沿着以下思路(我在这里使用“guard子句”,而其他人可能更喜欢单个返回点,但这不是重点):

// 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);
}

这完成了工作,但我对这段代码并不完全满意。诚然,它不是很复杂,但非常冗长和乏味。

问题是,如何使它不那么冗长(同时保留功能)?如果它们有帮助,请随时参考Java标准库或Apache Commons。使这个(稍微)更简单的唯一选择是实现我自己的“NullSafeStringComparator”,并将其应用于比较两个字段?

编辑1-3:埃迪的权利;修复了上面的“两个名字都为空”的情况

关于接受的答案

我在2009年问过这个问题,当然是在Java 1.6上,当时Eddie的纯JDK解决方案是我的首选接受答案。直到现在(2017年),我从未想过要改变这一点。

还有第三方库解决方案——2009年的Apache Commons Collections和2013年的Guava,都是我发布的——我确实在某个时间点更喜欢它们。

我现在让Lukasz Wiktor的干净的Java 8解决方案成为公认的答案。如果在Java 8上,这绝对是首选,现在Java 8应该可用于几乎所有项目。


答案 1

你可以简单地使用Apache Commons Lang

result = ObjectUtils.compare(firstComparable, secondComparable)

答案 2

使用 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);
}

推荐