Java新特性-Lambda表达式

引入 Lambda 表达式

创建一个线程实现类。

/**
 * @author BNTang
 */
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("thread -> " + Thread.currentThread().getName() + "启动了");
    }
}

实现方法有 3 种如下。

方式 1

通过编写实现类的方式来实现需求,如下。

/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();

        new Thread(myRunnable).start();
    }
}

方式 2

通过匿名内部类的方式来实现,如下。

/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread -> " + Thread.currentThread().getName() + "启动了");
            }
        }).start();
    }
}

方式 3

通过 Lambda 的方式来实现,如下。

/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println("thread -> " + Thread.currentThread().getName() + "启动了");
        }).start();
    }
}

Lambda 编写格式

(形式参数) -> {代码块}

  • 形式参数:如果有多个参数,参数之间用 逗号 隔开;如果没有参数,留空即可。
  • ->:由英文中画线和大于符号组成,固定写法。代表指向动作。
  • 代码块:是我们具体要做的事情,也就是以前我们写的方法体中的内容。

组成 Lambda 表达式的三要素与使用要求,如下:

  • 形式参数
  • 箭头
  • 代码块

使用要求,如下:

使用 Lambda 表达式必须要有接口,并且要求接口中 有且仅有 一个抽象方法。

下面我将给出一个示例来看看吧,如下:

接口

/**
 * @author BNTang
 */
public interface USB {
    void work();
}

实现类

/**
 * @author BNTang
 */
public class KeyBoardImpl implements USB {
    @Override
    public void work() {
        System.out.println("键盘工作");
    }
}

应用

/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        USB keyBoard = new KeyBoardImpl();

        mainBoard(keyBoard);
    }

    private static void mainBoard(USB usb) {
        usb.work();
    }
}

如上代码的含义很简单,就是普通的多态的写法,传入一个 USB 的实现类调用 work 方法进行处理。先来看看通过匿名内部类的方式怎么玩吧,如下:

/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        mainBoard(new USB() {
            @Override
            public void work() {
                System.out.println("鼠标");
            }
        });
    }

    private static void mainBoard(USB usb) {
        usb.work();
    }
}

在来看看通过 Lambda 表达式的方式来怎么玩吧,如下:

/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        mainBoard(() -> {
            System.out.println("打印机");
        });
    }

    private static void mainBoard(USB usb) {
        usb.work();
    }
}

带参数形式的 Lambda 表达式。

一个参数

/**
 * @author BNTang
 */
public interface TestTable {
    void fly(String s);
}

匿名内部类的方式如下:

/**
 * @author BNTang
 */
public class FlyableDemo {

    public static void main(String[] args) {
        useTestTable(new TestTable() {
            @Override
            public void fly(String s) {
                System.out.println(s);
            }
        });
    }
    
    private static void useTestTable(TestTable testTable){
        testTable.fly("一个参数");
    }
}

Lambda 表达式的方式如下:

/**
 * @author BNTang
 */
public class FlyableDemo {

    public static void main(String[] args) {
        useTestTable((String s) -> {
            System.out.println(s);
        });
    }

    private static void useTestTable(TestTable testTable) {
        testTable.fly("一个参数");
    }

}

多个参数

/**
 * @author BNTang
 */
public interface Addable {
    int add(int x, int y);
}
/**
 * @author BNTang
 */
public class AddableMain {
    public static void main(String[] args) {
        useAddable((int x, int y) -> {
            return x + y;
        });
    }

    private static void useAddable(Addable addable) {
        int sum = addable.add(10, 20);
        System.out.println(sum);
    }
}

Lambda 表达式的省略模式

参数的类型可以省略

有多个参数的情况下,不能只省略一个,要么就全部省略不要一个省略一个不省略。

如果参数有且仅有一个,那么小括号可以省略,如下。

如果代码块的语句只有一条,可以省略大括号和分号,如下。

如果代码块的语句只有一条,可以省略大括号和分号,如果有 returnreturn 也可以省略掉。

Lambda 表达式的注意事项

使用 Lambda 必须要有接口,并且要求接口中 有且仅有 一个抽象方法。

必须要有上下文环境,才能推导出 Lambda 对应的接口。

/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类");
            }
        }).start();
    }
}

可以直接写,因为知道对应的接口是 Runnable

/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类");
            }
        }.run();
    }
}

直接这样写会报错,因为没有办法推导出对应的接口。

Lambda 表达式与匿名内部类的区别

所需的类型不同

匿名内部类:可以是接口,也可以是抽象类,还可以是具体类。

Lambda 表达式:只能是接口。

使用的限制不同

如果接口中 有且仅有 一个抽象方法,可以使用 Lambda 表达式,也可以使用匿名内部类。

如果接口中有多于的一个抽象方法,只能使用匿名内部类,而不能使用 Lambda 表达式。

实现的原理不同

匿名内部类:编译之后,会产生一个单独的 .class 字节码文件。

Lambda 表达式:编译之后,没有一个单独的 .class 字节码文件。对应的字节码会在运行的时候动态生成。

posted @ 2021-01-13 20:26  BNTang  阅读(131)  评论(0编辑  收藏  举报