Jon*_*nik 147 java comparison null refactoring compareto
我正在compareTo()为一个简单的类实现方法(为了能够使用Collections.sort()和Java平台提供的其他好东西):
public class Metadata implements Comparable<Metadata> {
private String name;
private String value;
// Imagine basic constructor and accessors here
// Irrelevant parts omitted
}
Run Code Online (Sandbox Code Playgroud)
我希望这些对象的自然顺序为:1)按名称排序; 2)如果名称相同则按值排序; 两种比较都应该不区分大小写.对于这两个字段,空值完全可以接受,因此compareTo在这些情况下不得中断.
脑海中出现的解决方案与以下几行相似(我在这里使用"保护条款",而其他人可能更喜欢单个返回点,但这不是重点):
// 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);
}
Run Code Online (Sandbox Code Playgroud)
这样做,但我对这段代码并不满意.不可否认,这不是很复杂,但是相当冗长乏味.
问题是,你如何减少冗长(保留功能)?如果有帮助,请随意参考Java标准库或Apache Commons.使(稍微)更简单的唯一选择是实现我自己的"NullSafeStringComparator",并将其应用于比较两个字段吗?
编辑1-3:Eddie是对的; 修复了上面"两个名称都为空"的情况
我在2009年就Java 1.6问了这个问题,当时Eddie的纯JDK解决方案是我首选的接受答案.直到现在(2017年)我都没有改变过这种情况.
还有第三方库解决方案 - 一个2009年的Apache Commons Collections one和一个2013 Guava one 解决方案 - 两者都是我发布的 - 我在某个时间点确实更喜欢它.
我现在由Lukasz Wiktor制作了干净的Java 8解决方案.如果在Java 8上,这绝对应该是首选,而且现在几乎所有项目都可以使用Java 8.
Dag*_*Dag 201
你可以简单地使用Apache Commons Lang:
result = ObjectUtils.compare(firstComparable, secondComparable)
Run Code Online (Sandbox Code Playgroud)
Luk*_*tor 159
使用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);
}
Run Code Online (Sandbox Code Playgroud)
Edd*_*die 92
我会实现一个空安全比较器.可能有一个实现,但实现起来非常简单,我总是推出自己的实现.
注意:如果两个名称均为空,则上面的比较器甚至不会比较值字段.我不认为这是你想要的.
我会用以下内容实现它:
// 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);
}
Run Code Online (Sandbox Code Playgroud)
编辑:修复代码示例中的拼写错误.这就是我没有先测试它的原因!
编辑:将nullSafeStringComparator提升为静态.
Jon*_*nik 21
有关使用Guava的更新(2013)解决方案,请参阅本答案的底部.
这就是我最终的目标.事实证明我们已经有了一个用于null安全字符串比较的实用方法,所以最简单的解决方案就是利用它.(这是一个很大的代码库;容易错过这种事:)
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);
}
Run Code Online (Sandbox Code Playgroud)
这就是帮助器的定义方式(它是重载的,这样你也可以定义空值是第一个还是最后一个,如果你愿意的话):
public static int compare(String s1, String s2, boolean ignoreCase) { ... }
Run Code Online (Sandbox Code Playgroud)
因此,这与Eddie的答案(尽管我不会将静态辅助方法称为比较器)和uzhin 的答案基本相同.
无论如何,总的来说,我会强烈支持Patrick的解决方案,因为我认为尽可能使用已建立的库是一种很好的做法.(知道并使用 Josh Bloch所说的库.)但在这种情况下,不会产生最干净,最简单的代码.
实际上,这是一种使基于Apache Commons的解决方案NullComparator更简单的方法.将它与类中提供的不区分大小写相Comparator结合String:
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);
}
Run Code Online (Sandbox Code Playgroud)
我觉得现在这很优雅.(只剩下一个小问题:Commons NullComparator不支持泛型,所以有一个未经检查的任务.)
差不多5年后,这就是我如何处理我原来的问题.如果用Java编码,我(当然)会使用Guava.(当然不是 Apache Commons.)
把它保持在某个地方,例如在"StringUtils"类中:
public static final Ordering<String> CASE_INSENSITIVE_NULL_SAFE_ORDER =
Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast(); // or nullsFirst()
Run Code Online (Sandbox Code Playgroud)
然后,在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);
}
Run Code Online (Sandbox Code Playgroud)
当然,这几乎与Apache Commons版本(都使用JDK的CASE_INSENSITIVE_ORDER)完全相同,使用的nullsLast()是唯一的Guava特定的东西.这个版本更可取,因为Guava是Commons Collections的优先选择.(正如大家都同意的那样.)
如果你想知道Ordering,请注意它实现Comparator.它非常方便,特别是对于更复杂的排序需求,例如,您可以使用链接连接多个订单compound().阅读订购说明了解更多!
Pat*_*ick 13
我总是建议使用Apache commons,因为它很可能比你自己编写的更好.此外,您可以做"真正的"工作,而不是重新发明.
您感兴趣的课程是Null Comparator.它允许您使空值高或低.当两个值不为空时,您还可以使用自己的比较器.
在你的情况下,你可以有一个静态成员变量进行比较,然后你的compareTo方法只引用它.
有点像
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);
}
Run Code Online (Sandbox Code Playgroud)
}
即使你决定自己动手,也要记住这个类,因为它在订购包含null元素的列表时非常有用.
可以提取方法:
public int cmp(String txt, String otherTxt)
{
if ( txt == null )
return otherTxt == 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);
Run Code Online (Sandbox Code Playgroud)
}
| 归档时间: |
|
| 查看次数: |
141569 次 |
| 最近记录: |