• 死磕Lambda表达式(二):Lambda的使用


    城市就是森林,每一个男人都是猎手,每一个女人都是陷阱。——《三体》

    在哪使用Lambda表达式?

    在上一篇文章(传送门)中介绍了Lambda表达式的基本语法,其中的举了一个Lambda表达式的例子,就是按照品牌给口罩列表进行排序:

    maskList.sort((Mask o1, Mask o2) -> o1.getBrand().compareTo(o2.getBrand()));
    

    这里使用的sort方法的参数类型是Comparator<T>,我们就是把Lambda表达式作为Comparator<T>传入sort方法中的。Comparator<T>就是一个函数式接口,那么什么是函数式接口?

    欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

    函数式接口

    函数式接口就是有且仅有一个抽象方法的接口。上面提到的Comparator<T>接口,虽然有很多默认方法,但有且仅有一个抽象方法compare,所以它仍然是一个函数式接口。再举个例子:

    package java.util.concurrent;
    
    @FunctionalInterface
    public interface Callable<V> {
        V call() throws Exception;
    }
    

    Callable接口只有一个call抽象方法,所以它也是函数式接口。

    你可以已经发现了,Callable接口上有一个注解@FunctionalInterface,该注解用于标志该接口是一个函数式接口。如果你编写了一个不是函数式接口的接口,并且加了@FunctionalInterface注解,编译就会报错,需要注意一下。

    看了以上的例子,是不是撸胳膊挽袖子准备大干一场?别急,检验出真知,我们先简单测试一下。以下三个接口,哪些是函数式接口,哪些不是函数式接口?

    1. Runnable
    package java.lang;
    
    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }
    
    1. Task
    package com.sun.jmx.snmp.tasks;
    
    public interface Task extends Runnable {
        public void cancel();
    }
    
    1. Serializable
    package java.io;
    
    public interface Serializable {
    }
    

    请思考片刻…
    .
    .
    .

    .
    .
    .
    宣布答案

    1. Runnable只有一个抽象方法run,所以是函数式接口
    2. Task有两个抽象方法,分别是自己的cancel方法和从Runnable继承而来的run方法,所以不是函数式接口。
    3. Serializable没有任何一个方法,所以不是函数式接口。

    怎么样?都答对了嘛?

    欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

    实现函数式接口

    了解了什么是函数式接口以后,我们就可以直接使用Lambda表达式为函数式接口提供实现了,并且还可以把整个Lambda表达式作为函数式接口的实例。比如上面提到的Runnable接口,我们就是这样直接赋值:

    Runnable runnable = () -> {
        System.out.println("万猫学社");
    };
    

    到目前为止,我们已经知道在哪使用Lambda表达式,那么该如何正确的使用Lambda表达式呢?

    欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

    怎么使用Lambda表达式?

    从上面Runnable接口实例的例子中,可以看出:Runnable接口的run方法没有入参没有返回,该方法的签名是() -> void;Lambda表达式同样的也没有入参没有返回,该表达式的签名是() -> void

    也就是说:函数式接口的抽象方法的签名和Lambda表达式的签名必须一致。

    再比如,按照品牌给口罩列表进行排序的例子,Comparator<T>接口的compare方法的签名是(T ,T) -> int,Lambda表达式的签名同样也是(T ,T) -> int

    为了加深理解,我们再来做个小测试,看看哪些代码正确使用了Lambda表达式?

    1. Callable
    Callable<String> callable = () -> {
        return "万猫学社";
    };
    
    1. Runnable
    Runnable runnable = () -> {
        return "万猫学社";
    };
    
    1. Comparator<Mask>
    maskList.sort((Mask o1, Mask o2) -> {
        if (o1.getBrand().equals(o2.getBrand())) {
            return o1.getType().compareTo(o2.getType());
        } else {
            return o1.getBrand().compareTo(o2.getBrand());
        }
    });
    

    请思考片刻…
    .
    .
    .

    .
    .
    .
    宣布答案

    1. Callable:正确,Lambda表达式的签名是() -> String,与Callable<String>接口的唯一抽象方法call的签名匹配,所以是正确的。
    2. Runnable:错误,Lambda表达式的签名是() -> String,但是Runnable接口的唯一抽象方法run的签名是() -> void,两者不匹配,所以是错误的。
    3. Comparator<Mask>:正确,Lambda表达式的签名是(Mask, Mask) -> int,与Comparator<Mask>接口的唯一抽象方法compare的签名匹配,所以是正确的。

    怎么样?都答对了嘛?

    欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

    总结

    有且仅有一个抽象方法的接口叫做函数式接口,Lambda表达式可以直接作为函数式接口的实例,函数式接口的抽象方法的签名和Lambda表达式的签名必须一致。

    欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

    《死磕Lambda表达式》系列

    欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

  • 相关阅读:
    网络流24题题解
    NOIP2018游记
    AGC016题解
    雅礼集训总结
    数学相关【真·NOIP】
    NOIP2018系列
    洛咕P4180 严格次小生成树
    矩阵乘法学习笔记
    一些比较神奇的思路
    点分治复习记
  • 原文地址:https://www.cnblogs.com/heihaozi/p/12409205.html
Copyright © 2020-2023  润新知