Java最高

通过。开始使用Spring 5和Spring Boot 2学习的春天课程:

>>查看课程

1.概述

在本教程中,我们将首先看一下Java 8中对Lambda的支持——特别是如何利用它来编写比较器并对集合进行排序

本文是其中的一部分“Java -回归基本”系列Baeldung金宝搏188体育。

进一步阅读:

Java 8流API教程

本文用大量的示例介绍了Java 8 Stream API提供的可能性和操作。

Java 8的收集器指南

本文讨论了Java 8收集器,展示了内置收集器的示例,并展示了如何构建定制收集器。

Lambda表达式和函数接口:技巧和最佳实践

关于使用Java 8 lambdas和功能接口的技巧和最佳实践。

首先,让我们定义一个简单的实体类:

public class Human {private String name;私人int年龄;//标准构造函数,getter /setter, equals和hashcode}

2.没有的基本排序

在Java 8之前,对集合进行排序会涉及到类的匿名内部类比较器用于排序:

new Comparator() {@Override public int compare(Human h1, Human h2) {return h1. getname ().compare (h2. getname ());}}

这将简单地用于排序列表人类实体:

@Test public void givenprelambda_whensortingentitiesbyname_thencrightlsorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));Collections.sort(humans, new Comparator() { @Override public int compare(Human h1, Human h2) { return h1.getName().compareTo(h2.getName()); } }); Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12))); }

3.支持Lambda的基本排序

引入Lambdas后,我们现在可以绕过匿名内部类并实现相同的结果简单、功能语义:

(1. getname ().compareTo(h2. getname ());

类似的-我们现在可以像之前一样测试行为:

@Test public void whensortingentitiesbyname_thenccorrect sorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));humans.sort( (Human h1, Human h2) -> h1.getName().compareTo(h2.getName())); assertThat(humans.get(0), equalTo(new Human("Jack", 12))); }

注意,我们也在使用排序API添加到并不知道在Java 8-代替旧的Collections.sortAPI。

4.没有类型定义的基本排序

我们可以通过不指定类型定义来进一步简化表达式编译器能够推断出这些在自己的:

(h1, h2) -> h1. getname ().compare (h2. getname ())

同样,测试结果也非常相似:

@Test public void givenlambdashortform_whensortingentitiesbyname_thencrightlsorted () {List Human = Lists. ()newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));humans.sort((h1, h2) -> h1.getName().compareTo(h2.getName())); assertThat(humans.get(0), equalTo(new Human("Jack", 12))); }

5.使用引用静态方法排序

接下来,我们将使用Lambda表达式和对静态方法的引用来执行排序。

首先,我们要定义这个方法compareByNameThenAge-签名和比较方法在一个比较人类> <对象:

public static int compareByNameThenAge(Human lhs, Human rhs) {if (lhs.name.equals(hhs .name)) {return Integer.compare(hhs .age, hhs .age);} else{返回lhs.name.compareTo(rhs.name);}}

现在,我们将调用humans.sort参考方法:

humans.sort(人类::compareByNameThenAge);

最终结果是使用静态方法对集合进行工作排序比较器:

@Test public void givenmethoddefinition_whensortingentitiesbynamethenage_thencrightlsorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));humans.sort(人类::compareByNameThenAge);Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));}

6.分类提取的比较器

我们也可以通过使用实例方法参考Comparator.comparing方法——它提取并创建一个类似的基于这个函数。

我们会使用gettergetName ()构建Lambda表达式并按名称对列表进行排序:

@Test public void giveninstancemethod_whensortingentitiesbyname_thencrightlsorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));Collections.sort( humans, Comparator.comparing(Human::getName)); assertThat(humans.get(0), equalTo(new Human("Jack", 12))); }

7.反向排序

JDK 8还为扭转比较器-我们可以快速利用它来逆转我们的排序:

@Test public void whensortingentitiesbynamereversed_theenccorrect sorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));比较器<人类>比较器= (h1, h2) -> h1. getname ().compare (h2. getname ());humans.sort (comparator.reversed ());Assert.assertThat(humans.get(0), equalTo(new Human("Sarah", 10)));}

8.多条件排序

比较lambda表达式不必这么简单——我们可以这样写还有更复杂的表达式—例如先按名称排序,再按年龄排序:

@Test public void whensortingentitiesbynamethenage_thencrightlsorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,12),new Human(“Sarah”,10),new Human(“Zack”,12));humans.sort((lhs, rhs) -> { if (lhs.getName().equals(rhs.getName())) { return Integer.compare(lhs.getAge(), rhs.getAge()); } else { return lhs.getName().compareTo(rhs.getName()); } }); Assert.assertThat(humans.get(0), equalTo(new Human("Sarah", 10))); }

9.用多个条件排序-组合

同样的比较逻辑——首先按名称排序,然后再按年龄排序——也可以通过新的组合支持实现比较器

从JDK 8开始,我们现在可以将多个比较器链接在一起构建更复杂的比较逻辑:

@Test public void givencomposition_whensortingentitiesbynamethenage_thencrightlsorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,12),new Human(“Sarah”,10),new Human(“Zack”,12));humans.sort( Comparator.comparing(Human::getName).thenComparing(Human::getAge) ); Assert.assertThat(humans.get(0), equalTo(new Human("Sarah", 10))); }

10.对列表进行排序Stream.sorted ()

我们还可以使用Java 8对集合进行排序排序()API。

我们可以使用自然排序和a提供的排序对流进行排序比较器。为此,我们有两个重载的排序()API:

  • 排序ed ()- - - - - -对a的元素进行排序用自然排序;元素类必须实现类似的接口。
  • 排序(比较器< ?超级T >压缩空气rator)-根据a对元素进行排序比较器实例

让我们看一个如何做的例子使用排序()自然排序法:

@Test public final void givenstreamnaturalordering_whensortingentitiesbyname_thenccorrect sorted () {List letters = Lists。newArrayList(“A”“B”,“C”);List sortedLetters = letters.stream().sorted().collect(collections . tolist ());为了(sortedLetters.get(0),等于(A));}

现在我们来看看怎么做使用自定义比较器排序()API:

@Test public final void givenstreamcustomordering_whensortingentitiesbyname_thenccorrect sorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));nameComparator = (h1, h2) -> h1. getname ().compareTo(h2. getname ());List sortedHumans = humans.stream().sorted(nameComparator).collect(collections . tolist ());assert (sortedHumans.get(0), equalTo(new Human("Jack", 12)));}

我们可以进一步简化上面的例子使用Comparator.comparing ()方法:

@Test public final void givenstreamcomparatorordering_whensortingentitiesbyname_thencrightlsorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));List sortedHumans = humans.stream() .sorted(comparator . compare (Human::getName)) .collect(collections . tolist ());assert (sortedHumans.get(0), equalTo(new Human("Jack", 12)));}

11.对列表进行反向排序Stream.sorted ()

我们也可以用Stream.sorted ()对集合进行反向排序。

首先,让我们看一个如何做的例子结合排序()方法Comparator.reverseOrder ()以相反的自然顺序对列表进行排序:

@Test public final void givenstreamnaturalordering_whensortingentitiesbynamereversed_thenccorrect sorted () {List letters = Lists。newArrayList(“A”“B”,“C”);List reverseSortedLetters = letters.stream() .sorted(Comparator.reverseOrder()) .collect(collector . tolist ());为了(reverseSortedLetters.get(0),等于(C));}

现在,让我们看看怎么做使用排序()方法和自定义比较器:

@Test public final void givenstreamcustomordering_whensortingentitiesbynamereversed_thenccorrect sorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));/ /比较器<人类> reverseNameComparator = (h1, h2) -> h2. getname ().compareTo(h1. getname ());List reverseSortedHumans = humans.stream().sorted(reverseNameComparator) .collect(collections . tolist ());assert (reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10)));}

注意,调用compareTo是翻转的,也就是翻转的过程。

最后,让我们把上面的例子简化一下使用Comparator.comparing ()方法:

@Test public final void givenstreamcomparatorordering_whensortingentitiesbynamereversed_thenccorrect sorted () {List Human = Lists。newwarraylist (new Human(“Sarah”,10),new Human(“Jack”,12));List reverseSortedHumans = humans.stream() .sorted(comparator . compare (Human::getName, Comparator.reverseOrder())) .collect(collections . tolist ());assert (reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10)));}

12.空值

到目前为止,我们实现了比较器它们不能对包含值。也就是说,如果集合至少包含一个元素,那么排序方法抛出一个NullPointerException:

@Test(expected = NullPointerException.class) public void givenANullElement_whenSortingEntitiesByName_thenThrowsNPE() {List Human = Lists。newwarraylist (null, new Human("Jack", 12));humans.sort((h1, h2) -> h1.getName().compareTo(h2.getName())); }

最简单的解决方案是处理在我们的比较器实现:

@Test public void givenANullElement_whenSortingEntitiesByNameManually_thenMovesTheNullToLast() {List Human = Lists。newwarraylist (null, new Human("Jack", 12), null);humans.sort((h1, h2) -> { if (h1 == null) { return h2 == null ? 0 : 1; } else if (h2 == null) { return -1; } return h1.getName().compareTo(h2.getName()); }); Assert.assertNotNull(humans.get(0)); Assert.assertNull(humans.get(1)); Assert.assertNull(humans.get(2)); }

现在我们在推所有的元素靠近集合的末尾。为此,比较国考虑大于非空值。当两者都是他们被认为是平等的。

此外,我们可以通过任何比较器不是空安全的Comparator.nullsLast ()方法和达到相同的结果:

@Test public void givenANullElement_whenSortingEntitiesByName_thenMovesTheNullToLast() {List Human = Lists。newwarraylist (null, new Human("Jack", 12), null);humans.sort (Comparator.nullsLast (Comparator.comparing(人类::getName)));Assert.assertNotNull (humans.get (0));Assert.assertNull (humans.get (1));Assert.assertNull (humans.get (2));}

类似地,我们可以用Comparator.nullsFirst ()移动指向集合开头的元素:

@Test public void givenANullElement_whenSortingEntitiesByName_thenMovesTheNullToStart() {List Human = Lists。newwarraylist (null, new Human("Jack", 12), null);humans.sort (Comparator.nullsFirst (Comparator.comparing(人类::getName)));Assert.assertNull (humans.get (0));Assert.assertNull (humans.get (1));Assert.assertNotNull (humans.get (2));}

强烈推荐使用nullsFirst ()nullsLast ()装饰器,因为它们更灵活,最重要的是,更易于阅读。

13.结论

这篇文章说明了a列表可以使用Java 8 Lambda表达式排序-越过语法糖,进入真正的和强大的功能语义。

可以找到所有这些示例和代码片段的实现在GitHub

Java底部

通过。开始使用Spring 5和Spring Boot 2学习的春天课程:

>>查看课程
12评论
最古老的
最新的
内联反馈
查看所有评论
本文评论关闭!