Java 8流如何进行动态排序?

4
长话短说,我正在使用JDBI DAO访问数据。在查询中使用动态顺序很困难。因此,我计划在查询结果获取后使用Java 8流作为后处理步骤来执行此操作。
问题在于比较器的工作方式需要静态声明对象的方法。
shepherds = shepherds.stream()
    .sorted(Comparator.comparing(Shepherd::getId).reversed())
    .collect(Collectors.toList());

我该如何动态地处理像这样的变量?
请注意,我将保留原始文本中的HTML标记。
orderBy = id
orderDirection = ASC

所以我可以将这个方法调用参数化吗?

例如:

if(orderDirection.equals("ASC"))
    shepherds.stream().sorted(Comparator.comparing(orderBy));
else
    shepherds.stream().sorted(Comparator.comparing(orderBy).reversed());

1
既然流没有“解决”您的原始问题,那么您可能会忘记它。在数据库中进行排序,如果您无法让JDBI弯曲,那就用另一种方式来做。 - Kayaman
2
嘿,标题可能在谈论使用流进行排序,但实际问题是使用JDBI进行排序,对此有一个解决方案在duplicate中。仅仅因为你不知道如何做A,并不意味着你应该用B来做得很差。 - Kayaman
3
在数据库中始终应该进行排序。通过(可能的)http 将整个结果集流式传输到您的应用程序中仅仅是为了“找出”原本排序错误,并且只需要最后的十行,这是不值得的。这完全不能扩展。 - M. Prokhorov
如果它在第三个主要版本中仍然没有提供排序功能,我会说他们还有很长的路要走。然而,原始SQL现在很流行,我会坚持使用它,而不是使用可怕的Hibernate。 - tomaytotomato
除了数据库的讨论之外,如果需要,可以使用Comparator.comparing(-orderBy)来代替反向顺序的样板代码。 - user unknown
显示剩余7条评论
1个回答

2

最简单的方法可能是构建一个Map(除非您在数据库端真的无法这样做,这应该是您的主要关注点),其中Key看起来像:

class Key {
    String field;
    Direction direction; // enum
    // getters/setters/hashcode/equals
}

只需提前创建此Map

Map<Key, Comparator<Shepherd>> map = new HashMap<>();
map.put(new Key("id", Direction.ASC), Comparator.comparing(Shepard::getId))
map.put(new Key("id", Direction.DESC), Comparator.comparing(Shepard::getId).reversed())

我认为另一种方法是通过LambdaMetafactory来实现真正的动态创建,但这相当复杂。


1
如果您只存储字段作为键,并使用它来检索比较器,然后如果方向是DESC,则调用比较器上的reversed方法,可能会更清晰。这样,您根本不需要Key类,并且可以将映射中的项目数量减少一半。 - Alexandru Severin
@AlexandruSeverin 对,你也可以这样做。我不会担心空间问题,但我仍然会创建Key类,以便检索快速(O(1)),而无需进行任何额外的后处理(if/else)。但是,当然,你的想法也有道理。 - Eugene
2
你可以使用Array.asList("id", Direction.ASC)等或者更好的是在使用Java 9时使用List.of("id", Direction.ASC),而不是Key类。 - Holger
我还会使用Comparator<? super Shepherd>作为值的类型,这样可以使用比较器来比较Shepherd的超类型。 - fps
@FedericoPeraltaSchaffner 没错,即使我从未在实际代码中使用过,可能也从未遇到需要这样做的示例;但是这是一个好观点。 - Eugene

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接