Java多线程编程——Lambda表达式

Lambda表达式,又可称为闭包,是Java 8中的一项重要特性,本质上属于函数式编程的一种。

理解Lambda表达式的关键,是理解函数式接口(functional interface)的概念。所谓函数式接口,就是指该接口内只包含唯一一个抽象方法。对于函数式接口,我们可以通过Lambda表达式创建该接口的对象。

一、Lambda表达式的引出

1. 我们先看一下如何定义一个函数式接口,定义类以实现该接口,并创建类的对象以调用相关方法。

public class Main {
    public static void main(String[] args) {
        // 1.3 Create a object
        Animal animal = new Rabbit();
        // 1.4 Call the method
        animal.eat();
    }
}

// 1.1 Define a functional interface
interface Animal {
    void eat();
}

// 1.2 Define a class which implements the interface
class Rabbit implements Animal {
    @Override
    public void eat() {
        System.out.println("Grass");
    }
}

2. 可以看到,上面传统的定义方式十分繁琐。于是,我们可以采用静态内部类予以简化。

public class Main {
    // 2.2 Define a static class which implements the interface
    static class Rabbit implements Animal {
        @Override
        public void eat() {
            System.out.println("Grass");
        }
    }

    public static void main(String[] args) {
        // 2.3 Create a object
        Animal animal = new Rabbit();
        // 2.4 Call the method
        animal.eat();
    }
}

// 2.1 Define a functional interface
interface Animal {
    void eat();
}

这段程序与上面的不同之处在于类定义的位置不同了。现在,我们将类定义搬到了另一个类Main内,故称之为“内部类”,此外由在前面增加了一个修饰符static(即“静态”),这样Main类内的main方法才可以创建Rabbit对象。

3. 上述方法要在一个类里再创建一个类,我们还可以对其再进行修改。现在,我们使用局部内部类编写程序。

public class Main {
    public static void main(String[] args) {
        // 3.2 Define a local class which implements the interface
        class Rabbit implements Animal {
            @Override
            public void eat() {
                System.out.println("Grass");
            }
        }

        // 3.3 Create a object
        Animal animal = new Rabbit();
        // 3.4 Call the method
        animal.eat();
    }
}

// 3.1 Define a functional interface
interface Animal {
    void eat();
}

这段代码把Rabbit类的定义搬到了main方法内部,所以称为“局部内部类”。

4. 不论是静态内部类,还是成员内部类,写起来都还是太复杂。于是,我们还可以再做简化,利用匿名内部类实现。

public class Main {
    public static void main(String[] args) {
        // 4.2 Create a object which define an anonymous class
        Animal animal = new Animal() {
            @Override
            public void eat() {
                System.out.println("Grass");
            }
        };
        // 4.3 Call the method
        animal.eat();
    }
}

// 4.1 Define a functional interface
interface Animal {
    void eat();
}

这段代码利用内部类创建了一个没有名称类的对象(故称为“匿名”),并进一步完成了对类内方法的重写,从而实现了Animal接口。

5. 事实上,匿名内部类还是有些繁琐。从Java 8开始出现了一种新的特性——Lambda表达式,可以帮助我们进一步简化该步骤。

public class Main {
    public static void main(String[] args) {
        // 5.2 Create a object by lambda expression
        Animal animal = () -> {
            System.out.println("Grass");
        };
        // 5.3 Call the method
        animal.eat();
    }
}

// 5.1 Define a functional interface
interface Animal {
    void eat();
}

在这个Lambda表达式中,圆括号()对应前面Rabbit类中eat()方法的参数列表(当然这里是无参方法,所以就是空的),箭头后面的一对花括号对应eat()方法的方法体。

二、Lambda表达式的语法规则

Lambda表达式有两种形式:

  • Statement Lambda:

        ( parameters ) -> { statements; }

  • Expression Lambda:

        ( parameters ) -> expression

以下是几个例子:

1. 接收两个int型整数,并分别打印它们的和与差。

(int x, int y) -> {
    System.out.println(x + y);
    System.out.println(x - y);
}

当然,前件中的类型声明也可以都略去:

(x, y) -> {
    System.out.println(x + y);
    System.out.println(x - y);
}

注意:类型声明如要省略则所有变量都得省略,不能只省略其中一部分,例如下面的代码就是错误的。

(int x, y) -> {
    System.out.println(x + y);
    System.out.println(x - y);
}

此外,假如后件的语句块中只包含一条语句,则花括号可以省略。

(x, y) -> System.out.println(x + y)

2. 接收2个参数(数字),并返回它们的和。

(x, y) -> x + y

注意,若后件为一条表达式,则可以视作返回值,或者说是语句“return x + y”。

3. 接收1个参数(数字),并返回它的平方。

(x) -> x * x

当然,当参数仅有一条时,括号可以略去。

x -> x * x

下面总结一下:

  • Lambda表达式使用的前提是,接口为函数式接口,即其中只包含唯一一个抽象方法。
  • 参数的类型声明可以省略,但注意如要省略则所有参数都不应声明类型。
  • 若参数只有一个,则可以省略圆括号。
  • 若方法块内只有一条语句/仅为一条表达式,则可以省略花括号。

三、Lambda语句与线程创建

事实上,Java中的Runnable接口就是一个函数式接口,其中只包含一个抽象方法run()。显然,我们可以利用Lambda语句减少我们创建线程的工作量。

曾经,我们先定义一个类实现Runnable接口,然后在创建该类的对象,丢入Thread类创建线程对象,最后调用线程对象的start()方法。

public class Main {
    public static void main(String[] args) {
        new Thread(new Task()).start();
    }
}

class Task implements Runnable {
    @Override
    public void run() {
        System.out.println("I love Java.");
    }
}

现在,我们可以巧妙利用Lambda表达式特性,简化上述流程。

public class Main {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("I love Java.")).start();
    }
}

于是这样我们只需要一行即可!Thread类构造方法中的Lambda表达式中,前件圆括号对应上面Task类中run()方法的参数列表(当然这里为空),后件对应Task类中run()方法的方法体(因为只有一条语句,所以省略了花括号)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值