Java 8 进阶手册(XX):使用 Comparator 对列表进行排序
Posted mickjoust
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 8 进阶手册(XX):使用 Comparator 对列表进行排序相关的知识,希望对你有一定的参考价值。
目录
- 按字母顺序排序
- 对整数排序
- 按字符串字段排序
- 按双字段排序
- 使用自定义比较器排序
- .使用比较器链排序
- 小结
1.按字母顺序排序
List<String> cities = Arrays.asList(
"mickjoust",
"chengdu",
"sichuan",
"china",
"java8"
);
System.out.println(cities);
//打印:[mickjoust, chengdu, sichuan, China, Java8]
cities.sort(String.CASE_INSENSITIVE_ORDER);
System.out.println(cities);
//打印:[chengdu, China, Java8, mickjoust, sichuan]
cities.sort(Comparator.naturalOrder());
System.out.println(cities);
//打印:[China, Java8, chengdu, mickjoust, sichuan]
我写了一个小写的“ C”,以更好地突出Comparator.naturalOrder()和String.CASE_INSENSITIVE_ORDER之间的区别,Comparator.naturalOrder()返回一个以大写字母开头的 Comparator,String则不区分大小写。
在Java 7中,我们习惯先使用Collections.sort() 来排序,先是List,再是Comparator;而在Java 8中,我们有了一个新的方法:List.sort(),它接受一个Comparator。
2.对整数排序
List<Integer> numbers = Arrays.asList(6, 2, 1, 4, 9);
System.out.println(numbers);
//[6, 2, 1, 4, 9]
numbers.sort(Comparator.naturalOrder());
System.out.println(numbers);
//[1, 2, 4, 6, 9]
这个很容易理解,数字的先后顺序。
3.按字符串字段排序
假设,我们有Movie类,并且想按照标题对列表 List 进行排序。 在本示例中,我们可以使用Comparator.comparing()并传递一个函数,该函数提取用于排序的:字段-标题。
@Getter
@Setter
@AllArgsConstructor
@ToString
static class Movie
private String title;
List<Movie> movies = Arrays.asList(
new Movie("《指环王》"),
new Movie("《肖申克的救赎》"),
new Movie("《星球大战》"),
new Movie("《我和我的祖国》"));
movies.sort(Comparator.comparing(Movie::getTitle));
movies.forEach(System.out::println);
打印是:
Java8Pro.Movie(title=《我和我的祖国》)
Java8Pro.Movie(title=《指环王》)
Java8Pro.Movie(title=《星球大战》)
Java8Pro.Movie(title=《肖申克的救赎》)
你可能已经注意到,我们没有通过比较器 Comparator ,但是列表已正确排序。 这是因为标题(提取的字段)是一个字符串,并且字符串实现了Comparable接口。 如果您查看Comparator.comparing()实现,将会看到它在apply时其实调用了compareTo。
4.按双字段排序
以类似的方式,我们可以使用Comparator.comparingDouble()来比较double值。 在示例中,我们要按等级从最高到最低排序电影列表。
List<Movie> movies = Arrays.asList(
new Movie("《指环王》", 8.8),
new Movie("《肖申克的救赎》", 9.1),
new Movie("《星球大战》)", 8.0),
new Movie("《我和我的祖国》", 10.0));
movies.sort(Comparator.comparingDouble(Movie::getRating).reversed());
movies.forEach(System.out::println);
打印是:
Java8Pro.Movie(title=《我和我的祖国》, rating=10.0)
Java8Pro.Movie(title=《肖申克的救赎》, rating=9.1)
Java8Pro.Movie(title=《指环王》, rating=8.8)
Java8Pro.Movie(title=《星球大战》), rating=8.0)
为了不使用默认的自然顺序,我们在Comparator上用了reverse反转函数。 即从最高到最低。 Comparator.comparingDouble()在后台使用Double.compare()。
如果需要比较int或long,则可以分别使用compareInt()和compareingLong()。
5.使用自定义比较器排序
在前面的示例中,我们没有指定任何比较器,但是我们想要自定义比较器的。例如,我们的Movie类具有一个新字段——“stard”,该字段使用第三个构造函数参数设置。 在代码示例中,我们要对列表进行排序,以便在列表顶部为已加星标的电影打星。
List<Movie> movies = Arrays.asList(
new Movie("《指环王》", 8.8, true),
new Movie("《肖申克的救赎》", 9.1, false),
new Movie("《星球大战》)", 8.0, true),
new Movie("《我和我的祖国》", 10.0, false));
movies.sort(new Comparator<Movie>()
@Override
public int compare(Movie m1, Movie m2)
if(m1.getStarred() == m2.getStarred())
return 0;
return m1.getStarred() ? -1 : 1;
);
movies.forEach(System.out::println);
打印是:
Java8Pro.Movie(title=《指环王》, rating=8.8, starred=true)
Java8Pro.Movie(title=《星球大战》), rating=8.0, starred=true)
Java8Pro.Movie(title=《肖申克的救赎》, rating=9.1, starred=false)
Java8Pro.Movie(title=《我和我的祖国》, rating=10.0, starred=false)
当然,我们也可以使用 lambda 表达式代替匿名类,如下所示:
movies2.sort((m1, m2) ->
if(m1.getStarred() == m2.getStarred())
return 0;
return m1.getStarred() ? -1 : 1;
);
movies2.forEach(System.out::println);
我们还可以再次使用Comparator.comparing():
movies2.sort(Comparator.comparing(Movie::getStarred, (star1, star2) ->
if(star1 == star2)
return 0;
return star1 ? -1 : 1;
));
在最后一个示例中,Comparator.comparing() 使用函数来提取用于排序的键作为第一个参数,并使用 Comparator 作为第二个参数。 该比较器使用 apply 进行比较。 star1 和star2 是布尔值,分别代表m1.getStarred() 和 m2.getStarred() 。
6.使用比较器链排序
在最后一个示例中,我们希望在加星标或不加星标的电影中按评分排序。
List<Movie> movies3 = Arrays.asList(
new Movie("《指环王》", 8.8, true),
new Movie("《肖申克的救赎》", 9.1, false),
new Movie("《星球大战》)", 8.0, true),
new Movie("《我和我的祖国》", 10.0, false));
movies3.sort(Comparator.comparing(Movie::getStarred)
.reversed()
.thenComparing(Comparator.comparing(Movie::getRating)
.reversed())
);
movies3.forEach(System.out::println);
打印是:
Java8Pro.Movie(title=《指环王》, rating=8.8, starred=true)
Java8Pro.Movie(title=《星球大战》), rating=8.0, starred=true)
Java8Pro.Movie(title=《我和我的祖国》, rating=10.0, starred=false)
Java8Pro.Movie(title=《肖申克的救赎》, rating=9.1, starred=false)
如你所见,我们首先按星标排序,然后按评分排序,没有星标的也按评分排序。
小结
本文简答介绍了Java 8 中比较器的用法,和Java 7 不同的是,我们有更多的排序选择可共使用。
附:完整代码
public class Java8Pro
public static void main(String[] args)
List<String> cities = Arrays.asList(
"mickjoust",
"chengdu",
"sichuan",
"China",
"Java8"
);
System.out.println(cities);
cities.sort(String.CASE_INSENSITIVE_ORDER);
System.out.println(cities);
cities.sort(Comparator.naturalOrder());
System.out.println(cities);
List<Integer> numbers = Arrays.asList(6, 2, 1, 4, 9);
System.out.println(numbers);
numbers.sort(Comparator.naturalOrder());
System.out.println(numbers);
List<Movie> movies = Arrays.asList(
new Movie("《指环王》"),
new Movie("《肖申克的救赎》"),
new Movie("《星球大战》"),
new Movie("《我和我的祖国》"));
movies.sort(Comparator.comparing(Movie::getTitle));
movies.forEach(System.out::println);
List<Movie> movies1 = Arrays.asList(
new Movie("《指环王》", 8.8),
new Movie("《肖申克的救赎》", 9.1),
new Movie("《星球大战》)", 8.0),
new Movie("《我和我的祖国》", 10.0));
movies1.sort(Comparator.comparingDouble(Movie::getRating).reversed());
movies1.forEach(System.out::println);
List<Movie> movies2 = Arrays.asList(
new Movie("《指环王》", 8.8, true),
new Movie("《肖申克的救赎》", 9.1, false),
new Movie("《星球大战》)", 8.0, true),
new Movie("《我和我的祖国》", 10.0, false));
// movies2.sort((m1, m2) ->
// if(m1.getStarred() == m2.getStarred())
// return 0;
//
// return m1.getStarred() ? -1 : 1;
// );
movies2.sort(Comparator.comparing(Movie::getStarred, (star1, star2) ->
if(star1 == star2)
return 0;
return star1 ? -1 : 1;
));
movies2.forEach(System.out::println);
List<Movie> movies3 = Arrays.asList(
new Movie("《指环王》", 8.8, true),
new Movie("《肖申克的救赎》", 9.1, false),
new Movie("《星球大战》)", 8.0, true),
new Movie("《我和我的祖国》", 10.0, false));
movies3.sort(Comparator.comparing(Movie::getStarred)
.reversed()
.thenComparing(Comparator.comparing(Movie::getRating)
.reversed())
);
movies3.forEach(System.out::println);
@Getter
@Setter
@AllArgsConstructor
@ToString
static class Movie
private String title;
private Double rating;
private Boolean starred;
public Movie(String title)
this.title = title;
public Movie(String title, Double rating)
this.title = title;
this.rating = rating;
以上是关于Java 8 进阶手册(XX):使用 Comparator 对列表进行排序的主要内容,如果未能解决你的问题,请参考以下文章
Java 8 进阶手册(XX):使用 Comparator 对列表进行排序
Java 8 进阶手册(XX):使用 Comparator 对列表进行排序
Android 工程师进阶手册(8 年 Android 开发者的成长感悟)