Java8新特性(1):Lambda表达式
Lambda表达式可以理解为一种匿名函数:没有名称,但有参数列表、函数主体、返回类型。它是行为参数化的一种实现,行为参数化是指将不同的行为作为参数传递给方法,方法的所具备的能力取决于它接收的行为参数。使用Lambda表达式使我们不必为这些行为去编写一堆固定的实现类就能应对不断变化的需求,在1.8之前,可以使用匿名内部类的方式达到相同的效果,只是相对于Lambda表达式来说,匿名内部类的方式会显得啰嗦。
函数式接口
Lambda表达式的使用依赖于函数式接口,只有在接受函数式接口的地方才可以使用Lambda表达式。函数式接口是指只声明了一个抽象方法的接口,可以有多个静态方法、默认方法,如下所示:
@FunctionalInterface
public interface Calculation {
int calculate(int a, int b);
}
@FunctionalInterface注解表示被标注的接口将被设计成一个函数式接口,不是必须的,它主要是在接口违背函数式接口原则时会出现编译错误。比如修改Calculation接口,再添加一个抽象方法就会出现Multiple non-overriding abstract methods found in interface com.cf.demo.lambda.Calculation编译错误:
//编译错误:Multiple non-overriding abstract methods found in interface com.cf.demo.lambda.Calculation
@FunctionalInterface
public interface Calculation {
int calculate(int a, int b);
int calculate2(int a, int b);
}
注意:Object类的方法是特例,即使接口声明了多个Object类的方法,也不会被算入“只声明了一个抽象方法”的计数中。如下Calculation接口是正确的函数式接口:
@FunctionalInterface
public interface Calculation {
int calculate(int a, int b);
boolean equals(Object obj);
}
Java8提供了一些常用的函数式接口,位于java.util.function包下,并且为了避免装箱操作,还提供了和基本类型对应的接口,我们在实际使用时,可以优先使用这些内置的函数式接口。当然在某些情况我们也需要使用自定义的函数式接口,如需要在Lambda表达式中抛异常时,这种情况就需要自定义一个函数式接口,并声明异常。
Lambda表达式语法
Lambda表达式由参数列表、箭头(Lambda操作符)、Lambda主体三个部分组成。Lambda表达式的参数列表要和函数式接口的参数列表相对应,Lambda主体的返回值也要和函数式接口的返回类型相对应。现在有如下doArithmetic方法,接收两个整型参数以及一个Calculation,doArithmetic方法的行为是由传递的Calculation来决定的,我们可以调用该方法传递不同的Calculation来完成不同的计算:
public static int doArithmetic(int a, int b, Calculation calculation){
return calculation.calculate(a, b);
}
现在要计算两个数的乘积,用内部类的方式:
int result = doArithmetic(3, 2, new Calculation() {
@Override
public int calculate(int a, int b) {
return a * b;
}
});
System.out.println(result);//6
用Lambda表达式的方式要更简洁:
int result = doArithmetic(3, 2, (int a, int b) -> a * b);
System.out.println(result);//6
(int a, int b)是Lambda表达式的参数列表部分,只有一个参数的时候可以省略小括号,这里有多个参数,所以要保留小括号。参数类型可以省略,因为Java编译器能通过上下文推断出数据类型,无需显示的声明:
int result = doArithmetic(3, 2, (a, b) -> a * b);
System.out.println(result);//6
Lambda主体只有一个语句时,可以省略{}和return,(int a, int b) -> a * b)就是省略之后的写法,我们也可以使用完整的写法:
int result = doArithmetic(3, 2, (a, b) -> {
return a * b;
});
System.out.println(result);//6
当需要在Lambda表达式中使用‘外部局部变量’时,这个‘外部局部变量’默认是final的,‘外部局部变量’这里是指非Lambda表达式内部定义的局部变量。修改doArithmetic方法,添加一个‘外部局部变量’,为乘积赋个初始值,以下代码是编译不通过的:
int initialValue = 1;
int result = doArithmetic(3, 2, (a, b) -> a * b + initialValue);
initialValue = 2;//Variable used in lambda expression should be final or effectively final
System.out.println(result);
方法引用
方法引用可以对‘某种特殊情况’下的Lambda表达式进行简化,‘某种特殊情况’是指Lambda表达式要做的事情别的方法实现了,那我们就可以直接使用这个方法,然后像Lambda表达式一样传递即可。方法引用的语法为目标引用放在分隔符::前,方法的名称放在后面,目标引用可以是类名也可以是对象名。通过以下三个例子来介绍方法引用的三种使用方法,新增Arithmetic类,Arithmetic类包含一个静态方法和一个实例方法:
public class Arithmetic {
public static int multiply(int a, int b){
return a * b;
}
public int add(int a, int b){
return a + b;
}
}
1.指向静态方法的方法引用
int multiplyResult = doArithmetic(3, 2, Arithmetic::multiply);
System.out.println(multiplyResult);//6
2.指向现有对象的实例方法的方法引用
Arithmetic arithmetic = new Arithmetic();
int addResult = doArithmetic(3, 2, arithmetic::add);
System.out.println(addResult);//5
3.指向任意类型实例方法的方法引用,这种情况有个特点,就是在引用一个对象的方法,而这个对象本身是Lambda的一个参数。比如现在需要实现比较两个数的大小,首先修改calculate方法参数类型为包装类型Integer:
@FunctionalInterface
public interface Calculation {
int calculate(Integer a, Integer b);
}
比较a和b的大小可以这样写:
int result = doArithmetic(3, 2, Integer::compareTo);//Integer::compareTo等于a.compareTo(b)
System.out.println(result);//1
构造函数引用
对于一个现有构造函数,可以使用它的名称和new来创建一个它的引用: ClassName::new。再使用构造函数引用时,需要调用的构造器参数列表要和函数式接口的抽象方法的参数要一致。举个例子,现在添加了两个生成String对象的方法:
public static String generateString(Supplier<String> supplier) {
return supplier.get();
}
public static String generateString(String value, Function<String, String> function) {
return function.apply(value);
}
分别使用构造函数引用:
String result = generateString(String::new);//调用String()构造方法
System.out.println(result);
result = generateString("hello Lambda", String::new);//调用String(String original)构造方法
System.out.println(result);
Java8新特性(1):Lambda表达式的更多相关文章
- java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合
java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...
- Java8 新特性学习 Lambda表达式 和 Stream 用法案例
Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...
- Java8新特性之Lambda表达式
lambda表达式是java8给我们带来的几个重量级新特性之一,借用lambda表达式,可以让我们的java程序设计更加简洁.最近新的项目摒弃了1.6的版本,全面基于java8进行开发,本文是java ...
- Java8 新特性之Lambda表达式
1. Lambda 表达式概述 Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递); Lambda 表达式可以写出更简洁,更灵活的代码 ...
- 【Java8新特性】Lambda表达式基础语法,都在这儿了!!
写在前面 前面积极响应读者的需求,写了两篇Java新特性的文章.有小伙伴留言说:感觉Lambda表达式很强大啊!一行代码就能够搞定那么多功能!我想学习下Lambda表达式的语法,可以吗?我的回答是:没 ...
- 【Java8新特性】- Lambda表达式
Java8新特性 - Lambda表达式 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...
- 夯实Java基础(二十二)——Java8新特性之Lambda表达式
1.前言 Java 8于14年发布到现在已经有5年时间了,经过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)之后的又一个非常最重要的版本.因为Java 8里面出现了非常多新的特 ...
- java8新特性之——lambda表达式的使用
lambda表达式简介 个人理解,lambda表达式就是一种新的语法,没有什么新奇的,简化了开发者的编码,其实底层还是一些常规的代码.Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解 ...
- 【Java8新特性】Lambda表达式
一.Lambda 表达式 是什么? Lambda读音:拉姆达. Lambda是一个匿名函数,匿名函数就是一个没有名字的函数. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). ...
- Java8 新特性(一)- Lambda 表达式
2014年3月18日发布了JavaSE 8 不追求技术的新,追求技术的稳定 本质:Lambda 表达式是一个匿名函数 作用:简化代码,增强代码的表达力 Lambda 语法格式 // 格式1:无参无返回 ...
随机推荐
- Python电影数据分析
数据说明:MovieLens数据集,它包含来自于943个用户以及精选的1682部电影的100K个电影打分.每个用户至少为20部电影打分,数据类型user id | item id | rating | ...
- Building Applications with Force.com and VisualForce (DEV401) (二一):Visualforce Componets (Tags) Library Part 1
Dev401-022:Visualforce Pages: Visualforce Componets (Tags) Library Part 1 Module Objectives1.List ke ...
- python之面向对象性封装,多态,以及鸭子类型
默认类型 class A: class_name = 'python23期' def __init__(self, name, age): self.name = name self.age =age ...
- OpenCV-Python 直方图-4:直方图反投影 | 二十九
目标 在本章中,我们将学习直方图反投影. 理论 这是由Michael J. Swain和Dana H. Ballard在他们的论文<通过颜色直方图索引>中提出的. 用简单的话说是什么意思? ...
- 深度强化学习(DRL)专栏开篇
2015年,DeepMind团队在Nature杂志上发表了一篇文章名为"Human-level control through deep reinforcement learning&quo ...
- [vijos1304]回文数<模拟>
题目链接:https://vijos.org/p/1304 好久没写博客了,最近一直打不出题,感觉自己是废了,今天做了一道模拟水题,但还是半天没过,后来才发现是忘记考虐10以上的进制是带有字母的,然后 ...
- RecyclerView 的 Item 的单击事件
RecyclerView 的每个Item的点击事件并没有像 ListView 一样封装在组件中,需要 Item 的单击事件时就需要自己去实现,在 Adapter 中为RecyclerView 添加单击 ...
- P1345 [USACO5.4]奶牛的电信(点拆边 + 网络最小割)
题目描述 农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流.这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,-,a©,且a1与a2相连,a2 ...
- 汇编刷题:统计2000H开始的正负数的个数
DATA SEGMENT ORG 2000H INFO DB 1,2,3,4,5,70H,71H,72H,80H,92H N_NUMS DB 00H P_NUMS DB 00H DATA ENDS C ...
- 使用VirtualBox+Vagrant快速搭建Linux虚拟机环境
1. 软件准备 下载.安装Virtual Box https://www.virtualbox.org/wiki/Downloads 下载.安装Vagrant https://www.vagrantu ...