• 学习笔记Lambda表达式_解析


    现在时间午夜十点~ 此刻的我血脉喷张,异常兴奋:因为专注得学习了一把java,在深入集合的过程中发现好多套路配合Lambda表达式真的是搜椅子,so开了个分支,决定从“只认得”,变为“我懂得”

    start:

    先上一盘代码,对应来解析:

    /*我是一个接口*/
    interface Rap{
        void show();
        //注意:虽然没有用abstract修饰方法,但它真是抽象方法,我特意去试了下,应该是没有方法体的方法默认在前面加abstract
    }
    /*我是二个接口*/
    interface Basketball{
        void play(String name);
        //注意:同上
    }
    
    /*我是一个测试类*/
    public class LambdaTest(){
        //调用下面两个方法,要传递对应类型的对象(也就是我上面定义的接口类型),那得要创建实例才行啊,哈哈看看Lambda的骚操作
        public void method1(Rap r){
            //这是接口中的抽象方法,必须要接口的实现类进行重写才可使用
            r.show();
        }
        public void method2(Basketball b){
            //这是接口中的抽象方法,必须要接口的实现类进行重写才可使用
            b.play("坤坤")
        }
        
        public static void main(String[] args){
            LambdaTest lt = new LambdaTest();
            //Lambda开始操作
            //调用方法1
            //功能代码语句只有一句,可省略大括号
            System.out.println(lt.method1(() -> System.out.println("我是练习时长两年半的..你猜我是谁"));
                               
            //调用方法2
            //功能代码语句有多句,要加大括号
    		System.out.println(lt.method2(name) -> {
                System.out.println("请叫我:"+name);
                System.out.println("擅长唱跳Rap篮球")
            });
        }
    }
    
    解析:
    1. 首先此例将Lambda表达式作为实现了接口的实例对象,传递给了方法(不是对应类型的对象的话方法没有形参,无法调用);
    2. 所以可以确定Lambda表达式可以充当匿名对象
    3. 再看method1和method2两个方法内调用的都是我定义的两个接口中唯一的抽象方法,所以必定要要接口的实现类去重写接口中的抽象方法;
    4. 所以可以看出Lambda表达式可以充当匿名方法
    • 小技巧:箭头(->) 左边的是参数,右边的就是方法体

    • 从上也可以看出Lambda表达式的使用的限制:

      • Lambda表达式的目标类型必须是明确的函数式接口(目标类型就是被他实现的接口类型)
      • Lambda表达式只能为函数式接口创建对象:由于其只能实现一个方法,因此它只能位为只有一个抽象方法的接口(函数式接口)创建对象
    • 为了确保目标类型是一个明确的函数式接口,可以这样设计代码:

      • 将Lambda表达式赋值给函数式接口类型的变量
      • 将Lambda表达式作为函数式接口类型传递给某个方法(如上面的例子)
      • 使用函数接口对Lambda表达式进行强制类型转换
        • 值得一提的是,同样的Lambda表达式,其目标类型是可变的,也就是说通用的,这个接口可以用,换个接口也可以;当然前提是目标类型(接口)中的抽象方法形参列表相同;就好比我有两个函数式接口,都没有参数,然后我写个表达式并进行强制类转换,此时可以这两个接口的类型都可以用

    补充:java8中给函数式接口提供了@FunctionalInterface注解,检查接口必须是函数式接口

    引用

    Lambda表达式的代码块只有一条语句时,可以省略"{ }"花括号,其实还可以写的更简洁:使用方法引用 和 构造器引用,符号为两个英文冒号:::

    有四种引用方式:

    • 引用类方法

      语法:类名 :: 类方法

    /*定义一个函数式接口,将String类型数据转换成Integer*/
    interface Convert{
        //抽象方法,返回类型为Integer
        Integer Convert(String from);
    }
    
    /*使用Lambda表达式的写法创建Convert(目标类型)对象,就是获取接口实现类的实例*/
    Convert c1 = from -> Integer.valueOf(from);
    
    /*使用引用类方法的方式获取Convert对象*/
    Convert c2 = Integer :: valueOf;
    //是不是相当简洁,对比可以看出是将参数省略了,这就是其魅力所在
    //调用接口中抽象方法时,所传递的参数会默认传递给该类方法,即valueOf
    
    • 引用特定对象的实例方法

      语法:特定对象 :: 实例方法

    /*Lambda方式创建Coverter对象,借用上面的接口*/
    Converter c = from -> "fkit.org".indexOf(from);
    
    /*方法引用代替Lambda表达式获取对象*/
    Converter c = "fkit.org" :: indexOf;
    
    • 引用某类对象的实例方法

      语法:类名 :: 实例方法

    /*函数式接口;从指定的位置开始b,截取指定字符串a,指定长度c*/
    interface MyTest{
        String test(String a,int b,int c);
    }
    
    /*Lambda表达式方式获取接口MyTest的实现对象*/
    //有返回值的情况下会将此Lambda表达式作为返回值
    MyTest mt = (a,b,c) -> a.substring(b,c);
    
    /*换成引用方法的方式*/
    //将函数式接口中实现方法的第一个参数作为调用者
    //后面的参数全部传递给方法作为参数
    MyTest mt = String :: substring;
    
    /*使用接口实例调用接口方法*/
    String str = mt.test("我是测试字符串哈哈",2,5);
    System.out.println(str);//打印结果:测试字符串
    
    • 引用构造器

    语法:类名 :: new

    /*定义一个函数式接口,传递参数,调用MyClass类中对应的带参构造器*/
    interface MyTest{
        MyClass creat(String str);
    }
    
    /*使用Lambda表达式获取接口实例对象*/
    MyTest mt = str -> new MyClass(str);
    
    /*使用引用构造器方式*/
    //函数式接口的抽象方法的所有参数都会传递给对应的构造函数
    MyTest mt = MyClass :: new;
    
    /*调用测试*/
    MyClass mc = mt.creat("调用对应构造器创建对象");
    

    扩展

    • Lambda表达式和匿名内部类的联系

      • 相同点:都可以访问父类的成员,且被访问的成员默认修饰final,即不可二次赋值;都可以生成对象,并从接口中继承默认的方法
      • 区别:Lambda表达式只能为函数式接口创建实例(只有一个抽象方法的接口),且只能实现其中的抽象方法,其他方法免谈
    • 使用Lambda配合java.util.function中预定义的函数式接口

      • XxxFunction:这类接口中包含一个apply()抽象方法,用于对参数进行处理、转换
      • XxxConsumer:包含一个accept()抽象方法,与上面的apply()类似,也用于处理数据,只是不会返回处理结果
      • XxxPredicate:包含一个test()抽象方法,用来对参数进行条件判断(常用与过滤集合元素)
      • XxxSupplier:包含一个getAsXxx()抽象方法,该方法会根据所定义的逻辑算法返回一个数据

    上面接口中的抽象方法都可以用Lambda表达式来实现方法的逻辑了

    总的来说,Lambda表达式简洁,还能装逼。但是可读性有点差咯,不说别人来看,自己写的时间长了一时半会还看不懂...所以建议对于常用的函数式接口的实现可以用Lambda实现,或者注释满上,又或者我就要写别人看不懂的代码,nb(我喜欢~)

  • 相关阅读:
    读《高效能人士的七个习惯》有感
    Springboot中的日志
    fastjson JSON.toJavaObject() 实体类首字母大写属性无法解析问题
    java多线程编程实例
    IDEA插件配置推荐
    Spring Boot 自定义数据源 DruidDataSource
    zookeeper环境搭建
    eureka注册中心的使用
    记事本编码
    Chrome浏览器基本操作
  • 原文地址:https://www.cnblogs.com/csyh/p/12445774.html
Copyright © 2020-2023  润新知