Object 有关对象的目的、使用和查询。比较实用程序方法

Object 有关对象的目的、使用和查询。比较实用程序方法,object,null,compare,java-8,comparator,Object,Null,Compare,Java 8,Comparator,我有一个关于使用新对象的问题。compare(o1,o2,Comparator)方法-根据我自己的测试,如果o1和o2都为null,那么它返回0,但是,如果其中一个为null,那么它仍然抛出null指针异常。我在Objects.equals和其他一些Objects实用程序方法上找到了很多资料,但在Objects.compare和何时使用它/用它替换旧代码方面没有太多资料 所以在这里我可以这样做: String s1 = "hi"; String s2 = "hi"; int x = Object

我有一个关于使用新对象的问题。compare(o1,o2,Comparator)方法-根据我自己的测试,如果o1和o2都为null,那么它返回0,但是,如果其中一个为null,那么它仍然抛出null指针异常。我在Objects.equals和其他一些Objects实用程序方法上找到了很多资料,但在Objects.compare和何时使用它/用它替换旧代码方面没有太多资料

所以在这里我可以这样做:

String s1 = "hi";
String s2 = "hi";
int x = Objects.compare(s1, s2, Comparator.naturalOrder());
System.out.println("x = " + x);
很好,返回0,现在是:

String s1 = null;
String s2 = null;
也可以正常工作并返回0。然而,这:

String s1 = "hi";
Strng s2 = null;
抛出NullPointerException。我猜Object.compare(o1,o2,Comparator)和o1.compareTo(o2)的好处在于它至少可以处理两个对象都为null的情况,当其中一个为null时,它允许您设计一个比较器来处理它。我猜想,例如

int x = Objects.compare(s1, s2, Comparator.nullsFirst(Comparator.naturalOrder()));
而对于x.compareTo(y),除非您事先这样做,否则无法处理null?那么Java库开发人员现在是否打算让我们用Objects.compare替换所有对compareTo的调用,而我们关心的是空值?e、 g.我们会在类似的实施中这样做吗

侧边查询1:关于使用nullsFirst,如果使用它,然后传入一个比较器,该比较器使用比较、然后比较等链接,它是否适用于所有内部比较器?e、 g

Comparator.nullsFirst(Comparator.comparing(Song::getTitle)
    .thenComparing(Song::getArtist)
    .thenComparing(Song::getDuration)
)
这会将nullsFirst应用于内部的所有内容,还是需要对每个内容单独使用nullsFirst?通过测试,我认为它只适用于实际的歌曲对象为null,而不适用于标题或艺术家为null的字段,也就是说,如果它们为null,那么仍然会抛出NullPointerException。不管怎么说

旁白2:最后一个问题是,因为我喜欢Comparator.Comparating语法,我建议开始用它来编写compareTo实现——我一直在努力思考如何取代这种传统方法,例如

public int compareTo(Song other) {
    int result = this.title.compareTo(other.title);

    if (result == 0) {
        result = this.artist.compareTo(other.artist);

        if (result == 0) {

            result = Integer.compare(this.duration, other.duration);
        }
    }

     return result;
}
然后我想我可以使用对象。比较(…)如下:

public int compareTo(Song other) {

    return Objects.compare(this, other, Comparator.nullsFirst(
        Comparator.comparing(Song::getTitle)
        .thenComparing(Song::getArtist)
        .thenComparingInt(Song::getDuration)
        ));
}
我认为这个版本更优雅-我假设它是按照我认为的那样工作的,例如,通过将这个和其他作为前两个参数传递给比较器,然后传递给比较器,它与使用if语句的传统比较方法具有相同的效果?虽然我可以看到Objects.compare捕获两个null的好处永远不会出现,就好像这是null一样,但是永远不会到达compareTo方法调用(通过处理异常或抛出异常)。但是通过使用nullsFirst,我想如果传入的参数,即other,为null,那么这将安全地处理这个问题


非常感谢您的帮助。

对象。compare
并不意味着提供
null
安全比较,因为没有可以实现的默认行为。它只是实现了一个快捷方式,当两个对象相同时,不调用
比较器的方法。换句话说,它确实
a==b?0:c.比较(a,b)
,仅此而已。因此,当两个对象都
null
时不中断只是一个副作用。封装的代码可能看起来微不足道,但此类中的其他方法属于类似的类别。大量使用小型实用方法仍可能带来显著的胜利

顺便说一下,它根本不是Java8方法。它从Java7开始就存在


关于你的第二个问题,
Comparator.nullsFirst(…)
修饰现有的
比较器
,并将在委托给提供的比较器之前强制执行
null
值的规则,因为该比较器的目的是保护现有比较器永远看不到
null
值。装饰后的比较器是否是链式比较器并不重要。只要它是你所谓的“内部比较器”,就像

您不能对
nullsFirst
的结果调用
然后比较
,因为这意味着在两个值都为
null
时调用下一个比较器

Comparator.nullsFirst(Comparator.comparing(a).thenComparing(b)) // perfect
Comparator.nullsFirst(Comparator.comparing(a)).thenComparing(b) // ouch

现在转到第三个问题,使用
nullsFirst
比较器实现
compareTo
方法违反了以下规则:

实施者必须确保所有
x
y
sgn(x.compareTo(y))==-sgn(y.compareTo(x))
。(这意味着
x.compareTo(y)
必须在
y.compareTo(x)
引发异常时引发异常。)

这意味着将
null
作为参数传递应该总是导致
NullPointerException
作为交换参数,接收方也会无条件地抛出

包含
null
策略的订单应始终作为单独的
比较器提供


请注意,这也会非常低效,因为您会为每个
比较调用创建一个新的
比较器
(准确地说是多个
比较器
)。现在,对这些对象的一个相当大的列表进行图像排序…

对象。compare
并不意味着提供一个
null
安全的比较,因为没有可以实现的默认行为。它只是实现了一个快捷方式,当两个对象相同时,不调用
比较器的方法。换句话说,它确实
a==b?0:c.比较(a,b)
,仅此而已。因此,当两个对象都
null
时不中断只是一个副作用。封装的代码可能看起来微不足道,但此类中的其他方法属于类似的类别。大量使用小型实用方法仍可能带来显著的胜利

顺便说一下,它根本不是Java8方法。它从Java7开始就存在


关于您的第二个问题,
Comparator.nullsFirst(…)
修饰现有的
比较器
,并将在委托给提供的比较器之前强制执行
null
值的规则,因为此比较器的目的是保护现有比较器不受
public static final Comparator<Song> COMP_DEFAULT
        = nullsFirst(comparing(Song::getTitle, nullsFirst(naturalOrder()))
                .thenComparing(Song::getArtist, nullsFirst(naturalOrder()))
                .thenComparingInt(Song::getDuration));
public int compareTo(Song other) {
    return COMP_DEFAULT.compare(this, other);
}