【问题标题】:Does a natural comparator exist in the standard api?标准api中是否存在自然比较器?
【发布时间】:2011-03-15 12:57:09
【问题描述】:

我需要一个比较器作为策略模式的一部分,它既可以使用对象的自然顺序,也可以使用一些自定义顺序。对于自然排序的情况,我写了一个简单的比较器:

private static class NaturalComparator<T extends Comparable<? super T>> implements Comparator<T> {
    @Override
    public int compare(T o1, T o2) {
        return o1.compareTo(o2);
    }
}

看起来很简单,但我想知道是否有人知道标准 API 中的一个。我查看了 TreeMap,它没有这样的类,所以当编写该代码时,明显的答案是否定的,但也许它是后来添加的。

【问题讨论】:

  • 也许值得一提:在标准 API 之外,还有 Guava 的 Ordering.natural()。

标签: java comparator comparable


【解决方案1】:

添加到Comparator in Java 8:

static <T extends Comparable<? super T>> Comparator<T> naturalOrder()

这样使用,例如:

Comparator<Double> natural = Comparator.<Double>naturalOrder();
return natural.compare(1.0, 1.1));

【讨论】:

  • 如果您还没有使用 Java 8,并且您想在 Arrays.sort()Collections.sort() 等简单的方式中使用 Comparator,您可以简单地将 null 传递给 Comparator 参数,然后它将使用自然顺序。不过,并非所有 Comparator 的使用都能保证以这种方式工作。至少对于ArraysCollections,它确实是这样工作的。
  • @Joe 如果使用数组,数组项的类必须实现Comparable 接口
  • Comparator.&lt;String&gt;naturalOrder().compare(o1, o2) 支持字母数字吗?
【解决方案2】:

是的,JDK 肯定有!这里是:

Collections.reverseOrder(Collections.reverseOrder())

开个玩笑。 (但这是真的。(只是不要实际使用它。(永远。)))

【讨论】:

  • 我不接受这个答案,因为它已被 Java 8 克服,但它是 Java 8 之前的正确答案。但实际上不要使用它;-)。跨度>
  • 我可能错过了这里的笑话。为什么我不应该实际使用它(在较旧的 Java 中)?这里没有什么真正被逆转。开销非常小。
  • @JirkaHanika,从长远来看,您在编码中可以做的最重要的事情是让代码易于理解。当然,这是一个很好的单行代码,并且只使用基于 API 的类,但是对于任何中级和高级 Java 开发人员来说,问题中的代码一目了然。就像大多数“技巧”一样,这会给后来阅读它的任何人造成混乱。
  • @Yishai - 好的,我明白你的意思,它可能是旧 API 中最简单的自然比较器,但我可以自己使用 API 实现一个更好的比较器,同样使用 compareTo。谢谢。
  • Comparator&lt;String&gt; reverseOrder = Collections.reverseOrder(); Comparator&lt;String&gt; naturalOrder = Collections.reverseOrder(reverseOrder); 对我来说似乎很容易理解
【解决方案3】:

JDK 没有它,但是它被称为 ComparableComparator,它存在于许多框架中,例如 SpringApache CommonsHibernate 和许多其他框架中

【讨论】:

  • 仅供参考,番石榴称之为Ordering.natural()
【解决方案4】:

我不熟悉 Java 中的默认比较器,但很明显,Comparator to compareTo 通常只是一个包装器。

标准 API 中没有一般的“自然排序”,尽管某些内置类型(如数字)具有 compareTo 的实现,然后成为它们的自然排序。

TreeMapTreeSet 如果您放入的对象没有实现 Comparable,所有这些都应该抛出 RuntimeException。因此,例如,您可以输入字符串或数字,但不能输入另一个集合。

如果比较器不可用,TreeMap 的代码不使用比较器 - 它使用 compareTo 代替。要使用compareTo,它会强制转换为Comparable,这是异常的来源。

    private int compare(K k1, K k2) {
      return (comparator==null ? ((Comparable <K>)k1).compareTo(k2)
                                : comparator.compare((K)k1, (K)k2));
  }

【讨论】:

  • 顺便说一下,在 Java 中 Comparable 实现称为自然排序:filigris.com/products/docflex_javadoc/examples/new/java/lang/…
  • @Yishai:啊。我没有意识到这一点。我会假设 Java 避免使用类似火的术语,因为 compareTo 可能具有任意排序,可能与数学自然排序或源域中的任何排序不匹配。 (例如,字符串的顺序不是“自然的”,因为它不是纯自然语言顺序)
【解决方案5】:

我认为如果一个类具有自然顺序,那么在 Java 中实现Comparable 而不是每个类都有一个Comparator 实现更为常见。

因此,如果所讨论的对象定义了自然顺序,则它们必须实现 Comparable 并定义 compareTo 方法。无需去寻找Comparator。 java.util 中的大多数类要么采用可选的Comparator,如果要强加任何特定的顺序,或者如果没有指定其他顺序,则简单地尝试在对象上调用compareTo

所以,长话短说:只要你想对类强加自然顺序,就实现Comparable,只在你想要自然顺序以外的东西时才使用Comparator

【讨论】:

  • @downvoter:请解释投反对票的原因。很可能我犯了一个错误或完全错了,但如果我(或 OP)不知道它是什么也无济于事。
  • MAK,虽然我没有投反对票,但我也没有投赞成票,因为它回避了问题。有时你希望一个类根据策略模式进行排序(在我的例子中,它是一个更大的字母数字排序的子排序),所以你不想要一个单独的代码路径来进行自然排序(TreeMap 的代码非常难看由于没有这样做,尽管他们这样做可能有性能原因)。
  • 不过,我绝对同意在不发表评论的情况下投反对票。
  • @Yishai:点了。所以,我要说的是:不,Collections 类中没有默认的Comparator - 因为我的回答中所述的原因。如果你觉得有必要,你必须自己动手。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-22
  • 2012-11-07
  • 1970-01-01
  • 2013-09-04
  • 1970-01-01
  • 2014-04-15
  • 1970-01-01
相关资源
最近更新 更多