我爱编程

Java边用边学: 我有5种方法写排序

2018-09-01  本文已影响0人  朱和

需求及代码分析

下面的一段简单的排序代码(按照员工的年龄的倒序排列),可以有大概这么5种写法:

final List<Employee> employees = ...;

// 1.匿名类
employees.sort(new Comparator<Employee>() {
  @Override
  public int compare(Employee e1, Employee e2) {
    return Integer.compare(e1.getAge(), e2.getAge());
  }
}.reversed());

// 2.Lambda
// e2在前,倒序
employees.sort(
  (e1, e2) -> Integer.compare(e2.getAge(), e1.getAge())
);

// 3.Named Lambda
final Comparator<Employee> comparator = 
    (e1, e2) -> Integer.compare(e1.getAge(), e2.getAge());
employees.sort(comparator.reversed());

// 4.复用 + Lambda
employees.sort(
  comparingInt((Employee e) -> e.getAge()).reversed()
);

// 5.复用 + 方法引用
employees.sort(
  comparingInt(Employee::getAge).reversed()
);
  1. 匿名类

没什么好说的,Java 8之前的经典写法了。(至于是不是需要调用reversed()还是直接把e2放在e1前面,这个后面有答案)

  1. Lambda

Java 8+的Lambda,由于需要实现倒序,所以程序猿很注意的把e2写在了e1前面了(并配有完美的注释)

  1. 命名的Lambda

由于Lambda是没有名字的,所以想给它来个倒序,不得不给它先取个名字,然后就可以直接调用reversed()来声明我这个是倒序啊!

  1. 复用 + Lambda

Java自带的类库其实已经很丰富了,所以直接拿来用吧:Comparator.comparingInt(ToIntFunction)完美符合当前需求,用一段Lambda实现了ToIntFunction。

  1. 复用 + 方法引用

同上,用方法引用替换了Lambda。

讨论/争论开始

很容易写错的排序

这个排序看上去简单,但其实写错也很容易,大概的错误点包括:

Integer.compare(e1.getAge(), e1.getAge());
Integer.compare(e1.getAge(), e2.getLevel());
都写成e1/e2 比较的属性不一致 e1和e2的前后位置
#1.匿名类 中招 中招 中招
#2.Lambda 中招 中招 中招
#3.命名的Lambda 中招 中招 中招
#4.复用+Lambda
#5.复用+方法引用

实现#4和#5就很聪明,直接用Java的类库,正确性完全有保证(e1和e2的谁前谁后无需关心)。对于倒序则简单的调用下reversed(),完事!另外#5的方法引用让可读性更进一步。

亲民的函数式编程

从左到右读完这句

employees.sort(
    comparingInt(Employee::getAge).reversed()
);

大概可以获得下列信息:

就这么读过,代码的自说明能力完整的表述了其功能。

然后我们对比下#2.Lambda:

employees.sort(
  (e1, e2) -> Integer.compare(e2.getAge(), e1.getAge())
);

其解读大概是这样的:

如果需求再复杂点,那我们第5种的优势会更明显。

譬如先按年龄的倒序排列,如果年龄相同,则按性别的顺序排列:

employees.sort(
    comparingInt(Employee::getAge).reversed()   // 年龄(倒序)
    .thenComparing(Employee::getGender)        // 第二序列是性别(顺序)
);

换成其他几种写法,估计很难一眼看懂了。

结论

希望这篇博文能对你有所帮助,喜欢的话点个赞吧!


上一篇下一篇

猜你喜欢

热点阅读