程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

Java基础复习(DayTen):lambda表达式

发布于2021-05-29 21:31     阅读(1105)     评论(0)     点赞(2)     收藏(0)


lambda表达式是一个可传递的代码块,可以在以后执行一次或者多次,所以lambda实现的功能就是传递代码块

lamdba表达式其实就是一段代码块,以及必须传入的参数

表达形式为:参数,箭头(->)以及一个表达式
在这里插入图片描述

lambda表达式的使用

函数式接口

lambda一般使用在函数式接口,函数式接口是指只有一个抽象方法的接口,注意这里是只有一个抽象方法的接口,但接口可以有默认实现,也就是不抽象的方法,而且接口有可能会重新声明Object类的方法(这里要提一下,其实在底层中,接口相当于也是继承了Object),重新声明的这些Object类的方法,比如toString或者equals,都会默认有实现的,也就是变得不再抽象。

举个栗子

比如Compartor接口
在这里插入图片描述
可以看到它有一个equals方法,是有具体默认实现的,点进去就发现是Object的equals方法,这也是为什么Compartor最后只要去实现compare方法
在这里插入图片描述
Comparator只有compare没有默认实现,所以实现该接口的类只需要重写这个方法即可。

所以Comparator也算是一个函数式接口

所以我们可以用lambda表达式,将代码传给该接口即可

举个栗子,比如Arrays.sort方法

在这里插入图片描述
该方法需要一个泛型数组,然后需要一个Comparator接口,下面使用lambda表达式去实现该接口即可
在这里插入图片描述
所以总的来说,lambda表达式实现了以代码块为参数,利用该代码块实现了一个接口

方法引用

什么意思呢?lambda表达式可以传代码块,而上面函数式接口的栗子代码块是要自己写的,那能不能去应用其它类的代码块呢?

这是可以的,这种方法也叫做方法引用(引用别人的方法)

举个栗子,在String类上有一个compareToIgnoreCase的方法

在这里插入图片描述
我们可以直接利用它去实现Arrays.sort方法所需的Comparator接口参数
在这里插入图片描述
可能这里就有人疑问了,compareToIgnoreCase所需的参数只要一个,而Comparator的compre方法则需要两个,不是对应不起来吗?

compareToIgnoreCase是一个实例方法,必须实例字符串才可以调用,所以实例的对象也占了一个

//下面这两条语句是等效的
Arrays.sort(array,String::compareToIgnoreCase);
//originalStr代表实例String对象,str代表需要的参数
Arrays.sort(array,(originalStr,str)->{
    return originalStr.compareToIgnoreCase(str);
})
方法引用等价的lambda表达式说明
separator::equalsx->{separator.equals(x)}包含一个对象和一个实例方法的方法表达式,lambda参数作为该方法的显示参数传入
String::trimx->x.trim()一个类和一个实例方法的方法表达式,lambda表达式成为隐式参数
String::concat(x,y)->x.caoncat(y)一个类和一个实例方法的方法表达式,lambda表达式第一个参数为隐式参数,第二个为显示参数
Integer::valueofx->Integer::valueof(x)一个类和其静态方法的方法表达式,lambda表达式作为隐式参数传给静态方法
Integer::sum(x,y)->Integer::sum(x,y)一个类和其静态方法的方法表达式,lambda表达式作为隐式参数传给静态方法
Integer::newx->new Integer(x)一个类和其构造器引用,lambda参数作为构造器的隐式参数
Integer[]::newn->new Integer[n]数组构造器的引用,lambda参数作为数组构造器的隐式参数,代表长度

构造方法引用

lambda对于构造方法是自动匹配的,根据所给的参数

举个栗子,准备一个接口,该接口一个有参数,一个没有参数(注意要注释掉其中一个方法,因为函数式接口只能有一个抽象方法)

在这里插入图片描述
准备一个类,该类调用该接口去修改本身的属性,分别调用不同方法
在这里插入图片描述
在这里插入图片描述
然后调用以下,结果如下
在这里插入图片描述
可以看到,lambda代码块应该传的是有参构造,这是因为接口里面有一个name参数,所以就会变成new Fsy(name),如果我们将接口里面改为无参呢?

变成了如下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到结果变成了NULL,因为接口的抽象方法里面没有参数,就会变成new Fsy(),为无参构造。

使用总结

  • lambda表达式代表的就是代码块,用来实现想要的参数
  • lambda表达式代表的代码块可以自己自定义,也可以去进行方法引用,甚至可以进行构造器引用
  • 使用构造器引用要记得对应,也就是对应接口的参数去执行对应的构造方法

lambda变量作用域

lambda表达式共有三个部分

  • 一个代码块
  • 参数
  • 自由变量的值,这是指为非参数而且不在代码中定义的变量(也参数不属于lambda,而且在lambda中没有定义,lambda单纯进行引用)

闭包是指:一段代码块可以读另一段代码块的函数,通常以函数区分

lambda表达式的代码块可以读取外围的变量,所以这也可以称为闭包

但Java对这方面是有限制的,lambda读取外围的值,必须明确定义有值,而且只能是不可变的,而且在lambda不可以去进行修改他,比如修改其引用地址,这是为了避免并发执行多个动作造成的不安全现象。

成功示例(字符串不可变,在lambda内没有进行修改操作)

在这里插入图片描述
失败示例(没有明确定义有值)
在这里插入图片描述
失败示例(变量会发生修改)
在这里插入图片描述

对lambda表达式的处理

使用lambda表达式的重点是延迟执行

也就是只有要使用到lamdba的代码块实现的接口方法才会去执行lambda生成对应接口,即实现了要用到才会去生成

假如有一个日志操作为

public class Demo01Logger {
    private static void log(int level, String msg) {
        if (level == 1) {
           System.out.println(msg);
        }
    }
    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";
        log(1, msgA + msgB + msgC);
    }
}

那么无论日志等级(level)为什么,字符串(msgA,msgB,msgC)都会去进行拼接

那假设我们去实现一个日志接口,使用lambda表达式,那不就可以让日志等级到达leve1=1的时候才进行拼接咯,不就可以节约性能了。

@FunctionalInterface
public interface ShowLog {
    public abstract String BuilderMessage();
}
//具体修改成
public class ShowLogImpl {

    public static void showBuilderString(int level,ShowLog log){
        if(level == 1){
            System.out.println(log.BuilderMessage());
        }
    }

    public static void main(String[] args) {
        String msg1 = "Hello ";
        String msg2 = "Java ";
        String msg3 = "World ";
        //改为lambda实现
        showBuilderString(1,()->{
            return msg1+msg2+msg3;
        });
    }
}


所属网站分类: 技术文章 > 博客

作者:我是个大美女

链接:http://www.javaheidong.com/blog/article/207431/8155946404974ab6d0b2/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

2 0
收藏该文
已收藏

评论内容:(最多支持255个字符)