【问题标题】:Collections.sort isn't sortingCollections.sort 没有排序
【发布时间】:2015-05-29 12:23:34
【问题描述】:

我正在使用 Java EE 构建一个 Web 应用程序(尽管我的问题更多基于 Java)

在一个 Servlet 中,我从 EJB 获得一个订单列表。在此订单列表中,有此订单的状态列表(已发送、在码头、未收到...)

我想按州的日期对这个州列表进行排序。所以我像这样使用 Collections.sort:

    for (Command c : commands) {
        c.getStateList().sort(new Comparator<State>() {
                @Override
                public int compare(State o1, State o2) {
                    return o1.getStateDate().compareTo(o2.getStateDate());
                }
        });

        c.getStateList().sort(Collections.reverseOrder());
    }
request.setAttribute("commands", commands);

但是当我显示结果时,状态没有排序。

如您所见,我试图颠倒顺序,但它也不起作用。

您还可以看到,我将 Collections.sort 替换为 ListIWantToSort.sort。还是行不通。

关于它为什么不起作用或如何修复它的任何想法?

编辑:这是列表的getter及其实例:

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "ciiCommande")
    private List<Etat> etatList;

    @XmlTransient
    public List<Etat> getEtatList() {
        return etatList;
    }

    List<Commande> commandes = new ArrayList<Commande>();

我通过 findAll 方法获取命令。

为了显示它们,我使用它:

<c:forEach items="${commandes}" var="cmd">
    <td>${cmd.etatList[0].codeStatut.libelleSituation}</td>
</c:forEach>

【问题讨论】:

  • c.getEtatList() 返回什么?
  • @LutzHorn 它确实返回了订单所采用的状态列表。
  • getEtatList() 中的内容是否实现了Comparable 接口?
  • @trichetriche 这个列表的 type 到底是什么?
  • getEtatList() 是否返回c 内的列表副本?如果是这样,您正在对副本进行排序,然后立即将其丢弃,当您再次输出/使用getEtatList() 时,您会得到另一个未排序的副本。

标签: java sorting jakarta-ee collections


【解决方案1】:

您首先使用自定义比较器对列表进行排序。然后,您将根据元素的反向 自然 顺序重新排序 - 而不是您已经应用的自定义顺序。所以第一个排序没有生效,因为列表被第二个排序重新排序。请注意,Collections.reverseOrder() 反转列表 - 它是 自然 顺序的反转(因此 getEtatList() 中的元素必须已经是 Comparable)。

尝试丢失第二类并做:

c.getEtatList().sort(new Comparator<Etat>() {
    @Override
    public int compare(Etat o1, Etat o2) {
        // Note o2/o1 reversed.
        return o2.getDateEtat().compareTo(o1.getDateEtat());
    }
});

【讨论】:

  • reverseOrder其实是另一种尝试,我没有先用它。不过谢谢你提供的信息,我会记住的
  • getDateEtat() 返回什么?是java.util.Date吗?
【解决方案2】:

试试:

for (Commande c : commandes) {
                c.getEtatList().sort(Collections.reverseOrder(new Comparator<Etat>() {

                    @Override
                    public int compare(Etat o1, Etat o2) {
                        return o1.getDateEtat().compareTo(o2.getDateEtat());
                    }
                }));
            }

由于你使用的排序方法已经被添加到Java SE 8的List接口中,我猜你使用的是Java SE 8。那么你可以重写如下:

commandes.foreach(c -> 
  c.getEtatList().sort(Comparator.comparing(Etat::getDateEtat).reversed());
);

【讨论】:

  • 没有错误,一切编译正常。但是在我的应用程序中,它没有显示“已交付”(应该是最后一个状态),而是显示“未交付”(这是前一个状态)。仅供参考,我正在获得列表的第一个结果以显示此状态。
  • 您的第二个解决方案中有一些括号错误,但即使在更正之后,它也不起作用。
  • @trichetriche dateEtat 的类型是什么,可能的值是什么?
  • dateEtat 是一个日期,它可以采用该类型的所有可能值。但在我的数据库中,它从 01.05.2015 到 31.05.2015
  • 在“未交付”的情况下,dateEtat 的值是多少?
【解决方案3】:

这应该是你需要的:

    Comparator<Etat> comparator = new Comparator<Etat>() {
        @Override
        public int compare(Etat o1, Etat o2) {
            return o1.getDateEtat().compareTo(o2.getDateEtat());
        }
    };

    for (Commande c : commandes) {
        Collections.sort(c.getEtatList(), comparator);
        // or this one: Collections.sort(c.getEtatList(), Collections.reverseOrder(comparator));
    }

【讨论】:

  • 不抱歉,也不工作。 (我也尝试过相反的顺序)
  • getStateList()Command 类中的实际类型是什么?有人假设它是List&lt;State&gt;,或者?
  • 是的,它是List&lt;Etat&gt;(法语状态):private List&lt;Etat&gt; etatList;
  • getEtatList() 方法只是一个吸气剂,对吧?它不复制列表?实际上,您可以粘贴该方法的代码,以及通过new 发起etatList 的位置...
  • 你如何在 html 页面中显示命令列表?如果是jsp,还是怎么做?你能也显示演示代码吗?
【解决方案4】:

这按预期工作,您的问题出在其他地方:

public static void main(String[] args) {
  List<State> states = Arrays.asList(new State(2015, 1, 1),
                                     new State(2014, 1, 1),
                                     new State(2016, 1, 1));
  System.out.println(states); //not ordered
  states.sort(new Comparator<State>() {
    @Override public int compare(State o1, State o2) {
      return o1.getStateDate().compareTo(o2.getStateDate());
    }
  });
  System.out.println(states); //ordered
}

public static class State {
  private final LocalDate stateDate;
  public State(int year, int month, int day) {
    this.stateDate = LocalDate.of(year, month, day);
  }
  public LocalDate getStateDate() { return stateDate; }
  @Override public String toString() { return stateDate.toString(); }
}

请注意,您似乎使用的是 Java 8,并且可以编写比较器:

states.sort(comparing(State::getStateDate));

【讨论】:

  • 您可以尝试创建一个名为 Command 的新类,将状态列表作为属性吗?然后创建一个命令列表,并尝试对每个状态列表进行排序
  • @trichetriche 这不会有什么不同,如果一个列表可以排序,几个列表也可以排序(除非你在命令类中搞砸了并且正在共享一个列表或发送一个副本或.... - 但我猜不出你做了什么)。您应该阅读我在之前评论中发布的 MCVE 链接并遵循其建议。
  • 我的课程保持不变,因为我将它们作为实体类。而且我的代码很长,这就是为什么我不能真正专注于创建一个好的示例。也许如果我创建一个 git 存储库?
【解决方案5】:

经过几天的努力,我设法找到了解决方案。

我每次尝试后都不会对列表进行排序。我仍然不知道为什么。

但是我找到了一个注释 @OrderBy,它可以按照我想要的方式对列表进行排序。

谢谢大家的帮助,也许有一天这个问题会被解决(看到双关语吗?我很有趣)。

干杯

【讨论】:

    【解决方案6】:

    感谢您的提问,因为我刚刚经历过。我在我的 JPA Entity 类上实现了“Comparable”(就像我在其他很多次所做的那样)。在 myMainJPA_Object.getMyList() 上执行 Collections.sort 时,不会调用覆盖的可比较方法。

    我的解决方法是创建一个新列表作为 ArrayList(例如),执行 .addAll(myObject.getMyList()),然后在该新列表上执行 Collections.sort,然后排序工作(我的可比较的方法在排序上被调用)。例如:

    List<ObjectsToSort> tempList = new ArrayList<>();
    tempList.addAll(jpaEntity.getListOfStuff());
    Collections.sort(tempList);
    //Then you could set the list again
    jpaEntity.setListOfStuff(tempList);
    

    我真的不喜欢这个解决方案,但我不知道任何其他解决方法,也没有发现任何关于这个问题的信息(直到你的帖子)。我喜欢你的 @OrderBy 注释建议,在我的情况下,虽然我需要在不同的方法调用上再次重新排序,所以这个解决方案对我有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-12
      • 1970-01-01
      • 2018-10-11
      • 1970-01-01
      • 2019-12-01
      • 2019-03-06
      • 2012-07-15
      • 2019-02-17
      相关资源
      最近更新 更多