lambda表达式一定要在内部捕获受检异常?
场景
以调用java.util.ArrayList#forEach
方法为例,用不同的lambda表达式重写该Consumer
接口。
RuntimeException
list
中有两个元素,调用forEach
遍历,使用lambda重写Consumer
接口,抛出不受检异常RuntimeException
。
下面代码编译通过。
@Test
public void listForeachRuntimeExceptionTest() {
final List<Integer> list = new ArrayList<>(2);
list.add(1);
list.add(2);
list.forEach(
i -> {
System.out.println(i);
throw new RuntimeException();
});
}
受检异常
lambda内部抛出IOException
对上面的代码做一点修改,修改抛出的异常为IOException
:
@Test
public void listForeachCheckedExceptionTest() {
final List<Integer> list = new ArrayList<>(2);
list.add(1);
list.add(2);
list.forEach(
i -> {
System.out.println(i);
throw new IOException();
});
}
如此编译会报错,因为IOException
是受检异常,需要被捕获或抛到外层处理。
外层方法抛出该异常
将代码修改为在外层方法抛出该异常,编译也是会报错的,如下代码:
@Test
public void listForeachCheckedExceptionTest() throws IOException {
final List<Integer> list = new ArrayList<>(2);
list.add(1);
list.add(2);
list.forEach(
i -> {
System.out.println(i);
throw new IOException();
});
}
这是由于java.util.function.Consumer#accept
方法签名没有声明抛出IOException
,并且java.util.ArrayList#forEach
方法也没有对异常的处理。所以导致lambda表达式重写后的方法签名也是没有声明有异常抛出的。
java.util.function.Consumer#accept
源码
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
......
}
内部捕获
所以要想编译不报错,上面代码只能在lambda内部捕获该异常:
@Test
public void listForeachCheckedExceptionTest() {
final List<Integer> list = new ArrayList<>(2);
list.add(1);
list.add(2);
list.forEach(
i -> {
System.out.println(i);
try {
throw new IOException();
} catch (IOException e) {
e.printStackTrace();
}
});
}
小结
由于java.util.ArrayList#forEach
的函数式形参java.util.function.Consumer
类,它的accept
方法签名没有声明抛出IOException
,所以内部的受检异常IOException
必须捕获。
自定义函数式接口(声明受检异常)
难道所有的lambda表达式,遇到受检异常就必须都在内部捕获吗?
当然不是。
受检异常函数式接口
为了方便后续测试,自定义一个接口,只有一个方法action
,方法签名带有受检异常(IOException
)。
/**
* @author https://www.cnblogs.com/theRhyme/
*/
@FunctionalInterface
public interface CheckedExceptionAction<T> {
void action(T t) throws IOException;
}
自定义forEach接口声明异常
这里自定义一个接口,声明的是抛出受检异常IOException
。
/**
* @author https://www.cnblogs.com/theRhyme/
*/
public interface MyIterable<T> {
void forEach(CheckedExceptionAction<? super T> action) throws IOException;
}
自定义forEach实现
自定义MyList
,为了方便测试,这里只有add
和forEach
方法。
由于是重写的上面自定义接口的forEach
方法,方法声明自然也有throws IOException
,这里的声明异常是为了将CheckedExceptionAction#action
产生的异常抛出去,当然也可以在自定义的forEach
中捕获。
/**
* @author https://www.cnblogs.com/theRhyme/
*/
public class MyList<T> implements RandomAccess, MyIterable<T> {
private List<T> list;
public MyList() {
list = new ArrayList<>();
}
public boolean add(T t) {
return list.add(t);
}
@Override
public void forEach(CheckedExceptionAction<? super T> action) throws IOException {
for (T t : list) {
action.action(t);
}
}
}
测试
添加两个元素,并且在forEach
中抛出的受检异常IOException
,代码编译通过。
所以当forEach
中的函数式形参CheckedExceptionAction
声明了对应的受检异常,则lambda表达式内部不用捕获该异常。
/**
* @author https://www.cnblogs.com/theRhyme/
*/
public class Main {
public static void main(String[] args) throws IOException {
final MyList<Integer> myList = new MyList<>();
myList.add(1);
myList.add(2);
myList.forEach(i -> {
System.out.println(i);
throw new IOException();
});
}
}
受检异常与不受检异常
受检异常(checkedException),又叫做编译时异常,指的是代码编译期间,必须由编程人员手动处理(try-catch捕获或者throws抛出)的异常,否则代码报错,例如IOException
。
不受检异常(uncheckedException),又叫运行时异常(RuntimeException),指的是代码运行时出现的异常,比如ArrayIndexOutOfBoundsException
,ClassCastException
。
总结
在JDK源码中,像java.util.ArrayList#forEach
一样的函数式形参Consumer#accept
的方法声明中,没有声明对应的受检异常,所以传递lambda表达式内部可以抛出不受检异常RuntimeException,但是对于受检异常(如**IOException**
)只能在内部捕获该异常;
如果函数式形参声明了对应的受检异常,则lambda表达式内部可以抛出对应的受检异常,即不用在内部捕获;
函数式编程本质就是重写方法,返回对象实例的过程,既然是重写方法,原方法未声明异常,自然重写的方法就不能声明异常;
Lambda表达式内部是否需要捕获受检异常,实际上与Lambda表达式重写的方法有关。
lambda表达式一定要在内部捕获受检异常?的更多相关文章
- Lambda 表达式[MSDN]
Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数.Lambda 表达式对于编写 LINQ 查 ...
- Lambda 表达式(C# 编程指南) 微软microsoft官方说明
Visual Studio 2013 其他版本 Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地 ...
- lambda函数、lambda表达式
C++11 新特性:Lambda 表达式 豆子 2012年5月15日 C++ 10条评论 参考文章:https://blogs.oracle.com/pcarlini/entry/c_1x_tidbi ...
- 深入探索Java 8 Lambda表达式
2014年3月,Java 8发布,Lambda表达式作为一项重要的特性随之而来.或许现在你已经在使用Lambda表达式来书写简洁灵活的代码.比如,你可以使用Lambda表达式和新增的流相关的API,完 ...
- Cocos2d-x v3.0 新的事件调度方法 lambda表达式的使用
欢迎添� Cocos2d-x 交流群: 193411763 转载请注明原文出处:http://blog.csdn.net/u012945598/article/details/24603251 Coc ...
- C++11中新特性之:lambda 表达式
首先摆出Lambda表达式语法 lambda-expression: lambda-introducer lambda-declaratoropt compound-statementlambda-i ...
- [Java 8] (5) 使用Lambda表达式进行设计
使用Lambda表达式进行设计 在前面的几篇文章中,我们已经见识到了Lambda表达式是怎样让代码变的更加紧凑和简洁的. 这一篇文章主要会介绍Lambda表达式怎样改变程序的设计.怎样让程序变的更加轻 ...
- Lambda 表达式的示例-来源(MSDN)
本文演示如何在你的程序中使用 lambda 表达式. 有关 lambda 表达式的概述,请参阅 C++ 中的 Lambda 表达式. 有关 lambda 表达式结构的详细信息,请参阅 Lambda 表 ...
- (zz)Lambda 表达式(C# 编程指南)
https://msdn.microsoft.com/zh-cn/library/bb397687.aspx Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数.通过使用 lambd ...
- C++教程之lambda表达式一
什么是Lambda? C++ 11增加了一个很重要的特性--Lambda表达式.营里(戴维营)的兄弟都对Objective-C很熟悉,很多人多block情有独钟,将各种回调函数.代理通通都用它来实现. ...
随机推荐
- vue3 基础-动态组件 & 异步组件
之前学习的都是父子组件传值的话题, 一句话总结就是, 常规数据通过属性传, dom 结构通过插槽 slot 来传. 而本篇则关注如何通过数据去控制组件的显示问题, 如咱经常用到的页面切换呀, Tab ...
- .NET Core 和 .NET 标准类库项目类型有什么区别?
在 Visual Studio 中,至少可以创建三种不同类型的类库: 类库(.NET Framework) 类库(.NET 标准) 类库 (.NET Core) 虽然第一种是我们多年来一直在使用的,但 ...
- 第9.2讲、Tiny Decoder(带 Mask)详解与实战
自己搭建一个 Tiny Decoder(带 Mask),参考 Transformer Encoder 的结构,并添加 Masked Multi-Head Self-Attention,它是 Decod ...
- Nohup 启动程序未指定输出日志,导致磁盘空间被占满的解决方案
1. 问题原因 当使用 nohup 启动程序时,默认情况下,标准输出(stdout)和标准错误(stderr)都会被重定向到 nohup.out 文件.例如: nohup python my_scri ...
- Redis异常 Invalid argument during startup: unknown conf file parameter
问题提出 设置 redis 过期事件监听时,需将 notify-keyspace-events的值设置为Ex,故去掉了 notify-keyspace-events Ex'之前的注释符.然而,启动re ...
- ElasticSearch介绍及单机版安装
概述 ElasticSearch官网:https://www.elastic.co/cn/elasticsearch GitHub地址:https://github.com/elastic/elast ...
- kubernetes主流网络方案Flannel分析
一.Flannel简单说明 Flannel是kubernetes集群的CNI网络插件之一,实质上是一种overlay网络,flannel支持多种网络转发策略,常用的vxlan.hostgw等. 二.F ...
- Linux开放防火墙指定端口
方法一 开启8011端口 /sbin/iptables -I INPUT -p tcp --dport 8011 -j ACCEPT 保存配置 /etc/rc.d/init.d/iptables sa ...
- MKL库求解矩阵特征值、特征向量(LAPACKE_dgeev、dsyev)
LAPACK(Linear Algebra PACKage)库,是用Fortran语言编写的线性代数计算库,包含线性方程组求解(\(AX=B\)).矩阵分解.矩阵求逆.求矩阵特征值.奇异值等.该库用B ...
- dotnet (.Net) Core在不是Web 项目中使用HttpClientFactory正确用法
在不是web 项目中也不是Api 中使用 HttpClientFactory 先需要添加 Microsoft.Extensions.DependencyInjection.Abstractions M ...