深度解析Lambda表达式

什么是@FunctionalInterface注解?

lambda表达式的使用和@FunctionalInterface注解关系密切,它用来修饰仅有一个抽象方法的接口,比如Runnable接口的源码就带有@FunctionalInterface注解 —— 它告诉编译器:“这个接口只能有一个抽象方法!”。所以,如果你在加了@FunctionalInterface注解的接口里,试图添加第二个抽象方法,编译器将提示报错!

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

怎么理解functional Interface?它直译成中文是“功能性接口”。什么是功能?功能就是一个动作的实现,比如打印的功能、结算的功能,我们都知道接口是功能的抽象,如果某个接口仅仅是有且仅有一种功能的抽象,那它就是一个functional Interface

如何理解lambda?

那么它和lambda表达式有什么关系?—— 用大白话来解释,lambda表达式用来描述功能性接口的某种实现,你可以理解它是一种具体动作、具体实现。比如我们有一个Printable接口:

@FunctionalInterface
public interface Printable {
    void print();
}

接口只是抽象,对不对?就好像打印这个功能,我们可以竖着打印、横着打印、打印成小册子,这些都是接口具体的实现——它们就可以用lambda进行描述

public class MyLambdaTest {
    public static void main(String[] args) {
        Printable myLambda1 = () -> { System.out.println("竖着打印!") };
        Printable myLambda2 = () -> { System.out.println("横着打印!") };
        Printable myLambda3 = () -> { System.out.println("斜着打印!") };
    }
}

如果你对这些表达式感到不能理解,可以试着这么想:“接口就是某个或某些动作的抽象,任何实现它的动作都可以被看成它本身”,就好像不管是横、竖着打印,都是打印一样,所以myLambda1-3的类型都可以为Printable,是不是没毛病?

当然,你在代码不会看到有人单纯地写一串lambda表达式(如上例),然后孤零零地放在那里。为什么描述一种实现?因为我们希望把动作本身当做参数传进某个方法里——也就是把lambda当作一个参数传到方法里。比如我们有两台打印机,它们都能打印,A可以横着打印,B可以竖着打印,用代码实现如下:

public class PrinterA implements Printable {
    public void print() {
        System.out.println("横着打印!");
    };
}
// -----------------
public class PrinterB implements Printable {
    public void print() {
        System.out.println("竖着打印!");
    };
}

我们在日常生活中拥有一台打印机目的是什么?为了打印(printSomething方法)。为了可以打印,我们会买(new)一个打印机帮我们打印,如果想横打印就new一个PrinterA,想竖着打印就new一个PrinterB:

public class MyLambdaTest {
    public static void main(String[] args) {
        Printable myPrinter = new PrinterA();
        printSomething(myPrinter);
    }
    public static void printSomething(Printable printer) {
        printer.print();
    }
}

当然,上文描述的是现实生活里的操作——要打印必须要买打印机。但在代码里,有必要这么复杂吗?我们的目的是为了完成打印的动作(执行printSomething方法),所以,只需要把如何打印直接作为参数传进去就可以了,不用非得new一个打印机。我们刚刚说了,lambda就是为了描述动作而存在的,所以printSomething的参数直接传入lambda即可!所以上面的代码就可以直接简化为:

public class MyLambdaTest {
    
    public static void main(String[] args) {
        printSomething(
        	() -> System.out.println("横着打印!"); // lambda在此
        );
    }
    
    public static void printSomething(Printable printer) {
        printer.print();
    }
    
}

为什么lambda可以如此简写?

为什么lambda写法可以如此简单?因为关于方法的实现规则,在功能性接口里已经写得明明白白。lambda只适用于functional interface,后者有且只有一个方法,当你使用lambda时,也只有可能指“那”一个方法,它的方法签名里(比如void print();)已经告诉了你它的方法名、参数信息、返回值类型,所以lambda的参数(参数类型都不用写!)和方法体之间只需要一个右箭头进行连接即可,当方法体里只有一行代码,方法体的花括号甚至可以省略。

案例1:

@FunctionalInterface
public interface Printable {
    void print(); // 无参、无返回值
}

// --------------
public class MyLambdaTest {
    public static void main(String[] args) {
        Printable myLambda1 = () -> { System.out.println("竖着打印!") };
        Printable myLambda2 = () -> System.out.println("竖着打印!");  // 省略方法体花括号
    }
}

案例2:

@FunctionalInterface
public interface Printable {
    String print(); // 无参、返回值类型为String
}

// --------------
public class MyLambdaTest {
    public static void main(String[] args) {
        Printable myLambda1 = () -> { return "竖着打印!" };
        Printable myLambda2 = () -> "竖着打印!";  // 只有一行代码,省略方法体花括号甚至省略return关键字
    }
}

案例3:

@FunctionalInterface
public interface Printable {
    int print(String prefix, int num); // 有参、返回值类型为int
}

// --------------
public class MyLambdaTest {
    public static void main(String[] args) {
        String p = "打印机A";
        int n = 5;
        Printable myLambda1 = (p, n) -> { // 参数类型都不用写
            System.out.println(p + "竖着打印!") ;
            return n;
        };
    }
}

所以,一个复杂的lambda表达式应用,可能是如下这样的:1.它是某一个方法的参数,比如printSomething需要传入一个动作作为参数,比如new一个线程需要传入一个Runnable动作作为参数;2.它的书写非常简单,因为接口已经把它的相关信息定义得明明白白,不用废话太多,编译器compiler知道你在说什么!

public class MyLambdaTest {
    
    public static void main(String[] args) {
        printSomething(
        	(s, n) ->  {
        		System.out.println(prefix + "竖着打印!") ;
        		return n;
        	}
        );
    }
 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值