Java8新特性探索之Lambda表达式
为什么引入Lambda表达式?
- Lambda 表达式产生函数,而不是类。 在 JVM(Java Virtual Machine,Java 虚拟机)上,一切都是一个类,因此在幕后执行各种操作使 lambda 看起来像函数 —— 但作为程序员,你可以高兴地假装它们“只是函数”。
- Lambda 语法尽可能少,使用 Lambda 表达式可以使代码变的更加简洁紧凑, 易于编写和使用。
- Lambda 表达式通常比匿名内部类产生更易读的代码。
如何使用Lambda表达式?
首先我们先了解下Lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
任何 Lambda 表达式的基本语法是:
- 参数
- 接着
->,可视为“产出”。 ->之后的内容都是方法体。- [1] 当只用一个参数,可以不需要括号
()。 然而,这是一个特例。 - [2] 正常情况使用括号
()包裹参数。 为了保持一致性,也可以使用括号()包裹单个参数,虽然这种情况并不常见。 - [3] 如果没有参数,则必须使用括号
()表示空参数列表。 - [4] 对于多个参数,将参数列表放在括号
()中。 - [5] 如果在 Lambda 表达式中确实需要多行,则必须将这些行放在花括号中。 在这种情况下,就需要使用 return。到目前为止,所有 Lambda 表达式方法体都是单行。 该表达式的结果自动成为 lambda 表达式的返回值,在此处使用 return 关键字是非法的。 这是 lambda 表达式简化相应语法的另一种方式。
- [1] 当只用一个参数,可以不需要括号
Lambda 表达式实例
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
我们在 LambdaExpressions.java 中看到了一个 Lambda 表达式,但还有其他语法变体:
interface Description {
String brief();
}
interface Body {
String detailed(String head);
}
interface Multi {
String twoArg(String head, Double d);
}
public class LambdaExpressions {
static Body bod = h -> h + " No Parens!"; // [1]
static Body bod2 = (h) -> h + " More details"; // [2]
static Description desc = () -> "Short info"; // [3]
static Multi mult = (h, n) -> h + n; // [4]
static Description moreLines = () -> { // [5]
System.out.println("moreLines()");
return "from moreLines()";
};
public static void main(String[] args) {
System.out.println(bod.detailed("Oh!"));
System.out.println(bod2.detailed("Hi!"));
System.out.println(desc.brief());
System.out.println(mult.twoArg("Pi! ", 3.14159));
System.out.println(moreLines.brief());
}
}
输出结果:
Oh! No Parens!
Hi! More details
Short info
Pi! 3.14159
moreLines()
from moreLines()
lambda 表达式规约
Lambda 表达式的参数可以通过上下文推断,如果需要显示声明一个参数的类型,则必须为所有的参数声明类型。
@FunctionalInterface
public interface IFunctionMod {
boolean (int n, int d);
} IFunctionMod function = (n, d) -> (n % d) == 0 // 合理,n 和 d 的类型通过上下文推断
IFunctionMod function = (int n, int d) -> (n % d) == 0 // 合理,指定 n 和 d 的类型
IFunctionMod function = (int n, d) -> (n % d) == 0 // 不合理,须显示声明所有参数类型
Lambda 表达式中抛出的异常需要与目标函数式接口的抽象方法抛出的异常类型兼容。
以下是合理的:
@FunctionalInterface
public interface IFunctionMod {
boolean (int n, int d) throw Exception;
} IFunctionMod function = (n, d) -> {
if (d == 0) {
// IOException是EXception 的子类,通过类型转换,IOException 可转换为 Exception
throw new IOException("test");
}
return n % d == 0;
};
如果反一下,就不行:
@FunctionalInterface
public interface IFunctionMod {
boolean (int n, int d) throw IOException;
} IFunctionMod function = (n, d) -> {
if (d == 0) {
// 父类不能通过自动类型转换转为子类,lambda 表达式抛出的异常类型与抽象方法抛出的异常类型不兼容
throw new Exception("test");
}
return n % d == 0;
};
Lambda 表达式中参数类型需要与目标函数式接口中抽象方法的参数类型兼容。
从接口与实现的角度,可以很容易理解抛出异常兼容 和 参数类型兼容 这2点。
变量作用域
lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
在 lambda 表达式中访问外层的局部变量:
public class LambdaTester {
public static void main(String args[]) {
final int num = 1;
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2); // 输出结果为 3
} public interface Converter<T1, T2> {
void convert(int i);
}
}
lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
int num = 1;
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2);
num = 5;
//报错信息:Local variable num defined in an enclosing scope must be final or effectively
final
在 lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。
String first = "";
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length()); //编译会出错
总结
- Lambda表达式没有命名,用来像传递数据一样传递操作。
- 函数接口指的是只有一个抽象方法的接口,被当做是lambda表达式的类型。
Java8新特性探索之Lambda表达式的更多相关文章
- Java8新特性之一:Lambda表达式
Java8是自java5之后最重大的一次更新,它给JAVA语言带来了很多新的特性(包括编译器.类库.工具类.JVM等),其中最重要的升级是它给我们带来了Lambda表达式和Stream API. 1. ...
- Java8新特性之forEach+Lambda 表达式遍历Map和List
这是Java8系列的第二篇,今天来说一下Java8中forEach的简单使用.我们使用对比的方式来看应该会看得更加清楚,更能理解: 一.遍历Map ============Java8之前的方式==== ...
- java8新特性1:lambda表达式和函数式接口
1.lambda的介绍: 1.1.为什么java语言需要引入lambda表达式? java语言诞生于1995年,历史时间已经相对较长了.在其后的各种新型编程语言中,都有着lambda表达式的内容,并且 ...
- Java8新特性(1):Lambda表达式
Lambda表达式可以理解为一种匿名函数:没有名称,但有参数列表.函数主体.返回类型.它是行为参数化的一种实现,行为参数化是指将不同的行为作为参数传递给方法,方法的所具备的能力取决于它接收的行为参数. ...
- java8新特性:内存和lambda表达式
1.内存变化 取消了永久区和方法区,取而代之的是MetaSpace元空间,即直接使用物理内存,即电脑内存8G则直接使用8g内存,而不是分配内存.因为内存改变,所以调整性能对应的调整参数也随之改变. 2 ...
- Java8新特性(拉姆达表达式lambda)
一.函数式接口 函数式接口(functional interface 也叫功能性接口,其实是同一个东西).简单来说,函数式接口是只包含一个方法的接口.比如Java标准库中的java.lang.Runn ...
- java8 新特性入门 stream/lambda
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggregate operation),或者大批量数据操作 (b ...
- 乐字节-Java8核心特性实战之Lambda表达式
大家好,小乐又来给大家分享Java8核心特性了,上一篇文章是<乐字节|Java8核心实战-接口默认方法>,这次就来讲Java8核心特征之Lambda表达式. Java8 引入Lambda表 ...
- Java8新特性探索之Stream接口
一.为什么引入Stream流 流是一系列与特定存储机制无关的元素--实际上,流并没有"存储"之说.使用流,无需迭代集合中的元素,就可以从管道提取和操作元素.这些管道通常被组合在一起 ...
随机推荐
- GEKCTF2020-web
GEKCTF [GKCTF2020]CheckIN97 <title>Check_In</title> <?php highlight_file(__FILE__); c ...
- Spring Boot 第一弹,问候一下世界!!!
持续原创输出,点击上方蓝字关注我吧 目录 前言 什么是Spring Boot? 如何搭建一个Spring Boot项目? 第一个程序 Hello World 依赖解读 什么是配置文件? 什么是启动类? ...
- 坚果云+svn实现异地非局域网个人代码版本管理
原理大概是A地的设备作为服务端创建仓库,将仓库传上坚果云,同步到B地,再拉取仓库的代码
- @lookup注解的使用
背景,如果有一个类C,需要用到类B,如果使用@Autowired注解注入B,那么B每次调用都是同一个对象,即使B不是单例的,现在我希望每次调用B都是不一样的,那么实现方案有2个: 方案A : 每次从容 ...
- springboot+websocket实现简单的在线聊天功能
效果如下: java实现逻辑: 1.引入maven依赖 <dependency> <groupId>org.springframework.boot</groupId&g ...
- LVM的简单使用及常用的命令总结
Lvm的简单使用及常用的命令总结 centos7中默认使用的是xfs文件系统,此文件系统的特点,可以另外查找资料,这里说一下对文件系统的扩容: 1.先看一下没扩容之前的分区大小 2.添加一块新磁盘,并 ...
- 在Python中使用OpenCV(CV2)对图像进行边缘检测
转载:https://blog.csdn.net/cumtb2002/article/details/107798767 Modules used: 使用的模块: For this, we will ...
- 【优化】单调队列与dp
笔者大概看了一下单调队列对于DP的优化,故撰此文,望有帮助. (dp还是推式子难啊qwq) 例题1. 题目大意:在n个数的序列中,选择数字,使得其连续不超过k个数,且和最大. 本题的方程相对好推:设d ...
- 使用Jest快照测试api
你知道什么很烦人吗?API不匹配. 有一天,后台开发人员在没有通知前端开发人员的情况下更改了其中一个api."我们认为dateCreated这个名字比created_at更好,"他 ...
- linux 线程挂起恢复
1 //============================================================================ 2 // Name : thread. ...