入门lambda表达式(一)

引文

  在这篇文章中,我想介绍一下Java 8最吸引人的新特性——lambda表达式。
  先贴上lambda表达式的基本语法,有两种形式:java

  • (parameters) -> expression
  • (parameters) -> {expressions}

  lambda容许把函数做为一个方法的参数传递进方法中,体现了函数式编程思想。使用lambda表达式可使代码变得更加简洁紧凑。lambda表达式的本质只是一个所谓的“语法糖”,并无为Java语言添加新的功能,而是对已有功能进行了封装,由编译器推断并转换为常规的代码,所以能够用更少的代码来实现一样的功能。我我的以为,lambda表达式虽好,但不要乱用,用在合适的地方,能够有效减小代码量,使代码更加简洁,而滥用只会下降代码的可读性,使程序难以调试和维护。那么lambda表达式的应用场景是什么呢?
  网上有不少lambda表达式的例子,我看了半天,以为无外乎就两个场景(我的浅显观点......):
  一是代替函数式接口。函数式接口简单来讲就是只包含一个抽象方法的接口,好比Java标准库中的java.lang.Runnable和java.util.Comparator都是典型的函数式接口。对于函数式接口,除了可使用Java中标准的方法来建立实现对象以外,还可使用lambda表达式来建立实现对象,这能够在很大程度上简化代码的实现。在使用lambda表达式时,只须要提供形式参数和方法体。因为函数式接口只有一个抽象方法,因此经过lambda表达式声明的方法体确定是这个惟一的抽象方法的实现,并且形式参数的类型能够根据方法的类型声明进行自动推断(即形式参数能够省略类型)。
  第二个场景,就是和集合配合使用。Java 8新增了两个对集合数据进行批量操做的包:java.util.function和java.util.stream。能够说,lambda表达式和stream是自Java语言添加泛型和注解以来最大的变化,lambda表达式很大程度上影响了咱们在处理集合时的编码方式。express

Lambda表达式基本用法

  下面,我经过几个典型的例子带你们领略lambda表达式的强悍:编程

使用lambda表达式实现Runnable接口

传统方式ide

public class runnableTest {

    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
                System.out.println("I am Hawk.");
            }
        }).start();
    }
}
复制代码

使用lambda表达式函数式编程

public class runnableTest {

    public static void main(String[] args) {
        new Thread(() ->
            System.out.println("I am Hawk.")
        ).start();
    }
}
复制代码

  经过这个例子,咱们也能够进一步熟悉lambda表达式的声明方式:由形式参数和方法体两部分组成,中间经过“->”分隔。形式参数一般状况下不须要包含类型声明,能够进行自动推断。由于 System.out.println("I am Hawk.") 是单行语句,能够不用花括号“{}”括起来,若是方法体包含多行语句,则须要用“{}”括起来。函数

使用lambda表达式实现Comparator接口

  关于Comparator的机制,不在咱们此次的讨论范围内,我有时间...额...大概会写。总之,当咱们相比较的对象没有实现Comparable接口时,可使用Comparator接口并实现其中的compare方法进行比较。好比说,有这样一个Penple类:编码

// 使用lombok注解自动生成构造器与get、set方法等
@Data
@NoArgsConstructor
@AllArgsConstructor
public class People {
    
    private String name;
    
    private Integer age;
}
复制代码

  如今我想按照年龄对People对象进行排序:
传统方式spa

public class ComparatorTest {

    public static void main(String[] args) {
        List<People> peopleList = new ArrayList<>();
        peopleList.addAll(Arrays.asList(new People("a", 20), new People("b", 21), new People("c", 22)));
        Collections.sort(peopleList, new Comparator<People>() {
            @Override
            public int compare(People p1, People p2) {
                return p1.getAge().compareTo(p2.getAge());
            }
        });
    }
}
复制代码

使用lambda表达式调试

// 方法一
public class ComparatorTest {

    public static void main(String[] args) {
        List<People> peopleList = new ArrayList<>();
        peopleList.addAll(Arrays.asList(new People("a", 20), new People("b", 21), new People("c", 22)));
        Collections.sort(peopleList, (p1, p2) ->
            p1.getAge().compareTo(p2.getAge()));
    }
}

// 方法二
public class ComparatorTest {

    public static void main(String[] args) {
        List<People> peopleList = new ArrayList<>();
        peopleList.addAll(Arrays.asList(new People("a", 20), new People("b", 21), new People("c", 22)));
        peopleList.sort(Comparator.comparing(People::getAge));
    }
}
复制代码

  不知道你们咋想的,反正我当时知道还有方法二这种写法时是真的惊了。感受Java 8中的集合类型在增长了lambda表达式的支持以后变得......emmm高深莫测。须要注意一点,在方法二中,还使用了Java 8的另外一个新特性——方法引用,就是那两个冒号“::”(有点C++的赶脚)。方法引用能够在不调用某个方法的状况下引用一个方法,是另外一种实现函数式接口的方法,能够进一步简化代码。code

使用lambda表达式对列表进行迭代

传统方法

public class foreachTest {

    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        stringList.addAll(Arrays.asList("a", "b", "c"));
        for (String str : stringList) {
            System.out.println(str);
        }
    }
}
复制代码

使用lambda表达式

public class foreachTest {

    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        stringList.addAll(Arrays.asList("a", "b", "c"));
        stringList.forEach(System.out::println);
    }
}
复制代码

  额......先写到这里吧,由于stream部份内容较多,过几天再补充完。此次主要介绍了使用lambda表达式的第一个场景——代替函数式接口。这是一个趋势,但愿你们在从此的编码中,能逐渐抛弃匿名内部类,改用lambda这种更为简洁的写法。下次我将重点介绍lambda在集合中的使用以及如何与stream进行配合。

相关文章
相关标签/搜索