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情有独钟,将各种回调函数.代理通通都用它来实现. ...
随机推荐
- 如何在 Linux 上检查开放的端口并关闭不需要的端口
检查服务器开放端口并关闭不必要的端口是网络安全管理中的关键环节,开放端口如同服务器的"窗口",若其中存在未被利用或未受保护的端口,就如同为潜在的攻击者敞开了大门,他们可能会利用这些 ...
- ansible实战-2023
环境信息:cat /etc/ansible/hosts[webserver]192.168.31.18 ansible_ssh_user=root ansible_ssh_pass=123456 ht ...
- Go 层级菜单树转 json 处理
本篇是一个补充知识点, 目的是为了下篇的后台管理系统中, 菜单权限的接口进行铺垫一下. 同时也是做个笔记, 因为在很多地方都会用这种 "树结构" 来实现很多权限, 层级, 菜单的处 ...
- OSS 上传和删除图片 Python SDK
最近在搞一些全栈的小项目, 涉及到图片的上传, 删改等操作, 想着还是用这个云服务器来整一波, 阿里云的 OSS对象存储, 40G 1年9块钱, 值得拥有! 前提 购买了阿里云 OSS 服务 创建了 ...
- 网络编程:epoll
原理 select 的几个缺点: 1)每次调用select,都需要把fd集合从用户空间拷贝到内核空间,这个开销在fd很多时会很大 2)每次调用select都需要在内核遍历传递进来的所有fd,这个开销在 ...
- 定制Django的Tag和Filter(一)
1.在 app 目录下创建 templatetags 目录(目录名只能是 templatetags). 如: app/ __init__.py models.py templatetags/ __in ...
- Windows平台调试器原理与编写03.单步
调试器原理与编写03.单步-C/C++基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net 单步 TF - 置位(置1 复位就是置0) 单步步入 -- 遇到call便入 单步步过 ...
- 密码哈希:Bcrypt的魔法与盐值的秘密
title: 密码哈希:Bcrypt的魔法与盐值的秘密 date: 2025/06/01 16:41:37 updated: 2025/06/01 16:41:37 author: cmdragon ...
- Dispatch PDI v2.0.4即将发布,历经1000+用户装机验证,稳定版震撼来袭!
Dispatch PDI V2.0.4版本,即将登场! 亲爱的用户们: 在数据调度领域的探索之路上,我们始终致力于为大家提供更强大.更高效的工具.今天,我们怀着激动的心情宣布,Dispatch PDI ...
- Vue鼠标与键盘事件触发汇总
Vue鼠标与键盘事件触发汇总 一.鼠标事件 1.悬浮事件 @mouseenter :进入 @mouseover:在 @mousemove:移动 @mouseout:移出 @mouseleave:离开 ...