Java中的类型推断和lambda表达式
简介
java是强类型的编程语言,每个java中使用到的变量都需要定义它的类型,否则会编译失败。强类型语言的好处就是可以尽可能的在编译期间就发现代码中可能出现的问题,从而减少在运行时出现问题的可能性。
相对的,强类型语言的缺点就是不那么的灵活多变,写起来比较冗余。
JDK8之前,java是不支持类型推断的,在JDK8中,引入了lambda表达式,从此类型推断产生了。
本文将会讲解类型推断在lambda表达式中的最佳实践和在使用中应该注意的事项。
更多精彩内容且看:
- 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
- Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
- Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
- java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程
更多内容请访问www.flydean.com
类型的显示使用
假如我们定义了一个CustUser类,并且其中有age和name两个属性:
@Data
@AllArgsConstructor
public class CustUser {
int age;
String name;
}
看下我们怎么在Stream中显示使用类型:
public static void testStream(){
Stream.of(new CustUser(10,"alice"), new CustUser(20,"bluce"))
.forEach( (CustUser custUser)-> System.out.println(custUser.name));
}
上面的例子中,我们构建了一个CustUser类型的Stream,并在forEach方法中对CustUser进行处理。
forEach接收一个Consumer对象,Consumer需要实现void accept(T t)方法。因为Consumer函数接口,我们可以使用lambda表达式来替换。
这里,我们显示传入一个CustUser类型。代码编译是没有问题的,但是看起来复杂了点。接下来我们看下怎么在Stream中使用类型推断。
Stream中的类型推断
上面的例子,我们可以改写成这样:
public static void testInference(){
Stream.of(new CustUser(10,"alice"), new CustUser(20,"bluce"))
.forEach(custUser-> System.out.println(custUser.name));
}
这里我们并没有定义custUser的类型,但是java可以从Stream中的类型推断出来。所以这样写是没有问题的,可以正常通过编译。
类型推断中变量名字的重要性
上面的例子中,我们将变量的名字定义为custUser,查看代码的人一眼就可以看出来这个参数表示的是CustUser类型的custUser参数。
名字写的有意义可以很大程度上提升代码的可读性和可维护性。如果你这样写:
forEach(u-> System.out.println(u.name)
虽然代码变得更短了,但是失去了可读的意义,一眼看过去,大家并不知道你这个u代表的是什么,从而影响了代码的可读性。
所以变量名的定义一定要有意义。
类型推断对性能的影响
类型推断是个好东西,那么有同学会问了,类型推断对于java的性能会有影响吗?
我们可以把java分成编译和运行两部分。类型推断是在编译期间做的事情,可能使用类型推断会延长代码编译的时间,但是对运行时的效率是没有影响的。
一般来说,我们关注程序的性能问题是在运行时而不是编译时,所以类型推断对性能是没有影响的。
类型推断的限制
java虽然有类型推断,但是这个推断是有一定的限制的,它并不能够像人一样去思考,但是也已经足够智能了。下面我们举个例子:
public static Comparator<CustUser> createUser1(){
return (CustUser user1, CustUser user2) -> user1.getAge() - user2.getAge();
}
上面的例子中,我们需要创建一个Comparator,使用lambda表达式我们可以生成一个Comparator。
Comparator需要实现方法int compare(T o1, T o2),传入两个参数,返回一个int。
上面例子中,我们显示指定了两个参数的类型是CustUser,编译没有问题。
如果不显示指定CustUser类型可以吗?
public static Comparator<CustUser> createUser2(){
return (user1, user2) -> user1.getAge() - user2.getAge();
}
答案也是可以的。这个例子中,我们并没有传入user1,user2,java是怎么找到user1和user2的类型呢?
注意,上面的例子中,我们定义了返回类型是CustUser的,Java通过这个返回类型来推断出传入的实际类型就是CustUser的。是不是很智能。
如果我们将上面的return语句拆分成两条,会出现问题问题呢?
Comparator comparator=(user1, user2) -> user1.getAge() - user2.getAge();
这时候就会编译报错,说找不到getAge方法。这是因为我们返回的Comparator并没有指明类型,所以默认情况下是Object类型。Object类型并没有getAge方法,所以报错。
我们可以这样改写:
Comparator<CustUser> comparator=(user1, user2) -> user1.getAge() - user2.getAge();
编译完成,没有错误。
总结
除了JDK8中引入的lambda表示中使用了类型推断,其实JDK10中的var本地变量类型也是用到了类型推断,详请参考JDK10的新特性:本地变量类型var。
本文的例子https://github.com/ddean2009/
learn-java-base-9-to-20
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/java-type-inference-lambda/
本文来源:flydean的博客
欢迎关注我的公众号:程序那些事,更多精彩等着您!
Java中的类型推断和lambda表达式的更多相关文章
- java语言中的匿名类与lambda表达式介绍与总结 (Anonymous Classes and Lambda Expressions)
2017/6/30 转载写明出处:http://www.cnblogs.com/daren-lin/p/anonymous-classes-and-lambda-expressions-in-java ...
- Java基础(十二)lambda表达式
1.引入lambda表达式的重要性 lambda表达式是一个可传递的代码块,可以在以后执行一次或多次. 在前面的回调部分,有一个例子是,ActionListener类实现了TimePrinter接口并 ...
- java多线程--2 静态代理、Lambda表达式
java多线程--2 静态代理.Lambda表达式 静态代理 package com.ssl.demo02; //静态代理 //真实对象和代理对象都要实现同一个接口 //代理对象必须要代理真实角色 / ...
- C++11中新特性之:lambda 表达式
首先摆出Lambda表达式语法 lambda-expression: lambda-introducer lambda-declaratoropt compound-statementlambda-i ...
- - Java中boolean类型占用多少个字节 MD
目录 目录 Java中boolean类型占用多少个字节 1个bit(1位) 1个Byte(1字节,8位) 4个Byte(4字节,32位) 分析 官方文档中的描述 Markdown版本笔记 我的GitH ...
- Java中boolean类型占用多少个字节?我说一个,面试官让我回家等通知
摘自:https://www.cnblogs.com/qiaogeli/p/12004962.html 程序员乔戈里 腾讯面试官问我Java中boolean类型占用多少个字节?我说一个,面试官让我回家 ...
- C++ 中的匿名函数(lambda表达式)
问题引入 使用std::sort函数对自定义类型排序时,我们需要传入一个比较函数作为参数.该比较函数只需要使用一次,但占有一个全局命名域中的名字,而且非常短,短到不需要名字就知道它的作用.这很浪费命名 ...
- Java中double类型的数据精确到小数点后两位
Java中double类型的数据精确到小数点后两位 多余位四舍五入,四种方法 一: double f = 111231.5585;BigDecimal b = new BigDecimal(f); d ...
- java中基本类型封装对象所占内存的大小(转)
这是一个程序,java中没有现成的sizeof的实现,原因主要是java中的基本数据类型的大小都是固定的,所以看上去没有必要用sizeof这个关键字. 实现的想法是这样的:java.lang.Runt ...
- Java进阶(二十三)java中long类型转换为int类型
java中long类型转换为int类型 由int类型转换为long类型是向上转换,可以直接进行隐式转换,但由long类型转换为int类型是向下转换,可能会出现数据溢出情况: 主要以下几种转换方法,供参 ...
随机推荐
- FileBeat简单使用
简介 首先要了解ELK架构 这种结构因为需要在各个服务器上部署 Logstash,而它比较消耗 CPU 和内存资源,所以比较适合计算资源丰富的服务器,否则容易造成服务器性能下降,甚至可能导致无法正常工 ...
- 网络通信部分之bs/cs架构,网络概念,osi七层网络模型,TCP/UDP协议---day27
1.网络开发的两大架构c/s,b/s # ### 1.网络开发的两大架构 a文件 -> b文件 借助c文件 a文件和b文件进行数据交流,借助c文件中转数据 a文件把数据放在c文件中,b文件从c文 ...
- 【ACM专项练习#01】基本输入输出,如何加减
关于ACM,牛客其实也有专门的模拟练习:https://ac.nowcoder.com/acm/contest/5657#question 做这个也可以 关于while(cin>>n) 在 ...
- 【Azure 存储服务】关于中国区Azure Storage Account 存储账号服务误删除后的恢复问题
问题描述 在Azure上,如果需要恢复之前删除的存储账户(Storage Account), 有什么办法呢? 问题解答 Azure 现在推出了自主恢复已删除的存储账号的功能,具体步骤如下: 第一步: ...
- 使用C#和MemoryCache组件实现轮流调用APIKey以提高并发能力
文章信息 标题:使用C#和MemoryCache组件实现轮流调用API Key以提高并发能力的技巧 摘要:本文介绍了如何利用C#语言中的MemoryCache组件,结合并发编程技巧,实现轮流调用多个A ...
- golang官方包管理vendor模式无法引用非go文件
主页 微信公众号:密码应用技术实战 博客园首页:https://www.cnblogs.com/informatics/ 背景&问题 golang作为高级计算机语言之一,在云原生以及web网站 ...
- j-link仿真器的作用和价值以及Ubuntu下使用注意事项
一 J-LINK是什么? J-Link是SEGGER公司为支持仿真ARM内核芯片推出的JTAG仿真器.配合IAR EWAR,ADS,KEIL,WINARM,RealView等集成开发环境支持所有A ...
- Python爬虫实战系列3:今日BBNews编程新闻采集
一.分析页面 打开今日BBNews网址 https://news.bicido.com ,下拉选择[编程]栏目 1.1.分析请求 F12打开开发者模式,然后点击Network后点击任意一个请求,Ctr ...
- terminate called after throwing an instance of 'std::regex_error'(C++11)
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- eviacam在Arch/Manjaro Linux下的安装
安装base-devel 安装编译工具,默认的依赖里没有编译工具 sudo yay -S base-devel 如果安装编译工具,会报类似下面的错误: 安装eviacam yay -S eviacam ...