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

51

请问谁能给我展示一个在Java 8中使用新的lambda语法如何对ArrayList进行字母排序的快速示例。


2
我建议你阅读这个链接:http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html - Alexis C.
12个回答

73

对于字符串,这将起作用。

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

39
更好的写法:arrayList.sort(String::compareTo)。翻译解释:这是一行Java代码,它使用了Lambda表达式中的方法引用(Method Reference)来调用String类的compareTo()方法,然后对ArrayList中的元素进行排序。 - Brian Goetz
25
更好的写法:arrayList.sort(Comparator.naturalOrder()) - Holger
32
请注意,.sort(String::compareTo).sort(Comparator.naturalOrder())都会在任何小写字母之前对所有大写字母进行排序。通常你需要的是.sort(String::compareToIgnoreCase) - UTF_or_Death

33

你只是在对String进行排序吗?如果是这样,你不需要使用lambda表达式;这没有意义。你只需执行以下操作:

import static java.util.Comparator.*;

list.sort(naturalOrder());

...虽然如果你正在按照String字段对对象进行排序,那么它会更加有意义:

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

9

使用 list.sort(String::compareToIgnoreCase) 方法进行排序。

使用 list.sort(String::compareTo)list.sort(Comparator.naturalOrder()) 将会导致错误的(即非字母顺序)排序结果。这会将任何大写字母排在所有小写字母前面,因此数组["aAAA","Zzz", "zzz"] 会被排序为["Zzz", "aAAA", "zzz"]


8
假设你有一个字符串列表,想要按字母顺序排序。
List<String> result = names.stream().sorted(
                 Comparator.comparing(n->n.toString())).collect(Collectors.toList());

它工作得非常完美。

1
Comparator 是完全不必要的。 - River

4
在函数式编程中,您不是使用旧对象来操作它们,而是以这样的方式创建新对象:
list.stream().sorted().map(blah-blah).filter(...)...

这是不正确的,因为现在流不再由旧元素组成,而是由映射和过滤版本组成。考虑一个你想要按照人名排序的银行账户:如果你像你建议的那样做,那么你开始就有了一个银行账户流,并最终得到了一个人名流,而你希望最终又得到一个银行账户流。 - skiwi
通常情况下,当你以函数式编程的方式编写程序时,你不需要迭代地保存结果。因此,这一切都是一个列表:list.stream().sorted() 不是对旧列表进行排序,而是创建了一个新列表。 - Dmitry Ginzburg
如果你真的想把结果存储在同一个列表中,你可以这样做:list = list.stream().sort().collect(Collectors.toList());,但是作者要求使用Java 8风格,而这就是Java 8风格。 - Dmitry Ginzburg
您现在省略了指定排序运算符,请先获取一个可工作的示例,然后使用该示例更新您的答案。 - skiwi
1
@skiwi 没有必要指定排序运算符,因为 OP 想要按字典顺序对 String 进行排序,这是默认行为。 - Dmitry Ginzburg
显示剩余2条评论

3

不应该把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),但我不建议这样做,因为它不是类型安全的。


2
一个通用的解决方案是引入一些类似于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));

2

最简练:

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

2

如果您有一个具有自然排序的元素数组(即 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);

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

1
 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); - Shahzad

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