美文网首页我爱编程
Java边用边学: 我有5种方法写排序

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

作者: 朱和 | 来源:发表于2018-09-01 23:18 被阅读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。

    讨论/争论开始

    很容易写错的排序

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

    • 都写成e1或e2:
    Integer.compare(e1.getAge(), e1.getAge());
    
    • 比较的属性不一致:
    Integer.compare(e1.getAge(), e2.getLevel());
    
    • e1和e2的前后位置(涉及到倒序还是顺序)
      • 我们的实现3.Named Lambda的排序其实写反了。它的Lambda是倒序(没错啊,我们的业务是需要倒序),问题是它在使用的时候再次反序了下,那就又回到顺序了。
    都写成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())
    );
    

    其解读大概是这样的:

    • 对列表进行排序需要:
      • 嗯,e1和e2应该是前后相邻的两个Employee实例
      • 都取出了年龄来比较
      • e2在前,应该是倒序吧(Code Review的同学比较严谨,查了下Javadoc)。嗯,倒序!

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

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

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

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

    结论

    • 方法引用优先于Lambda
    • 有用的Java类库,譬如Comparator, Collectors

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


    相关文章

      网友评论

        本文标题:Java边用边学: 我有5种方法写排序

        本文链接:https://www.haomeiwen.com/subject/yekpwftx.html