学习Lambda表达式看这篇就够了,不会让你失望的哦(续篇)

欢迎关注头条号:老顾聊技术

精品原创技术分享,知识的组装工


目录

  1. 前言
  2. Lambda类型
  3. Lambda的域以及访问限制
  4. 内置函数接口
  5. 方法引用
  6. 静态方法引用
  7. 实例方法引用
  8. 对象方法引用
  9. 构造方法引用
  10. 总结

前言

上一篇介绍了lambda表达式的语法和使用场景Lambda用在哪里?几种场景? 和 为什么会出现Lambda表达式,你知道吗?,今天老顾继续介绍

Lambda类型

Lambda表达式可以被当做是一个Object。Lambda表达式的类型,叫做“目标类型(target type)”。Lambda表达式的目标类型是“函数接口(functional interface)”

有一个接口,如果只有一个显式声明的抽象方法,那么它就是一个函数接口。一般用@FunctionalInterface标注出来(也可以不标)。举例如下

我们看到最后的Comparator接口,声明了两个方法,好像不符合函数接口的定义,但Comparator确实是函数接口。这个是因为equals方法是Object的,所有的接口都会声明Object的public方法(虽然大多是隐式的)。所以,Comparator显式的声明了equals不影响它依然是个函数接口

虽然Lambda虽然可以当作是Object类型,但需要显式转换才行。

我们可以用一个Lambda表达式为一个函数接口赋值

Runnable r1 = () -> {System.out.println("Hello Lambda!");};

然后再赋值给一个Object:

 Object obj = r1;

但却不能这样干:

Object obj = () -> {System.out.println("Hello Lambda!");}; 
// ERROR! Object is not a functional interface!

必须显式的转型成一个函数接口才可以:

Object o = (Runnable) () -> { System.out.println("Hello Lambda!"); };

一个Lambda表达式只有在转型成一个函数接口后才能被当做Object使用。所以下面这句也不能编译:

System.out.println( () -> {} ); //错误! 目标类型不明

必须先转型:

System.out.println( (Runnable)() -> {} ); // 正确

我们可以定义一个无参数,无返回值的接口,类似Runnable

@FunctionalInterface 
public interface MyRunnable { 
 public void run(); 
}

那下面的写法,都是正确的

Runnable r1 = () -> {System.out.println("Hello Lambda!");};
MyRunnable r2 = () -> {System.out.println("Hello Lambda!");};

这说明一个Lambda表达式可以有多个目标类型(函数接口),只要函数匹配成功即可。

但需注意一个Lambda表达式必须至少有一个目标类型

Lambda的域以及访问限制

域即作用域,Lambda表达式中的参数列表中的参数在该Lambda表达式范围内(域)有效。在作用Lambda表达式内,可以访问外部的变量:局部变量、类变量和静态变量,但操作受限程度不一

1、访问局部变量

在Lambda表达式外部的局部变量会被JVM隐式的编译成final类型,因此只能访问外而不能修改。

2、访问静态变量和成员变量

在Lambda表达式内部,对静态变量和成员变量可读可写。

内置函数式接口

小伙伴们有没有发现,如果使用Lambda表达式,还是需要我们自己写一个接口定义的,其实很多接口无非是入参类型和返回值不一样而已,所以Java给我们提供了几个常用的标准函数接口:

Consumer< T >con 消费型接口: void accept(T t);

Supplier< T >sup供给型接口: T get();

Function< T , R >fun 函数型接口: R apply (T t);

Predicate< T >: 断言型接口: boolean test(T t);

1、Consumer 消费型接口

接口中的方法为 void accept(T t),1个参数,无返回值。调用方要传入值,而不需要返回,形象比喻成消费型

这个就是对传入num参数值,进行相关的处理(消费)。到底进行处理,具体就在

(num) -> System.out.println("消费了" + num)

上面的代码中,是一个典型的1个参数,无返回值的消费;如果没有内置的函数接口,那我们就需要自己定义一个,如:

interface MyConsumer{
	void doFunction(T t);
}

我们发现和内置函数接口,没有什么区别,就是接口名和方法名称不一样而已,其实本质是一样的,这就是为什么Java会提供一些内置的函数,这样可以减少大量的代码。

2、Supplier供给型接口

接口中的方法 T get(),无参数,有返回值;不需要对方给参数,而是一直返回给对方,形象定义为供给型接口

上面代码就是返回一个新的实体对象。

3、Function函数式接口

接口中的方法 R apply (T t),有参数,有返回值;典型的函数,所以形象比喻成函数型接口

接口实现转换成大写的字符。

4、Predicate断言型接口

接口中方法 boolean test(T t),有参数,返回boolean,是一个条件检查式方法,比喻成断言型接口

内置的函数接口,大大的提高开发的效率,减少了开发代码

方法引用

方法引用是Lambda表达式的一个简化写法,其语法结构为:

ObjectRef::methodName

左边可以是类名或者实例名,中间是方法引用符号“::”,右边是相应的方法名。方法引用可以分为三类。

使用前提:Lambda体中调用方法的参数列表和返回值类型,要和函数式接口中抽象方法的参数列表和返回值类型保持一致

静态方法引用

先上一个案例

上面的代码中,我们发现Converter匿名类重载方法中,调用了ReferenceTest的静态方法String2Int。再有函数接口的方法参数类型 和 返回值类型,跟String2Int是一样的,入参为String,返回值为Integer。那我们这个时候可以简化成

直接用静态方法进行赋值,是不是很简洁。

实例方法引用

如果函数式接口的实现恰好可以通过调用一个实例的实例方法来实现,那么就可以使用实例方法引用

对象方法引用

抽象方法的第一个参数类型刚好是实例方法的类型(函数式接口的抽象方法必须要有输入参数)抽象方法剩余的参数恰好可以当做实例方法的参数

如果函数式接口的实现能由上面说的实例方法调用来实现的话,那么就可以使用对象方法的引用(两个条件都要满足)

我们看到第一参数Prod s,和实例对象new Prod是同一个类型;剩余的参数s1,正好是实例方法fun的参数;这样就可以简化成Prod::fun

构造方法引用

如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用,语法【类名::new】

上面是无参数的构造函数,再来看看有参构造函数

到这里,老顾来个方法引用的总结:

总结

Lambda表达式要熟练掌握,是要小伙伴们经常去写,才能够运用自如,代码虽然比较简洁,但确实没有接触的开发人员看上去,就懵逼了,可读性不强。还有Stream的知识点,老顾后面再介绍;今天就分享到这里,谢谢!!!


--End--

最近老顾上传了微服务网关的分享课程,请大家支持

推荐阅读

1、Lambda用在哪里?几种场景?

2、为什么会出现Lambda表达式,你知道吗?

3、不说“分布式事务”理论,直接上大厂阿里的解决方案,绝对实用

4、女程序员问到这个问题,让我思考了半天,Mysql的“三高”架构

5、大厂二面:CAP原则为什么只能满足其中两项?而不能同时满足

6、阿里P7二面:聊聊零拷贝的原理

7、秒杀系统的核心点都在这里,快来取

8、你了解如何利用token方式实现分布式Session吗?

9、Mysql索引结构演变,为什么最终会是那个结构呢?让你一看就懂

10、一场比赛涉及到的知识,用通俗易通的方式介绍并发协调

11、企业实战Redis全方面思考,你思考了吗?

12、面试题:Thread的start和run的区别

13、面试题:什么是CAS?CAS的作用以及缺点

14、如何访问redis中的海量数据?避免事故产生

15、如何解决Redis热点问题?以及如何发现热点?

16、如何设计API接口,实现统一格式返回?

17、你真的知道在生产环境下如何部署tomcat吗?

18、分享一线互联网大厂分布式唯一ID设计 之 snowflake方案

19、分享大厂分布式唯一ID设计方案,快来围观

20、你想了解一线大厂的分布式唯一ID生成方案吗?

21、你知道如何处理大数据量吗?(数据拆分篇)

22、如何永不迁移数据和避免热点? 根据服务器指标分配数据量(揭秘篇)

23、你知道怎么分库分表吗?如何做到永不迁移数据和避免热点吗?

24、你了解大型网站的页面静态化吗?

25、你知道如何更新缓存吗?如何保证缓存和数据库双写一致性?

26、你知道怎么解决DB读写分离,导致数据不一致问题吗?

27、DB读写分离情况下,如何解决缓存和数据库不一致性问题?

28、你真的知道怎么使用缓存吗?

29、如何利用锁,防止缓存击穿?重构思想的重要性

30、海量订单产生的业务高峰期,如何避免消息的重复消费?

31、你知道如何保障生产端100%消息投递成功吗?

32、微服务下的分布式session该如何管理?

展开阅读全文

页面更新:2024-04-09

标签:表达式   续篇   分布式   变量   静态   函数   实例   失望   接口   参数   类型   方法

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top