如何简化空安全 compareTo() 实现? [英] How to simplify a null-safe compareTo() implementation?

查看:15
本文介绍了如何简化空安全 compareTo() 实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm implementing compareTo() method for a simple class such as this (to be able to use Collections.sort() and other goodies offered by the Java platform):

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

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

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

I want the natural ordering for these objects to be: 1) sorted by name and 2) sorted by value if name is the same; both comparisons should be case-insensitive. For both fields null values are perfectly acceptable, so compareTo must not break in these cases.

我想到的解决方案如下(我在这里使用保护子句",而其他人可能更喜欢单个返回点,但这不是重点):

The solution that springs to mind is along the lines of the following (I'm using "guard clauses" here while others might prefer a single return point, but that's beside the point):

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

这样做可以,但我对这段代码并不满意.诚然,它不是非常复杂,但相当冗长乏味.

This does the job, but I'm not perfectly happy with this code. Admittedly it isn't very complex, but is quite verbose and tedious.

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

The question is, how would you make this less verbose (while retaining the functionality)? Feel free to refer to Java standard libraries or Apache Commons if they help. Would the only option to make this (a little) simpler be to implement my own "NullSafeStringComparator", and apply it for comparing both fields?

编辑 1-3:Eddie 是对的;修复了上面两个名字都为空"的情况

Edits 1-3: Eddie's right; fixed the "both names are null" case above

我在 2009 年问过这个问题,当然是在 Java 1.6 上,当时 Eddie 的纯 JDK 解决方案 是我的首选答案.直到现在(2017 年),我才开始改变它.

I asked this question back in 2009, on Java 1.6 of course, and at the time the pure JDK solution by Eddie was my preferred accepted answer. I never got round to changing that until now (2017).

还有 第 3 方库解决方案——一个 2009 年的 Apache Commons Collections 和一个 2013 年的 Guava,两者都由我——我在某个时间点确实更喜欢.

There are also 3rd party library solutions—a 2009 Apache Commons Collections one and a 2013 Guava one, both posted by me—that I did prefer at some point in time.

我现在将 Lukasz Wiktor 提供的干净的 Java 8 解决方案 设为已接受的答案.如果在 Java 8 上,这绝对是首选,而且现在几乎所有项目都应该可以使用 Java 8.

I now made the clean Java 8 solution by Lukasz Wiktor the accepted answer. That should definitely be preferred if on Java 8, and these days Java 8 should be available to nearly all projects.

推荐答案

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

这篇关于如何简化空安全 compareTo() 实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆