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:无参无返回 ...
随机推荐
- 机器学习之强化学习概览(Machine Learning for Humans: Reinforcement Learning)
声明:本文翻译自Vishal Maini在Medium平台上发布的<Machine Learning for Humans>的教程的<Part 5: Reinforcement Le ...
- Spring Boot 邮件发送
pom文件依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- twoway 系列命令绘制地图
twoway 系列命令绘制地图 ❝ 在谈到用stata绘制地图时,很多人首先想到的是spmap命令.其实,最常见的twoway系列命令就可以完成我们的大多数绘图需求. 对于spmap命令的使用,在线资 ...
- 系统警告,Bronya请求支援(两遍最短路)
系统警告,Bronya请求支援 Description 休伯利安号的一行人来到了由逆熵镇守的前文明遗迹[海渊城],他们准备用巨大的传送装置[海渊之眼]进入量子之海,寻找丢失的渴望宝石.然而在行动前夜爱 ...
- 新建jsp文件,The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path错误解决方法
新建一个jsp文件后,有一个错误,The superclass "javax.servlet.http.HttpServlet" was not found on the Java ...
- jQuerry点击按钮回到顶部功能
简单实现点击按钮回到顶部功能
- [转发]对ThreadPoolExecutor初识
知识点提前预知: Java.util.concurrent.ThreadPoolExecutor类是ExecutorSerivce接口的具体实现.ThreadPoolExecutor使用线程池中的一个 ...
- PTA数据结构与算法题目集(中文) 7-34
PTA数据结构与算法题目集(中文) 7-34 7-34 任务调度的合理性 (25 分) 假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行.“ ...
- docker中使用mysql数据库详解(在局域网访问)
开发过程中经常需要安装.调试mysql数据库,还需要在各种操作系上安装包依赖,实在是繁琐,因此就研究了一下如何在docker上运行一个mysql镜像,省却了我安装.找依赖的问题. 注:本文所有内容均在 ...
- x86汇编利用int 16h中断实现伪多线程输入
x86汇编利用int 16h中断实现伪多线程输入 我们都知道,如果想让一个程序,同时又干这个,又干那个,最好的办法就是多线程.这个在高级语言里面已经用烂了. 但是,DOS是只有单线程的.我如果想让程序 ...