使用lambda表达式简化代码

最近阅读《Java8 in action》, Java8的一个重要的变化就是更好地支持行为参数化,这也是函数式编程范式的基础。传统命令式编程的目的是操作值,一切围绕值来展开,参数传递依也是赖值,但是Scala和Groovy等编程语言已经证明,方法参数化是正确的选择,应该让方法成为一等公民,他可以让代码更加简单,并且表达更直观丰富。Java8从语言层面支持了方法引用和lambda表达式。

lambda表达式是一个匿名函数,它基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。 要理解lambda表达式,首先要了解的是函数式接口(functional interface)。简单来说,函数式接口是只包含一个抽象方法的接口。比如Java标准库中的java.lang.Runnable和java.util.Comparator都是典型的函数式接口。对于函数式接口,除了可以使用Java中标准的方法来创建实现对象之外,还可以使用lambda表达式来创建实现对象。这可以在很大程度上简化代码的实现。在使用lambda表达式时,只需要提供形式参数和方法体。由于函数式接口只有一个抽象方法,所以通过lambda表达式声明的方法体就肯定是这个唯一的抽象方法的实现,而且形式参数的类型可以根据方法的类型声明进行自动推断。

具体关于函数式编程的思想,Java8对lambda表达式的支持,可以参考一下博客:
http://www.ruanyifeng.com/blog/2012/04/functional_programming.html
https://www.ibm.com/developerworks/cn/java/j-ft20/index.html
http://www.infoq.com/cn/articles/Java-se-8-lambda
http://www.importnew.com/16436.html

Lambda表达式的基本语法:

(parameters) -> expression
or
(parameters) -> { statements; }

它由三部分构成

  1. 参数列表
  2. 符号 ->
  3. 函数体 : 有多个语句,可以用{} 包括, 如果需要返回值且只有一个语句,可以省略 return

具体语法细节和Java的支持请参考:
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html#overview

来个例子对比下lambda表达式的神奇之处:
我们要对某次考试的成绩做统计,找出其中没有及格(分数小于60)的学生,并且按照分数从高到低排序。
定义一个类StudentScore,包含学生姓名和考试分数两个字段。

public class StudentScore {
    private String name;
    private Integer score;

    public StudentScore(){

    }

    public StudentScore(String name, Integer score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getScore() {
        return score;
    }

    public void setScore(Integer score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "StudentScore{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}

模拟一个测试的List

List<StudentScore> studentScoreList = Lists.newArrayList(new StudentScore("Tom", 80), new StudentScore
                ("Alice", 43), new StudentScore("Bob", 55), new StudentScore("Cassy", 51));

1. 传统java7的实现

        List<StudentScore> failedStudentScoreList = Lists.newArrayList();
        // filter
        for (StudentScore studentScore : studentScoreList) {
            if (studentScore.getScore().compareTo(60) < 0) {
                failedStudentScoreList.add(studentScore);
            }
        }
        // sort
        Collections.sort(failedStudentScoreList, new Comparator<StudentScore>() {
            @Override
            public int compare(StudentScore o1, StudentScore o2) {
                return o1.getScore().compareTo(o2.getScore());
            }
        });
        // transform
        List<String> failedNames = Lists.newArrayList();
        for(StudentScore studentScore : failedStudentScoreList){
            failedNames.add(studentScore.getName());
        }
        System.out.println(failedNames);

2. 使用guava简化代码

使用guava提供的filter,transform等集合工具可以一定程度上简化代码,避免了for循环等代码实现细节,但是需要注意lazy load问题,之前的博客专门分析过。

List<StudentScore> failedStudentList = Lists.newArrayList(Iterables.filter(studentScoreList, new
        Predicate<StudentScore>() {
            @Override
            public boolean apply(StudentScore input) {
                return input.getScore().compareTo(60) < 0;
            }
        }));
Collections.sort(failedStudentList, new Comparator<StudentScore>() {
    @Override
    public int compare(StudentScore o1, StudentScore o2) {
        return o1.getScore().compareTo(o2.getScore());
    }
});
List<String> failedNames = Lists.transform(failedStudentList, new Function<StudentScore, String>() {
    @Override
    public String apply(StudentScore input) {
        return input.getName();
    }
});
System.out.println(failedNames);

3. lambda表达式结合guava

使用lambda表达式,可以极大地简化代码,原有的函数式接口(只定义一个抽象方法的接口)可以完全用lambda表达式替换,省去了匿名接口的一系列模板代码。

List<StudentScore> failedStudentList = Lists.newArrayList(Iterables.filter(studentScoreList, studentScore -> studentScore.getScore() < 60));
Collections.sort(failedStudentList, Comparator.comparing(StudentScore::getScore));
List<String> failedNames = Lists.transform(failedStudentList, StudentScore::getName);
System.out.println(failedNames);

其实,Java8新增了Stream API对于处理这种集合操作更合适,不仅代码更加简洁(以上功能一行代码实现),逻辑更易读,还自带并行处理能力,下回再整理。

如果觉得我的文章对您有用,请在支付宝公益平台找个项目捐点钱。 @sxzhou Feb 11, 2018

奉献爱心