- 1. 为什么使用 Lambda 表达式
- 2. Lambda 表达式的本质与函数式接口
- 3. Lambda 表达式的使用
- (1) 无参,且无返回值
- (2) 一个参数,无返回值
- (3) 形参的数据类型可以省略,编译器可以由编译类型推断得出
- (4) 形参若只需要一个参数时,参数的小括号可以省略
- (5) 两个或两个以上参数,多条执行语句,并且可以有返回值
- (6) 当 Lambda体 只有一条语句时,关键字return 和 方法体的大括号都可以省略
- 小结:Lambda 表达式使用的总结
- 4. 函数式接口与Lambda表达式结合的示例
- 4.1 消费型接口的使用
- 4.2 断定型接口的使用
Lambda 表达式是一个 匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样可以传递)。使用它可以写出更简洁、灵活的代码。
2. Lambda 表达式的本质与函数式接口Lambda 表达式在 Java 中本质还是一个对象,它针对的是函数式接口,它可以产生函数式接口的一个匿名实现类的实例。
所以,以前我们用匿名实现类实现的代码,都可以通过Lambda 表达式来更简单的书写。
能够用Lambda 表达式实现的接口有一定的要求,就是接口中只能有唯一的一个抽象方法。正因为只有唯一的一个抽象方法需要去实现,所以Lambda 表达式不需要我们去指明到底是哪一个方法需要去实现。
而一个接口中,如果只声明了一个抽象方法,则此接口就称为函数式接口。
我们举两个例子来展示函数式接口长什么样:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
@FunctionalInterface public interface Comparator{ int compare(T o1, T o2); }
我们也可以自己定义一个函数式接口玩一玩:
// @FunctionalInterface 这个注解加不加都不影响MyInterface是一个函数接口的事实 // 不加一样也可以使用我们后面即将讲到的Lambda 表达式 // 此注解 仅仅起到检验的作用 @FunctionalInterface public interface MyInterface{ public abstract void method(T o); }
我们可以在一个函数式接口上使用 @ F u n c t i o n a l I n t e r f a c e @FunctionalInterface @FunctionalInterface 注解,这样做可以检验它是否是一个函数式接口。同时,javadoc也会包含一条声明,说明该接口是一个函数式接口。
在 java.util.function 包下,定义了丰富的函数式接口,注意下图中'函数型接口' 和我们之前一直提到的'函数式接口' 的差异。
- 举例: (o1, o2) -> Integer.compare(o1, o2);
- 格式:
->:Lambda操作符 或 箭头操作符
->左侧 :Lambda形参列表 (其实就是接口中抽象方法的形参列表)
->右侧 :Lambda体 (其实就是重写的抽象方法的方法体)
// 匿名内部类写法
Runnable r1 = new Runnable() { // 父类引用指向子类对象
@Override
public void run() {
while (true) {
System.out.println("线程正在执行中~~~");
}
}
};
// 等价于
Runnable r2 = () -> { // lambda 方法体
while (true) {
System.out.println("线程正在执行中~~~");
}
};
(2) 一个参数,无返回值
// 消费型接口:只接收参数,但是无返回值 Consumer(3) 形参的数据类型可以省略,编译器可以由编译类型推断得出consumer = new Consumer () { // 父类引用指向子类对象 @Override public void accept(String s) { System.out.println(s); } }; // 等价于 Consumer consumer = (String s) -> { System.out.println(s); };
// 类型推断,可以省略参数 Consumer(4) 形参若只需要一个参数时,参数的小括号可以省略consumer = (String s) -> { System.out.println(s); }; // 等价于 Consumer consumer = (s) -> { System.out.println(s); }; // 类型推断不仅Lambda表达式中有,讲集合的时候也用到过 ArrayList list = new ArrayList (); // 可以直接写为 ArrayList list = new ArrayList<>();
// 参数唯一时,可以省略小括号 Consumer(5) 两个或两个以上参数,多条执行语句,并且可以有返回值consumer = (s) -> { System.out.println(s); }; // 等价于 Consumer consumer = s -> { System.out.println(s); };
Comparator(6) 当 Lambda体 只有一条语句时,关键字return 和 方法体的大括号都可以省略comparator = new Comparator () { @Override public int compare(Integer o1, Integer o2) { System.out.println(o1); System.out.println(o2); // 模拟通用情况,有多条语句 return o1.compareTo(o2); } }; // 等价于 Comparator comparator = (o1, o2) -> { System.out.println(o1); System.out.println(o2); // 模拟通用情况,有多条语句 return o1.compareTo(o2); };
// 例子1: Comparatorcomparator = (o1, o2) -> { return o1.compareTo(o2); }; // 等价于(return和{}要么同时不写,要么同时写) Comparator comparator = (o1, o2) -> o1.compareTo(o2);
// 例子2: Consumer小结:Lambda 表达式使用的总结consumer = s -> { System.out.println(s); }; // 等价于 Consumer consumer = s -> System.out.println(s);
-> 左侧:Lambda形参列表的参数类型可以省略(编译类型自动推断);如果Lambda形参列表只有一个参数,其()可以省略;
-> 右侧:Lambda体应该使用一对{}进行包裹;如果Lambda体只有一条执行语句(可能是return语句),可以省略{}和return关键字。
public class Main {
@Test
public void testOldWay() { // 匿名实现类的方式
spendMoney(500, new Consumer() {
@Override
public void accept(Double money) {
System.out.println("消费了 " + money + " 元。");
}
});
}
@Test
public void testNewWay() { // 使用Lambda 表达式的方式
spendMoney(500, money -> System.out.println("消费了 " + money + " 元。"));
}
public void spendMoney(double money, Consumer consumer) {
consumer.accept(money);
}
}
4.2 断定型接口的使用
public class Main {
private List list = Arrays.asList("北京", "南京", "天津", "吴京", "普京");
@Test
public void testOldWay() { // 传统匿名实现类的方式,筛选含"京"的字符串
List newStrs = filterString(list, new Predicate() {
@Override
public boolean test(String s) {
return s.contains("京");
}
});
}
@Test
public void testNewWay() { // 使用Lambda 表达式的方式,筛选含"京"的字符串
List newStrs = filterString(list, s -> s.contains("京"));
}
// 根据传入的规则,过滤集合中的字符串。此规则由Predicate接口的实现类决定
public List filterString(List list, Predicate predicate) {
ArrayList newList = new ArrayList<>();
for (String s : list) {
if (predicate.test(s)) {
newList.add(s);
}
}
return newList;
}
}



