【问题标题】:Return sorted list in Java在Java中返回排序列表
【发布时间】:2012-05-22 19:25:04
【问题描述】:

我正在编写这样的代码:

List<Bean> beans = service.findBeans();
Collections.sort(beans, new BeanComparator());
return beans;

完美运行。我正在寻找的是一条捷径,只需一行:

return somelibrary.Collections.sort(service.findBeans(), new BeanComparator());

或者:

return somelibrary.newList(service.findBeans(), new BeanComparator());

请注意,它需要一个可变列表。

【问题讨论】:

  • 原版有什么问题?
  • 如果库只是在做与Collections.sort 已经提供的完全相同的事情,那么它的目的是什么?
  • 您的原始代码看起来很棒。为什么要改变它?在我看来,三行比一行好。为什么人们认为将一堆代码塞进一行更好?保持原样,享受可读性!
  • 是java,大部分东西需要不止一行。
  • @Marko 这里真正的问题不是一个版本比另一个版本长,或者我们必须添加另一个依赖项。 如果提议的 API 设计良好且有意义,我会是第一个希望将其添加到标准 API 中的人(尽管有一长串真正明智的好功能,但集合 API 很糟糕失踪)。真正的问题是就地排序不应该返回其输入参数,因为这会导致糟糕的 API 设计。大多数人会期望一个返回集合的sort,返回输入参数的排序副本

标签: java oop sorting collections refactoring


【解决方案1】:

这是一行:

List<Bean> beans = service.findBeans(); Collections.sort(beans, new BeanComparator()); return beans;

但更严重的是,Java 并不是真正适合单行代码的语言。此外,仅仅因为某些东西是单线的,并不意味着它会更好。例如,我最初惊讶地发现:

return condition ? a : b;

创建比

更长的字节码
if( condition )
    return a;
else
    return b;

但这就是语言和编译器的样子。

如果你坚持你的单线,GuavaOrdering可以做到:

return Ordering.from( new BeanComparator() ).sortedCopy( service.findBeans() );

返回的列表是可修改的、可序列化的,并且可以随机访问。

效率方面,我认为在开销方面有点浪费。而且您现在还依赖于第 3 方库。您实际上是在使用非常强大的工具来完成一项非常简单的任务。如果你只使用它,那就太过分了。

【讨论】:

  • @thereality 还有像 perl 这样的东西 ;) 我不认为第一个版本特别混乱。一个就地排序但返回对输入参数的引用的sort 版本在 imo 中设计得很糟糕,因为大多数人会期望从这样的 API 返回排序后的副本并且输入参数保持不变。 Python - 一种通常在简短和可读性之间保持相当好的平衡的语言(比 java 更好) - 对于给定的问题看起来几乎相同。
  • @trutheality - 是的......我想我的陈述有点宽泛。只是想向那些喜欢编写长而难以阅读的代码行的人传达一个观点;)
  • @trutheality 感谢批评者和 Guava 选项。
【解决方案2】:

我相信下面的函数会产生你想要的结果。只需将其放在您选择的类中即可。

public static <T> List<T> sort(List<T> list, Comparator<? super T> compare) {
    Collections.sort(list, compare);
    return list;
}

【讨论】:

    【解决方案3】:

    您可以使用 apache CollectionUtils 将列表与比较器和空列表进行比较。

    CollectionUtils.collate(service.findBeans().iterator(),Collections.EMPTY_LIST.iterator(),new beanComparator())
    

    CollectionUtils 确实应该添加一个返回排序列表的实用方法...

    对使用更多行的经典反驳是记录。出于可读性目的而进行的日志记录不应超过一行。当您试图找出代码实际在做什么时,日志记录是一种静态噪音,但日志记录是相当关键的。

    所以日志记录应该是紧凑的(一行)和安静的(不应该抛出异常/是空安全的)并且应该是高性能的(如果关闭不应该引入超出 isDebugOn() 检查的额外处理。

    第二个反驳是流利的界面,例如 JOOQ,它变得越来越流行。

    【讨论】:

      【解决方案4】:

      我猜如果你没有重复并且不介意你可以使用的 hacky 代码:

      return new ArrayList<Bean>(new TreeSet<Bean>(service.findBeans()));
      

      【讨论】:

      • 不幸的是,这种方法使用自然排序进行排序,不允许我们使用自定义比较器。
      【解决方案5】:

      我认为发布的原始问题是有效的。因为“Collections.sort(..)”方法具有对传入的集合进行排序的预期副作用,所以如果您想维护原始集合,则必须执行以下操作:

      List<Bean> beans = service.findBeans();
      List<Bean> sortedBeans = new ArrayList<Bean>(beans);
      Collections.sort(sortedBeans, new BeanComparator());
      return sortedBeans;
      

      在上述情况下,我们对服务方法返回的 Collection 进行排序可能没什么大不了的。但是,如果我们要排序的 Collection 是一个方法参数,而调用者不希望传入的 Collection 被排序呢?

      我通常更喜欢没有后果的方法。

      由于“Collections.sort(..)”影响列表,我只好写如下代码:

      public void doSomethingWithBeansInOrder(List<Bean> beans) {
          Collection<Bean> sortedBeans = new ArrayList<Bean>(beans);
          Collections.sort(sortedBeans, ...comparator...;
      
          for (Bean bean : sortedBeans) {
              .. do something
          }
      }
      

      我觉得“sortedBeans”的定义很丑。

      如果 "(Collections.sort(..)" (或类似的东西)返回一个新的 Collection 并且不影响传入的 Collection,我可以这样写:

      public void doSomethingWithBeansInOrder(List<Bean> beans) {
          for (Bean bean : Collections.sort(beans, ...comparator...) {
              .. do something
          }
      }
      

      在我看来,GuavaOrdering 的答案是最好的。

      【讨论】:

        【解决方案6】:

        首先,Java 8 在List 接口上引入了sort() 方法。因此,对实际列表进行排序的示例是:

        List<Integer> integerList = Arrays.asList(3, 2, 1);
        integerList.sort(Comparator.naturalOrder());
        return integerList;
        

        在这里,我使用了预定义的naturalOrder() 比较器,它又依赖于Comparable,但也可以使用自定义比较器。这仍然需要两个语句。

        但是,如果所需的行为是创建一个新的排序列表,并保持原来的状态不变,我想流将是最简单的方法:

        integerList.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
        

        这里的比较器也一样。

        【讨论】:

          猜你喜欢
          • 2016-06-13
          • 2021-09-07
          • 1970-01-01
          • 2016-05-20
          • 1970-01-01
          • 2016-08-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多