Java8新特性学习之二:lambda表达式深入学习

Java8新特性学习之二:lambda表达式深入学习

前言:

前面我们已经学习lambda的入门,也感性的了解了lambda可以帮助我们解决什么问题,今天跟大家一起深入的学习如何使用、以及在哪里使用lambda表达式。如果你希望在看源码中遇到了lambda表达式不会抓狂;你希望你的代码更加优雅、简洁、或者装逼专用,咱们一起来学习。

 

  • Lambda表达式的语法
  • 在哪里使用、如何使用lambda
  • Lambda扩展

一、lambda表达式语法

如果你见过lambda表达式、或者你看过我的上一篇文章,你应该见过类似下面的代码

Thread thread = new Thread(()-> System.out.println("i am a thead ,i am running my name is "+Thread.currentThread().getName()));
thread.start();

redApples.sort((Apple a1,Apple a2)->a1.getWeight()-a2.getWeight());
Thread t = new Thread(()->{
    int a = 1;
    System.out.println(a);
});
t.start();

上面就是lambda表达式,那么lambda表达式的语法到底是怎么样的呢?使用它需要注意什么?我们从上面两个两个例子中应该能抓住一些lambda共有的特性,比如()->{}或者()->xxx。我们发现lambda表达式主要包括三个部分

1、参数列表:()里面的内容,如果为空,那么就没有参数

2、箭头:把参数列表和主体分开

3、Lambda主体:是一个表达式或者{}的内容,有返回值(返回值可能为void)

Lambda表达式的语法分下面两种:

1、(parameter)->expression

2、(parameter)->{statement;}

 

为了更加详细的掌握lambda的语法规则,下面用几个实例表示(伪代码)

//用伪代码解析lambda表达式的规则
//参数是String类型的变量,并且返回一个int,这里的retur隐藏起来了
(String s)->s.length()
//参数是Apple类型的变量,返回时一个boolean类型,return隐藏起来了
(Apple apple)->apple.getWeight() > 150
//接受两个int类型的参数,没有返回值类型,或者理解为返回void,表达式可以包括多行,需要用{}包起来
(int x,int y)->{
    System.out.println("x+y:");
    System.out.println(x+y);
}
//没有参数,返回是int类型
()->42
//接受两个apple类型,返回int类型
(Apple a1,Apple a2)->a1.getWeight()-a2.getWeight()
//return 语句是控制流语句,必须要用{}包起来,下面写法是错误的
(int a)-> return "test"+a;
//上面的正确写法应该是这样的,接受一个int类型的参数,返回一个String类型
(int a)->{return "test"+a};
//“test”是表达式,不是语句,不能用大括号包起来,这种写法是错误的。有两种修改的方式
(String s)->{"test";}
//正确写法1:不用{}:接受一个String类型的参数,返回String类型
(String s)->"test"
//正确写法2:加return
(String s)->{return  "test";}

通过上面的实例,相信大家应该都掌握了编写lambda表达式的技巧了,其实lambda表达式可以理解为一个匿名函数,将行为参数化。

二、在哪里使用、如何使用lambda

回想一下我们在前面学习的时候,在哪些场景里面使用过lambda呢?Runnable、Comparator、ApplePredicate、FruitsPredicate?当参数为这些的时候,我们用过lambda是不是?是的,不错,官网上说的是“你可以在函数式接口上使用lambda表达式”,这里有一个关键字是函数式接口,什么叫做函数式接口?下面给出它的定义

函数式接口:只定义一个抽象方法的接口

这好像跟我们刚才想的Runnable、Comparator、ApplePredicate一样,就是一个函数式接口,我们可以尝试一下在FruitsPredicate中编写两个方法,看看会发生什么。

public interface FruitsPredicate<T> {

    boolean test(T fruits);

    boolean test2(T fruits,T t2);
}

Java8新特性学习之二:lambda表达式深入学习

 会报错,没错,因为这段代码不能确定要传递哪个方法。

在哪里使用lambda这个问题,相应大家应该都知道了,就是在函数式接口中可以使用lambda表达式。那是不是我们知道了lambda表达式的语法、以及在哪里使用lambda表达式就可以了呢?答案是不够的,lambda表达式的编写还需要和函数式接口中的方法有一定的匹配规则,就是lambda表达式的参数(包括类型和个数)和返回值类型要和函数式接口的方法参数和返回值要一致。否则也是无法编译的,我们可以测试一下。

Java8新特性学习之二:lambda表达式深入学习

 这里报了一个参数不匹配的错误,因为我的函数式接口是这样子的

public interface FruitsPredicate<T> {

    boolean test(T fruits);

    //boolean test2(T fruits,T t2);
}

这里要求参数是一个对象,那么我传了两个,所以报错了

Java8新特性学习之二:lambda表达式深入学习

 这里报的错是我的函数式接口的返回值是boolean类型,而我的lambda表达式返回的int类型,也是不匹配,所以报错。好了,我相信到这里,小伙伴们应该都会使用lambda表达式了。我们有没有想过,lambda表达式是如何和函数式接口发生关联的呢?当我们使用下面的代码他是如何工作的呢?

List<Apple> heavyApples = filterFruits(inventory,(Apple apple)-> apple.getWeight() > 150);

简单的用一个流程图来描述一下:

Java8新特性学习之二:lambda表达式深入学习

三、lambda表达式扩展

1、同样的lambda表达式,不同的函数式接口

这个很简单,就是lambda表达式相同,比如都是(String name)->name +“hello world”

但是函数式接口不一样,定义两个不同的函数式接口就行啦,返回值和参数一样

2、类型推断

你有可能见过下面类似的lambda表达式的写法

redApples.sort(( a1, a2)->a1.getWeight()-a2.getWeight());
redApples.sort((Apple a1,Apple a2)->a1.getWeight()-a2.getWeight());

这两者有什么不一样吗?可以尝试下,运行的结果是一样的,这两个的唯一的区别就是第一句代码中省略了类型,这也是ok的,这是因为lambda表达式可以根据函数式接口的方法推断出参数的类型,所以以后遇到了没有类型的参数,不用大惊小怪,当然还是建议使用加上参数类型,因为这样可读性会好很多(即便省略了参数类型,性能上也没任何的提升)

3、方法引用

你或许见过下面的lambda表达式的写法

redApples.sort(comparing(Apple::getWeight));

当然comparing()方法是Comparator里面的方法,这是通过静态导入的方式,让我们使用起来就像调用本类的方法一样,这不是我们这次关注的重点,我们重点关注的是Apple::getWeight,这种方式就是方法引用。方法引用让你可以重复使用现有的方法定义,并想lambda一样传递它们,有时候,它比lambda表达式可读性更好。它的基本思想是:如果一个lambda代表的只是“直接调用这个方法”,那最好还是用名称来调用它,而不是用描述如何调用它。它是如何工作的呢?当你需要使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面,不需要使用括号,因为并没有实际调用这个方法,上面的方法引用其实就是(Apple apple)->apple.getWeight()的快捷写法。好了希望通过这篇文章可以让小伙伴们学会如何使用lambda表达式,下面我还会跟大家一起学习Stream流和Optional等java8的新特性。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/111219.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • nessus怎么用_nessus如何换端口

    nessus怎么用_nessus如何换端口打开安装有nessus软件的虚拟机,输入账号密码输入ifconfig打开浏览器,输入虚拟机的IP地址,加端口号8843这个时候,等一会,加载完插件,就可以输入用户名密码

    2022年10月18日
  • python3 时间戳_python如何获取当前时间

    python3 时间戳_python如何获取当前时间前言python3中,可以通过datetime、time模块去获取想要的时间戳获取方式使用time模块>>>importtime>>>time.time()获取纳秒时间戳time.time_ns()使用datetime模块>>>fromdatetimeimportdatetime>>>datetime.timestamp(datetime.now())结语time—时间的访问和转换

  • 决策树的原理_决策树特征选择

    决策树的原理_决策树特征选择决策树的原理:根据树结构进行决策,可以用于分类和回归。一颗决策树包括一个根结点、若干个内部节点和若干个叶节点。从根节点出发,对每个特征划分数据集并计算信息增益(或者增益率,基尼系数),选择信息增益最大的特征作为划分特征,依次递归,直至特征划分时信息增益很小或无特征可划分,形成决策树。决策树优点1.计算复杂度不高;2.输出结果易于理解;3.不需要数据预处理;4…

  • vue双向绑定失效_vue 跨域

    vue双向绑定失效_vue 跨域v-for渲染一个数组到视图上,对这个数组进行如下操作时会导致双向绑定失败无法在视图上渲染最新的数据:1.对这个数组的数组项整个进行修改Item:[{name:’小王’,age:19,},{name:’小张’,age:22}]this.Item[0]={name:’小K’,age:98}此时发现视图上渲染的第0项是没有改变的,但是打印出来的Item是已经修改到的为什么说整个数组项,如果对数组内对象的某个属性值修改,视图上还是能监听到的2.对这个数组进行添加或删除操作this.Ite

  • Django(22)Django执行SQL语句「建议收藏」

    Django(22)Django执行SQL语句「建议收藏」前言Django在查询数据时,大多数查询都能使用ORM提供的API方法,但对于一些复杂的查询可能难以使用ORM的API方法实现,因此Django引入了SQL语句的执行方法,有以下三种执行方式ext

  • spring boot 时间戳转日期格式

    spring boot 时间戳转日期格式第一种方式:默认的json处理是jackson也就是对configureMessageConverters没做配置时mybatis数据查询返回的时间,是一串数字,如何转化成时间。两种方法,推荐第一种方法一:可以在apllication.property加入下面配置就可以#时间戳统一转换  spring.jackson.date-format=yyyy-MM-ddHH:mm:ss…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号