java8异常处理_Java8Stream中的异常处理

Java 8中的Stream与Lambda表达式结合在一起,确实使得开发中的很多常见任务变得更简单。通过级联多个不同的操作符,如map、filter和reduce等,可以在一行代码里面完成很多的任务。那种一行代码搞定一切的愉悦感,着实让人很满意。今天我们来说说Stream中不那么愉悦的部分 - 异常处理。

如果你看一眼Stream中包含的所有方法,你会发现,这些方法都没有声明抛出任何checked异常。再看一眼接口Function、Consumer和Supplier,其中包含的方法也是不抛出checked异常的。关于checked和unchecked异常的讨论由来已久。目前的趋势是尽量使用unchecked异常,但是checked异常也有它的用武之地。当然,这个不是我们今天要讨论的重点。这些方法都不抛出checked异常,也就意味着那些抛出checked异常的方法不能直接使用。这就涉及到了我们今天要讨论的如何处理异常的问题。

为了避免枯燥的讨论,我们来看一个具体的例子。我们有一个接口UserService,其中包含了方法load来根据用户的ID返回对应的User对象。现在我们有一个包含了多个用户ID的List对象。在load方法的实现中,可能出现各种错误。所以load方法声明了会抛出UserLoadException异常。

public interface UserService {

User load(String id) throws UserLoadException;

}

现在我们要实现的是加载多个用户的方法List loadAllUsers(List userIds)。

最直接的实现方式userIds.stream().map(userService::load)是行不通的,编译错误,因为没有处理UserLoadException异常。在继续之前,我们首先要明确的是,处理异常的逻辑是什么。这个看似简单的问题,其实很多时候都被我们忽略了。而这个问题的答案来自于具体的业务逻辑。

如果该方法一共接收到了10个用户ID,其中的2个用户在加载时出现了异常,那我们需要做什么?

第一种做法,我们可以忽略出错的那2个用户,而只返回一个包含了8个User对象的List。这种做法对应的业务逻辑就是尽最大努力的完成任务。

我们只需要把用户ID的Stream映射成Optional的Stream,再进行过滤即可。

public List loadAllUsersBestEffort(final List userIds) {

return userIds.stream().>map(id -> {

try {

return Optional.of(this.userService.load(id));

} catch (UserLoadException e) {

return Optional.empty();

}

}).filter(Optional::isPresent)

.map(Optional::get)

.collect(Collectors.toList());

}

第二种做法,整个加载过程直接失败,抛出异常,不返回任何结果。这种做法对应的业务逻辑就是把整个加载过程看成一个整体,不允许部分成功。

我们只需要把抛出的checked异常封装成unchecked异常,再重新抛出即可。由该方法的调用者来负责处理异常。

public List loadAllUsersFailFast(final List userIds) {

return userIds.stream().map(id -> {

try {

return this.userService.load(id);

} catch (UserLoadException e) {

throw new RuntimeException(e);

}

}).collect(Collectors.toList());

}

第三种做法与第一种做法类似,只不过会把加载时出现的异常也记录下来,并返回给调用者。这样提供给调用者给多的信息和更多的选择。调用者可以选择使用这部分成功的结果,也可以选择直接抛出所产生的异常。

在增加了异常信息之后,方法的返回类型变成了Tuple2, Optional>。基本的实现方式是把用户ID的Stream映射成Tuple2, Optional>类型的Stream之后,再使用reduce操作合并成单一的对象。我们通过Throwable.addSuppressed()方法来把多个异常对象进行合并。

public Tuple2, Optional> loadAllUsersWithException(

final List userIds) {

return userIds.stream().map(id -> {

try {

return Tuple

.of((List) Lists.newArrayList(this.userService.load(id)),

Optional.empty());

} catch (UserLoadException e) {

return Tuple.of((List) Lists.newArrayList(), Optional.of(e));

}

}).reduce(Tuple.of(new ArrayList<>(), Optional.empty()), (r1, r2) -> {

r1._1.addAll(r2._1);

if (r2._2.isPresent()) {

if (r1._2.isPresent()) {

r1._2.get().addSuppressed(r2._2.get());

} else {

return Tuple.of(r1._1, r2._2);

}

}

return r1;

});

}

上面给出了在Stream中进行异常处理的三种常见思路。可以根据业务逻辑的需要进行选择。

rel: https://zhuanlan.zhihu.com/p/30747343

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值