Java基础 第四节 第七课

练习: 使用 Lambda 标准格式 (无参无返回)

题目

给定一个厨子 Cook 接口, 内含唯一的抽象方法 makeFood, 且无参数, 无返回值. 如下:

public class Test {
    public static void main(String[] args) {
        // TODO 请在此使用Lambda [标准格式] 调用invokeCook方法

    }
    private static void invokeCook(Cook cook) {
        cook.makeFood();
    }
}

解答

public static void main(String[] args) {
    // TODO 请在此使用Lambda[标准格式]调用invokeCook方法
    invokeCook(() ->{
        System.out.println("吃饭了!");
    });
}
注: 小括号代表 Cook 接口 makeFood 抽象方法的参数为空, 大括号代表 makeFood 的方法体.

Lambda 的参数和返回值

需求: 使用数组存储多个 Person 对象, 对数组中的 Person 对象使用 Arrays 的 sort 方法通过年龄进行升序排序.

下面举例演示java.util.Comparator<T>接口的使用场景代码, 其中的抽象方法定义为:

public abstract int compare(T o1, T o2);

当需要对一个对象数组进行排序时, Array.sort 方法需要一个 Comparator 接口实例来指定排序的规则. 假设有一个 Person 类, 含有 String name 和 int age 两个变量.

public class Person {
    private String name;
    private int age;

    // 构造
    Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

传统写法

如果使用传统的代码对 Person[] 数组进行排序, 写法如下:

import java.util.Arrays;
import java.util.Comparator;

public class Test57 {
    public static void main(String[] args) {
        // 本来年龄乱序的对象数组
        Person[] array = {
                new Person("大白", 19),
                new Person("小小白", 17),
                new Person("小白", 18)
        };

        // 匿名内部类
        Comparator<Person> comp = new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        };
        Arrays.sort(array,comp);  // 第二个参数为排序规则, 即Comparator接口实例

        System.out.println(Arrays.toString(array));
    }
}

输出结果:
[Person{name='小小白', age=17}, Person{name='小白', age=18}, Person{name='大白', age=19}]

这种做法在面向对象的思想中, 似乎也是 “理所当然” 的. 其中 Comparator 接口的实例 (使用了匿名内部类) 代表了 “按照年龄从小到大” 的排序规则.

代码分析

下面我们来搞清楚上述代码真正要做什么事情.

  • 为了排序, Arrays.sort 方法需要排序规则. 即 Comparator 接口的实例, 抽象方法 compare 是关键
  • 为了指定 compare 的方法体, 不得不需要 Comparator 接口的实现类
  • 为了省去定义一个 ComparatorImpl 实现类的麻烦, 不得不使用匿名内部类
  • 必须覆盖重写抽象 compare 方法, 所以方法名称, 方法参数, 方法返回值不得不再写一遍, 其不能写错
  • 实际上, 只有参数和方法体才是关键

Lambda 写法

import java.util.Arrays;

public class Test58 {
    public static void main(String[] args) {
        // 本来年龄乱序的对象数组
        Person[] array = {
                new Person("大白", 19),
                new Person("小小白", 17),
                new Person("小白", 18)
        };
        Arrays.sort(array,(Person o1, Person o2)-> {
            return o1.getAge() - o2.getAge();
        });
        System.out.println(Arrays.toString(array));
    }
}

输出结果:
[Person{name='小小白', age=17}, Person{name='小白', age=18}, Person{name='大白', age=19}]

练习: 使用 Lambda 标准格式 (有参有返回)

题目

给一个计算器 Calculator 接口, 内含抽象方法 calc 可以将两个 int 数字相加得到和值:

public interface Calculator {
    int calc(int a, int b);
}

在下面的代码中, 请使用 Lambda 的标准格式调用 invokeCalc 方法, 完成 120 和 130 相加计算.

public class Test {
    public static void main(String[] args) {
        // TODO 请在此使用 Lambda [标准格式] 调用 invokeCalc 方法来计算120+130的相加计算
        invokeCalc(120,130,(int a, int b)->{
            return a + b;
        });
    }
    private static void invokeCalc(int a, int b, Calculator calculator) {
        int result = calculator.calc(a, b);
        System.out.println("结果是:" + result);
    }
}

输出结果:
结果是:250

注: 小括号代表 Calculator 接口 calc 抽象方法的参数, 大括号代表 clac 的方法体.

Lambda 省略格式

可推导可省略

Lambda 强调的是 “做什么” 而不是 “怎么做”. 所以凡是可以根据上下文推导得知的信息, 都可以省略. 例如上例还可以使用 Lambda 的省略写法:

public class Test {
    public static void main(String[] args) {
        invokeCalc(120,130,(a,b) -> a + b);
    }
    private static void invokeCalc(int a, int b, Calculator calculator) {
        int result = calculator.calc(a, b);
        System.out.println("结果是:" + result);
    }
}

省略规则

在 Lambda 标准格式的基础上, 使用省略写法的规则为:

  1. 小括号内参数的类型可以省略
  2. 如果小括号内有且仅有一个参数, 则小括号可以省略
  3. 如果大括号内有且仅有一个语句, 则无论是否有返回值, 都可以省略大括号, return 等关键字及语句分号

注: 掌握这些省略规则后请对应地回顾本章开头的多线程案例.

练习: 使用 Lambda 省略格式

题目

仍然使用前文含唯一 makeFood 抽象方法的厨子 Cook 接口, 在下面的代码中, 请使用 Lambda 的省略格式调用 invokeCook 方法, 打印输出 “吃饭了啦!” 字样.

public class Test {
    public static void main(String[] args) {
        // TODO 请在此使用Lambda [标准格式] 调用invokeCook方法

    }
    private static void invokeCook(Cook cook) {
        cook.makeFood();
    }
}

解答

public class Test61 {
    public static void main(String[] args) {
        // TODO 请在此使用Lambda [标准格式] 调用invokeCook方法
        invokeCook(() -> System.out.println("吃饭了!"));
    }
    private static void invokeCook(Cook cook) {
        cook.makeFood();
    }
}

输出结果:
吃饭了!

Lambda 的使用前提

Lambda 的语法非常简洁, 完全没有面向对象复杂的束缚. 但是使用时有几个问题需要特别注意:

  1. 使用 Lambda 必须有接口, 且要求接口中有且仅有一个抽象方法. 无论是 JDK 内置的 Runnable, Comparator 接口还是自定义的接口, 只有当接口中的抽象方法存在且唯一时, 才可以使用 Lambda
  2. 使用 Lambda 必须具有上下文推断. 也就是方法的采纳数或局部变量类型必须为符合 Lambda 要求的接口类型, 才能使用 Lambda 作为该接口的实例

注: 有且仅有一个抽象方法的接口, 称为 “函数接口”.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值