(二) Java函数式编程:Lambda表达式

Lambda表达式简介

Java 8的最大变化是引入了Lambda表达式(Lambda 是希腊字母 λ 的英文名称)——一种紧凑的、传递行为的方式。编写Lambda表达式时,也会随之被编译成一个函数式接口。

Lambda 表达式

Lambda表达式的语法:

(argument-list) -> {body}  

(参数列表) -> {若干语句;}

1) 参数列表: 可以为空,也可以非空.

2) 箭头: 它用来连接参数列表和方法体.

3) 方法体: 包含若干的表达式和语句.

几个示例:

// 1. 不需要参数,返回值为 21  
() -> 21

// 2. 接收一个参数(数字类型),返回其5倍的值  
x -> 5 * x  

// 3. 接受2个参数(数字),并返回他们的和  
(x, y) -> x + y  

// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y  

// 5. 接受一个Long对象,并在控制台打印,不返回任何值  
(Long number) -> System.out.println(number)

// 6. 接受两个参数
(String aText,String bText) -> {
    // some code here
    return aText + bText;
}

函数式接口

在 Java 中,Marker(标记)类型的接口是一种没有方法或属性声明的接口,简单地说,marker 接口是空接口。相似地,函数式接口是只包含一个抽象方法声明的接口。

java.lang.Runnable 就是一种函数式接口,在 Runnable 接口中只声明了一个方法 void run(),相似地,ActionListener 接口也是一种函数式接口,我们使用匿名内部类来实例化函数式接口的对象,有了 Lambda 表达式,这一方式可以得到简化。

每个 Lambda 表达式都能隐式地赋值给函数式接口,例如,我们可以通过 Lambda 表达式创建 Runnable 接口的引用。

Runnable runnable = () -> System.out.println("hey,siri!");

当不指明函数式接口时,编译器会自动解释这种转化:

new Thread(
   () -> System.out.println("hey,siri!")
).start();

因此,在上面的代码中,编译器会自动推断:根据线程类的构造函数签名 public Thread(Runnable r) { },将该 Lambda 表达式赋给 Runnable 接口。

一些常见的Lambda 表达式及其函数式接口:

Consumer<Long>  c = (long x) -> { System.out.println(x) };

BiConsumer<Long, String> b = (Long x, String y) -> System.out.println(x + " : " + y);

Predicate<String> p = (String s) -> { s == null };

@FunctionalInterface 声明函数式接口

@FunctionalInterface 是 Java 8 新加入的一种接口,用于指明该接口类型声明是根据 Java 语言规范定义的函数式接口。Java 8 还声明了一些 Lambda 表达式可以使用的函数式接口,当你注释的接口不是有效的函数式接口时,可以使用 @FunctionalInterface 解决编译层面的错误。

定义:

@FunctionalInterface
public interface Pluggable {
    void plug();
}

根据定义,函数式接口只能有一个抽象方法,如果你尝试添加第二个抽象方法,将抛出编译时错误。例如:

@FunctionalInterface
public interface Pluggable {
    void plug();
    void recharge();
}

使用例子:

@FunctionalInterface
public interface Pluggable {
    void plug();
}

class PluggableTest {
    public static void main(String[] args) {
        PluggableTest.execute(() -> {
            System.out.println("It is pluggable with lambda expression!");
        });

        PluggableTest.execute(new Pluggable() {
            @Override
            public void plug() {
                System.out.println("It is pluggable with anonymous class!");
            }
        });

    }

    public static void execute(Pluggable pluggable) {
        pluggable.plug();
    }
}

Lambda 表达式与匿名类的区别

使用匿名类与 Lambda 表达式的一大区别在于关键词的使用。对于匿名类,关键词 this 解读为匿名类,而对于 Lambda 表达式,关键词 this 解读为写就 Lambda 的外部类。

Lambda 表达式与匿名类的另一不同在于两者的编译方法。Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有函数,它使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法。

(完)

发表评论

邮箱地址不会被公开。 必填项已用*标注