Java基础 第四节 第七课

举报
我是小白呀iamarookie 发表于 2021/09/09 23:27:34 2021/09/09
【摘要】 Lambda 练习 练习: 使用 Lambda 标准格式 (无参无返回)题目解答 Lambda 的参数和返回值传统写法代码分析Lambda 写法 练习: 使用 Lambda 标准格式 (有...

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

题目

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

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

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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

解答

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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Lambda 的参数和返回值

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

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

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

  
 
  • 1

当需要对一个对象数组进行排序时, 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 +
                '}';
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

传统写法

如果使用传统的代码对 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}]

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

这种做法在面向对象的思想中, 似乎也是 “理所当然” 的. 其中 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}]

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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

题目

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

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

  
 
  • 1
  • 2
  • 3

在下面的代码中, 请使用 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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

注: 小括号代表 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);
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

省略规则

在 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();
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

解答

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

输出结果:
吃饭了!

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Lambda 的使用前提

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

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

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

文章来源: iamarookie.blog.csdn.net,作者:我是小白呀,版权归原作者所有,如需转载,请联系作者。

原文链接:iamarookie.blog.csdn.net/article/details/111550051

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。