引入 Lambda 表达式
创建一个线程实现类。
/**
 * @author BNTang
 */
public class MyRunnable implements Runnable {
    
    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() {
            
            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 {
    
    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() {
            
            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() {
            
            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 表达式的省略模式
参数的类型可以省略

有多个参数的情况下,不能只省略一个,要么就全部省略不要一个省略一个不省略。
如果参数有且仅有一个,那么小括号可以省略,如下。

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

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

Lambda 表达式的注意事项
使用 Lambda 必须要有接口,并且要求接口中 有且仅有 一个抽象方法。
必须要有上下文环境,才能推导出 Lambda 对应的接口。
/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            
            public void run() {
                System.out.println("匿名内部类");
            }
        }).start();
    }
}可以直接写,因为知道对应的接口是 Runnable。
/**
 * @author BNTang
 */
public class TestMain {
    public static void main(String[] args) {
        new Runnable() {
            
            public void run() {
                System.out.println("匿名内部类");
            }
        }.run();
    }
}直接这样写会报错,因为没有办法推导出对应的接口。

Lambda 表达式与匿名内部类的区别
所需的类型不同
匿名内部类:可以是接口,也可以是抽象类,还可以是具体类。
Lambda 表达式:只能是接口。
使用的限制不同
如果接口中 有且仅有 一个抽象方法,可以使用 Lambda 表达式,也可以使用匿名内部类。
如果接口中有多于的一个抽象方法,只能使用匿名内部类,而不能使用 Lambda 表达式。
实现的原理不同
匿名内部类:编译之后,会产生一个单独的 .class 字节码文件。
Lambda 表达式:编译之后,没有一个单独的 .class 字节码文件。对应的字节码会在运行的时候动态生成。










