JavaLambda详解

博客 动态
0 212
优雅殿下
优雅殿下 2022-03-30 21:57:20
悬赏:0 积分 收藏

Java Lambda详解

Lambda表达式是JDK 8开始后的一种新语法形式。

作用:简化匿名内部类的代码写法

简化格式

(匿名内部类被重写方法的形参列表) -> {	重写方法}

Lambda表达式只能简化函数式接口的匿名内部类的写法形式

什么是函数式接口?

  • 首先必须是接口、其次接口中有且仅有一个抽象方法的形式
  • 通常会在接口上加上一个@FunctionalInterface注解,标记该接口必须是满足函数式接口

如何使用Lambda?

我们将根据下面三个问题来帮助大家理解和使用Lambda

背景:我们自定义了一个man的类,创建了一个man的List。

class man {    public int age;    public char sex;    public double socre;    public man(int age, char sex, double score) {        this.age = age;        this.sex = sex;        this.score = score;    }}

问题一

现需要对这个list根据人的年龄进行排序

要实现排序的功能,可以直接调用List对象自带的sort方法完成,但是需要man先实现Comparator的接口并重写compare方法,编译器才能比较两个不同man的大小。但是要更改原始类的代码,会比较麻烦,如果以后要对人的分数进行排序,那就又要更改的类的源码,这样操作很不方便。

sort(Comparator<? super E> c)方法可以直接传入一个Comparator对象,我们可以直接改写compare方法就可以实现比较。

第一种写法

public class lambdaTry {    public static void main(String[] args) {        List<man> humans = new ArrayList<>();        humans.add(new man(19, 'g', 98.0));        humans.add(new man(18, 'b', 95.0));        humans.add(new man(20, 'b', 96.0));        humans.add(new man(17, 'g', 97.0));        humans.sort(new Comparator<man>() {            @Override            public int compare(man o1, man o2) {                return o1.age - o2.age;            }        });    }}

第二种写法

Lambda

我们知道Lambda是用来简化函数式接口的匿名内部类,且Comparator满足函数式接口的两个条件:

  • 首先必须是接口、其次接口中有且仅有一个抽象方法的形式
  • @FunctionalInterface注解
@FunctionalInterfacepublic interface Comparator<T> {	int compare(T o1, T o2);    ...}

因此我们可以对上述的源码进行改写成Lambda格式

public class lambdaTry {    public static void main(String[] args) {        List<man> humans = new ArrayList<>();        humans.add(new man(19, 'g', 98.0));        humans.add(new man(18, 'b', 95.0));        humans.add(new man(20, 'b', 96.0));        humans.add(new man(17, 'g', 97.0));        humans.sort((man o1, man o2) -> {                return o1.age - o2.age;        });    }}

改写过后代码简洁了很多。但是还可以继续简写。

Lambda表达式的省略写法

  1. 参数类型可以不写
  2. 如果只有一个参数,参数类型可以省略,同时()也可以省略
  3. 如果Lambda表达式的方法块中代码只有一行,可以省略大括号,同时省略分号。
  4. 在条件三的基础上,如果这行代码是return语句,必须省略return。

第三种写法

Lambda简写

可以看到,此表达式满足省略写法的条件,可以继续简写成如下格式。只需要一行语句就能完成

public class lambdaTry {    public static void main(String[] args) {        List<man> humans = new ArrayList<>();        humans.add(new man(19, 'g', 98.0));        humans.add(new man(18, 'b', 95.0));        humans.add(new man(20, 'b', 96.0));        humans.add(new man(17, 'g', 97.0));        humans.sort((o1, o2) -> o1.age - o2.age);    }}

问题二

将List转换为数组

我们知道List接口有一个方法toArray方法可以实现将其转换为数组。

JDK11之后,提供了这样的一个方法,提供了一个函数式接口来让我们转换

default <T> T[] toArray(IntFunction<T[]> generator) {    return toArray(generator.apply(0));}

IntFunction函数式接口是从JDK8之后实现的,内部只有一个apply抽象方法,是一个标准的函数式接口

@FunctionalInterfacepublic interface IntFunction<R> {    R apply(int value);}

我们可以直接用lambda,完成数组的转换

public class lambdaTry {    public static void main(String[] args) {        List<man> humans = new ArrayList<>();        humans.add(new man(19, 'g', 98.0));        humans.add(new man(18, 'b', 95.0));        humans.add(new man(20, 'b', 96.0));        humans.add(new man(17, 'g', 97.0));		// 原本写法        // man[] mans = humans.toArray(new IntFunction<man[]>() {        //     @Override        //     public man[] apply(int value) {        //         return new man[value];        //     }        // });        // lambda写法        man[] mans = humans.toArray(value -> new man[value]);                // 实际上用不上这样的写法,只是为了举例说明        // man[] mans = humans.toArray(new man[0]);        // man[] mans = humans.toArray(man[]::new);        // 上面两种写法都可以,传值进去的size为0不影响实际的转换,具体可以看ArrayList的toArray重写方法            }}

问题三

输出年龄大于18的男同学的成绩

可以用forEach方法快捷实现,forEach方法来自于Iterable接口

default void forEach(Consumer<? super T> action) {    Objects.requireNonNull(action);    for (T t : this) {        action.accept(t);    }}

再看Consumer接口,也是一个函数式接口

@FunctionalInterfacepublic interface Consumer<T> {    void accept(T t);    ...}

具体实现

public class lambdaTry {    public static void main(String[] args) {        List<man> humans = new ArrayList<>();        humans.add(new man(19, 'g', 98.0));        humans.add(new man(18, 'b', 95.0));        humans.add(new man(20, 'b', 96.0));        humans.add(new man(17, 'g', 97.0));        // humans.forEach(new Consumer<>() {        //     @Override        //     public void accept(man man) {        //         if (man.age >= 18 && man.sex == 'g') {        //             System.out.println(man.score);        //         }        //     }        // });        humans.forEach(man -> {            if (man.age >= 18 && man.sex == 'g') {                System.out.println(man.score);            }        });    }}

有时Lambda还可以继续简写成方法引用(method reference)

方法引用

方法引用通过方法的名字来指向一个方法。

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用使用一对冒号 ::

主要分为四种:

  • 构造器引用 Class::new

    man[] mans = humans.toArray(man[]::new);
  • 静态方法引用 Class::static_method

    打印每个man(需要在man内重写toString)

    humans.forEach(System.out::println)
  • 特定类的任意对象的方法引用 Class::method

  • 特定对象的方法引用 instance::method

posted @ 2022-03-30 21:27 Xi-iX 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    优雅殿下

    优雅殿下 (王者 段位)

    2018 积分 (2)粉丝 (47)源码

    小小码农,大大世界

     

    温馨提示

    亦奇源码

    最新会员