场景

以调用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,为了方便测试,这里只有addforEach方法。
由于是重写的上面自定义接口的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),指的是代码运行时出现的异常,比如ArrayIndexOutOfBoundsExceptionClassCastException

总结

在JDK源码中,像java.util.ArrayList#forEach一样的函数式形参Consumer#accept的方法声明中,没有声明对应的受检异常,所以传递lambda表达式内部可以抛出不受检异常RuntimeException,但是对于受检异常(如**IOException**)只能在内部捕获该异常
如果函数式形参声明了对应的受检异常,则lambda表达式内部可以抛出对应的受检异常,即不用在内部捕获
函数式编程本质就是重写方法,返回对象实例的过程,既然是重写方法,原方法未声明异常,自然重写的方法就不能声明异常;
Lambda表达式内部是否需要捕获受检异常,实际上与Lambda表达式重写的方法有关

lambda表达式一定要在内部捕获受检异常?的更多相关文章

  1. Lambda 表达式[MSDN]

    Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数.Lambda 表达式对于编写 LINQ 查 ...

  2. Lambda 表达式(C# 编程指南) 微软microsoft官方说明

    Visual Studio 2013 其他版本 Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地 ...

  3. lambda函数、lambda表达式

    C++11 新特性:Lambda 表达式 豆子 2012年5月15日 C++ 10条评论 参考文章:https://blogs.oracle.com/pcarlini/entry/c_1x_tidbi ...

  4. 深入探索Java 8 Lambda表达式

    2014年3月,Java 8发布,Lambda表达式作为一项重要的特性随之而来.或许现在你已经在使用Lambda表达式来书写简洁灵活的代码.比如,你可以使用Lambda表达式和新增的流相关的API,完 ...

  5. Cocos2d-x v3.0 新的事件调度方法 lambda表达式的使用

    欢迎添� Cocos2d-x 交流群: 193411763 转载请注明原文出处:http://blog.csdn.net/u012945598/article/details/24603251 Coc ...

  6. C++11中新特性之:lambda 表达式

    首先摆出Lambda表达式语法 lambda-expression: lambda-introducer lambda-declaratoropt compound-statementlambda-i ...

  7. [Java 8] (5) 使用Lambda表达式进行设计

    使用Lambda表达式进行设计 在前面的几篇文章中,我们已经见识到了Lambda表达式是怎样让代码变的更加紧凑和简洁的. 这一篇文章主要会介绍Lambda表达式怎样改变程序的设计.怎样让程序变的更加轻 ...

  8. Lambda 表达式的示例-来源(MSDN)

    本文演示如何在你的程序中使用 lambda 表达式. 有关 lambda 表达式的概述,请参阅 C++ 中的 Lambda 表达式. 有关 lambda 表达式结构的详细信息,请参阅 Lambda 表 ...

  9. (zz)Lambda 表达式(C# 编程指南)

    https://msdn.microsoft.com/zh-cn/library/bb397687.aspx Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数.通过使用 lambd ...

  10. C++教程之lambda表达式一

    什么是Lambda? C++ 11增加了一个很重要的特性--Lambda表达式.营里(戴维营)的兄弟都对Objective-C很熟悉,很多人多block情有独钟,将各种回调函数.代理通通都用它来实现. ...

随机推荐

  1. vue3 基础-动态组件 & 异步组件

    之前学习的都是父子组件传值的话题, 一句话总结就是, 常规数据通过属性传, dom 结构通过插槽 slot 来传. 而本篇则关注如何通过数据去控制组件的显示问题, 如咱经常用到的页面切换呀, Tab ...

  2. .NET Core 和 .NET 标准类库项目类型有什么区别?

    在 Visual Studio 中,至少可以创建三种不同类型的类库: 类库(.NET Framework) 类库(.NET 标准) 类库 (.NET Core) 虽然第一种是我们多年来一直在使用的,但 ...

  3. 第9.2讲、Tiny Decoder(带 Mask)详解与实战

    自己搭建一个 Tiny Decoder(带 Mask),参考 Transformer Encoder 的结构,并添加 Masked Multi-Head Self-Attention,它是 Decod ...

  4. Nohup 启动程序未指定输出日志,导致磁盘空间被占满的解决方案

    1. 问题原因 当使用 nohup 启动程序时,默认情况下,标准输出(stdout)和标准错误(stderr)都会被重定向到 nohup.out 文件.例如: nohup python my_scri ...

  5. Redis异常 Invalid argument during startup: unknown conf file parameter

    问题提出 设置 redis 过期事件监听时,需将 notify-keyspace-events的值设置为Ex,故去掉了 notify-keyspace-events Ex'之前的注释符.然而,启动re ...

  6. ElasticSearch介绍及单机版安装

    概述 ElasticSearch官网:https://www.elastic.co/cn/elasticsearch GitHub地址:https://github.com/elastic/elast ...

  7. kubernetes主流网络方案Flannel分析

    一.Flannel简单说明 Flannel是kubernetes集群的CNI网络插件之一,实质上是一种overlay网络,flannel支持多种网络转发策略,常用的vxlan.hostgw等. 二.F ...

  8. Linux开放防火墙指定端口

    方法一 开启8011端口 /sbin/iptables -I INPUT -p tcp --dport 8011 -j ACCEPT 保存配置 /etc/rc.d/init.d/iptables sa ...

  9. MKL库求解矩阵特征值、特征向量(LAPACKE_dgeev、dsyev)

    LAPACK(Linear Algebra PACKage)库,是用Fortran语言编写的线性代数计算库,包含线性方程组求解(\(AX=B\)).矩阵分解.矩阵求逆.求矩阵特征值.奇异值等.该库用B ...

  10. dotnet (.Net) Core在不是Web 项目中使用HttpClientFactory正确用法

    在不是web 项目中也不是Api 中使用 HttpClientFactory 先需要添加 Microsoft.Extensions.DependencyInjection.Abstractions M ...