在 Java 8 中使用 Lambda 对 ArrayList 进行排序

Posted

技术标签:

【中文标题】在 Java 8 中使用 Lambda 对 ArrayList 进行排序【英文标题】:Sorting ArrayList with Lambda in Java 8 【发布时间】:2014-07-05 07:11:57 【问题描述】:

有人可以向我展示一个简单的示例,如何使用新的 lambda 语法在 Java 8 中按字母顺序对 ArrayList 进行排序。

【问题讨论】:

我建议你阅读这个:docs.oracle.com/javase/tutorial/java/javaOO/… 【参考方案1】:

对于字符串,这会起作用

arrayList.sort((p1, p2) -> p1.compareTo(p2));

【讨论】:

更好:arrayList.sort(String::compareTo) 更好:arrayList.sort(Comparator.naturalOrder()) 请注意,.sort(String::compareTo) and .sort(Comparator.naturalOrder()) 都会将 all 大写字母排在任何小写字母之前。通常你想要的是.sort(String::compareToIgnoreCase)【参考方案2】:

您只是在对Strings 进行排序吗?如果是这样,您不需要 lambda;毫无意义。你只是这样做

import static java.util.Comparator.*;

list.sort(naturalOrder());

...虽然如果您使用 String 字段对对象进行排序,那么它会更有意义:

list.sort(comparing(Foo::getString));

【讨论】:

【参考方案3】:

使用list.sort(String::compareToIgnoreCase)

使用list.sort(String::compareTo)list.sort(Comparator.naturalOrder()) 会给出不正确(即非字母)的结果。它将在 all 小写字母之前对 any 大写字母进行排序,因此数组 ["aAAA","Zzz", "zzz"] 被排序为 ["Zzz", "aAAA", "zzz"]

【讨论】:

【参考方案4】:

假设您有想要按字母顺序排序的名称列表(字符串)。

List<String> result = names.stream().sorted(
                 Comparator.comparing(n->n.toString())).collect(Collectors.toList());

它工作得很好。

【讨论】:

Comparator 完全不需要。【参考方案5】:

在函数式编程中,您不是使用旧对象来操作它们,而是以这种方式创建新对象:

list.stream().sorted().map(blah-blah).filter(...)...

【讨论】:

这是不正确的,因为现在流不再包含旧元素,而是映射和过滤的版本。考虑一个你想按人名排序的银行账户:如果你按照你的建议去做,那么你从一个银行账户流开始,到一个人名流结束,而你想以一个又是银行账户流。 一般来说,当你用 FP 风格编写程序时,你不需要迭代保存结果。所以,这一切都是一个列表:list.stream().sorted() 不是对旧列表进行排序,而是创建新列表。 而该列表刚刚变得毫无用处,因为您留下了此人的姓名(在我的示例中),并且您不能再将其(直接)引用回他们的银行帐户. 另外,可能是您的困惑(无可指责)的根源是 OP 请求了一种对列表进行排序的方法,但您只返回一个中间流,您还需要将其存储在某些点,您从答案中省略了。通过尝试实现这一点,您自己也可能会看到问题。 @skiwi 不需要指定排序运算符,因为 OP 想要按字典顺序对 Strings 进行排序,这是默认行为。【参考方案6】:

Lambda 不应该是目标。在您的情况下,您可以像在 Java 1.2 中一样对其进行排序:

Collections.sort(list); // case sensitive
Collections.sort(list, String.CASE_INSENSITIVE_ORDER); // case insensitive

如果你想用 Java 8 的方式来做:

list.sort(Comparator.naturalOrder()); // case sensitive
list.sort(String.CASE_INSENSITIVE_ORDER); // case insensitive

您也可以使用list.sort(null),但我不建议这样做,因为它不是类型安全的。

【讨论】:

【参考方案7】:

一个真正通用的解决方案是引入一些 StreamUtil 之类的

public class StreamUtil 

    private StreamUtil() 
           

    @SuppressWarnings( "rawtypes", "unchecked" )
    public static <TYPE> Comparator<TYPE> sort(Function<TYPE, ? extends Comparable> getterFunction, boolean descending) 
        if (descending) 
            return (o1, o2) -> getterFunction.apply(o2).compareTo(getterFunction.apply(o1));
        
        return (o1, o2) -> getterFunction.apply(o1).compareTo(getterFunction.apply(o2));
    


调用看起来像

list.stream().sorted(sort(YourClass::getSortProperty, true));

【讨论】:

【参考方案8】:

最简洁:

Collections.sort(stringList, String::compareToIgnoreCase);

【讨论】:

【参考方案9】:

如果您有一个包含自然排序元素的数组(即Stringintdouble);那么可以通过以下方式实现:

List<String> myList = new ArrayList<>();
myList.add("A");
myList.add("D");
myList.add("C");
myList.add("B");
myList.sort(Comparator.comparing(s -> s));
myList.forEach(System.out::println);

另一方面,如果您有一个对象数组,并且您想根据某种对象字段进行排序,那么您可以使用:

class User 
    double score;
    // Constructor // Getters // Setters


List<User> users = new ArrayList<>();
users.add(new User(19d));
users.add(new User(67d));
users.add(new User(50d));
users.add(new User(91d));

List<User> sortedUsers = users
        .stream()
        .sorted(Comparator.comparing(User::getScore))
        .collect(Collectors.toList());

sortedUsers.forEach(System.out::println);

如果排序更复杂,那么您必须编写自己的比较器并将其传入。

【讨论】:

【参考方案10】:
 List<Product> list = new ArrayList<>();
        List<String> list1 = new ArrayList<>();
        list.add(new Product(1));
        list.add(new Product(2));
        list.add(new Product(3));
        list.add(new Product(10));
 Collections.sort(list, Comparator.comparing((Product p) -> p.id));
        for (Product p : list) 
            System.out.println(p.id);
        

【讨论】:

坚持函数式编程,for (Product p : list) System.out.println(p.id); 可以写成 list.stream().forEach(System.out::println);【参考方案11】:

包含自定义比较器的语法非常简单快捷,例如这里被排序的 ArrayList 包含 JSONObjects,我将根据名为“order”的属性对其进行排序:

arrayList.sort((JSONObject o1, JSONObject o2)->o1.getInt("order")-o2.getInt("order"));

我认为这是一种非常简洁明了的语法,易于阅读并且比非 lambda 语法更简洁。

【讨论】:

以上是关于在 Java 8 中使用 Lambda 对 ArrayList 进行排序的主要内容,如果未能解决你的问题,请参考以下文章

[Java 8] Lambda表达式对递归的优化(上) - 使用尾递归 .

重点知识学习--[Java 8 之 Lambda 表达式]

Java 8 中的 Lambda 表达式

Java 8新特性:学习如何使用Lambda表达式,一看必懂

Java ASM系列:(067)Java 8 Lambda原理探究

Java 8 lambda表达式20180404