java 8 lambda表达式中的异常处理

简介

java 8中引入了lambda表达式,lambda表达式可以让我们的代码更加简介,业务逻辑更加清晰,但是在lambda表达式中使用的Functional Interface并没有很好的处理异常,因为JDK提供的这些Functional Interface通常都是没有抛出异常的,这意味着需要我们自己手动来处理异常。

因为异常分为Unchecked Exception和checked Exception,我们分别来讨论。

处理Unchecked Exception

Unchecked exception也叫做RuntimeException,出现RuntimeException通常是因为我们的代码有问题。RuntimeException是不需要被捕获的。也就是说如果有RuntimeException,没有捕获也可以通过编译。

我们看一个例子:

List<Integer> integers = Arrays.asList(1,2,3,4,5);
integers.forEach(i -> System.out.println(1 / i));

这个例子是可以编译成功的,但是上面有一个问题,如果list中有一个0的话,就会抛出ArithmeticException。

虽然这个是一个Unchecked Exception,但是我们还是想处理一下:

        integers.forEach(i -> {
try {
System.out.println(1 / i);
} catch (ArithmeticException e) {
System.err.println(
"Arithmetic Exception occured : " + e.getMessage());
}
});

上面的例子我们使用了try,catch来处理异常,简单但是破坏了lambda表达式的最佳实践。代码变得臃肿。

我们将try,catch移到一个wrapper方法中:

    static Consumer<Integer> lambdaWrapper(Consumer<Integer> consumer) {
return i -> {
try {
consumer.accept(i);
} catch (ArithmeticException e) {
System.err.println(
"Arithmetic Exception occured : " + e.getMessage());
}
};
}

则原来的调用变成这样:

integers.forEach(lambdaWrapper(i -> System.out.println(1 / i)));

但是上面的wrapper固定了捕获ArithmeticException,我们再将其改编成一个更通用的类:

    static <T, E extends Exception> Consumer<T>
consumerWrapperWithExceptionClass(Consumer<T> consumer, Class<E> clazz) { return i -> {
try {
consumer.accept(i);
} catch (Exception ex) {
try {
E exCast = clazz.cast(ex);
System.err.println(
"Exception occured : " + exCast.getMessage());
} catch (ClassCastException ccEx) {
throw ex;
}
}
};
}

上面的类传入一个class,并将其cast到异常,如果能cast,则处理,否则抛出异常。

这样处理之后,我们这样调用:

integers.forEach(
consumerWrapperWithExceptionClass(
i -> System.out.println(1 / i),
ArithmeticException.class));

处理checked Exception

checked Exception是必须要处理的异常,我们还是看个例子:

    static void throwIOException(Integer integer) throws IOException {
}
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
integers.forEach(i -> throwIOException(i));

上面我们定义了一个方法抛出IOException,这是一个checked Exception,需要被处理,所以在下面的forEach中,程序会编译失败,因为没有处理相应的异常。

最简单的办法就是try,catch住,如下所示:

        integers.forEach(i -> {
try {
throwIOException(i);
} catch (IOException e) {
throw new RuntimeException(e);
}
});

当然,这样的做法的坏处我们在上面已经讲过了,同样的,我们可以定义一个新的wrapper方法:

    static <T> Consumer<T> consumerWrapper(
ThrowingConsumer<T, Exception> throwingConsumer) { return i -> {
try {
throwingConsumer.accept(i);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
};
}

我们这样调用:

integers.forEach(consumerWrapper(i -> throwIOException(i)));

我们也可以封装一下异常:

static <T, E extends Exception> Consumer<T> consumerWrapperWithExceptionClass(
ThrowingConsumer<T, E> throwingConsumer, Class<E> exceptionClass) { return i -> {
try {
throwingConsumer.accept(i);
} catch (Exception ex) {
try {
E exCast = exceptionClass.cast(ex);
System.err.println(
"Exception occured : " + exCast.getMessage());
} catch (ClassCastException ccEx) {
throw new RuntimeException(ex);
}
}
};
}

然后这样调用:

integers.forEach(consumerWrapperWithExceptionClass(
i -> throwIOException(i), IOException.class));

总结

本文介绍了如何在lambda表达式中处理checked和unchecked异常,希望能给大家一些帮助。

本文的例子https://github.com/ddean2009/learn-java-streams/tree/master/lambda-exception

欢迎关注我的公众号:程序那些事,更多精彩等着您!

更多内容请访问 www.flydean.com

java 8 lambda表达式中的异常处理的更多相关文章

  1. Java 8 Lambda表达式

    Java 8 Lambda表达式探险 http://www.cnblogs.com/feichexia/archive/2012/11/15/Java8_LambdaExpression.html 为 ...

  2. 深入浅出 Java 8 Lambda 表达式

    摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系 OneAPM 工程师编译整理. Java 是一流的面向对象语言,除了部分简 ...

  3. Java 8 Lambda表达式10个示例【存】

    PS:不能完全参考文章的代码,请参考这个文件http://files.cnblogs.com/files/AIThink/Test01.zip 在Java 8之前,如果想将行为传入函数,仅有的选择就是 ...

  4. Java SE 8 for the Really Impatient读书笔记——Java 8 Lambda表达式

    1. lambda表达式的语法 lambda表达式是一种没有名字的函数,它拥有函数体和参数. lambda表达式的语法十分简单:参数->主体.通过->来分离参数和主体. 1.1 参数 la ...

  5. Java 8 Lambda 表达式

    Lambda 是啥玩意 简单来说,Lambda 就是一个匿名的方法,就这样,没啥特别的.它采用一种非常简洁的方式来定义方法.当你想传递可复用的方法片段时,匿名方法非常有用.例如,将一个方法传递给另外一 ...

  6. java 8 Lambda表达式(翻译自Stackoverflow)

    (原文链接)Lambda只能作用于一个只有一个抽象方法的函数式接口(Function Interface),不过函数式接口可以有任意数量default或static修饰的方法(因此,它们有时也被当做单 ...

  7. Java 8 Lambda 表达式(一)

    Java 8 新特性 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). 使用 Lambda 表 ...

  8. 聊聊Java 8 Lambda 表达式

      早在2014年oracle发布了jdk 8,在里面增加了lambda模块.于是java程序员们又多了一种新的编程方式:函数式编程,也就是lambda表达式.我自己用lambda表达式也差不多快4年 ...

  9. Java 8 lambda表达式示例

    例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runna ...

随机推荐

  1. NKOJ3772 看电影

    问题描述 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l<=r<= ...

  2. Mac电脑之间的文件共享 - 偏门

    文件共享是工作中经常要进行的. Mac用户之间可以通过AirDrop来共享文件.AirDrop要借助无线网络,而很多人都是将Mac做成个人热点供手机等Wifi连接,AirDrop时必须断开热点,不方便 ...

  3. IDEA 正式版终于支持中文版和 JDK 直接下载了(太方便了)附介绍视频

    IDEA 2020.1 经过了漫长的打磨终于发布正式版了,而这次的版本不止直接支持 Java 14,还带来了两个重量级的功能,官方中文版支持和 JDK 直接下载. 在之前的开发中,当我们需要下载 JD ...

  4. 微信小程序动态修改页面标题setNavigationBarTitle

    微信小程序是可以动态修改页面标题的. 首先我们来看看静态是怎么实现的 在对应页面的json文件里面加入下面代码就可以实现了 { "navigationBarTitleText": ...

  5. java文件中字母出现的次数和百分比

    主要是文件的读写.先在代码中导入文件.一行一行的进行数据的读入,通过“  ”空格对读入的信息进行分割,存入到数组里之后对于每一个单词的每一个字母进行区分存入相应的字母数组里.最后统计总的字母个数.应用 ...

  6. VSCode——自定义VSCode背景图片

    本文转载自https://blog.csdn.net/yukinoai/article/details/84564949 1.以管理员身份运行VS Code,安装background插件 2.打开se ...

  7. go 切片重组

    我们已经知道切片创建的时候通常比相关数组小,例如: slice1 := make([]type, start_length, capacity) 其中 start_length 作为切片初始长度而 c ...

  8. Tcl编程第三天,数学运算

    1.tcl语言没有自己的数学计算,如果想要使用数学公式,必须得用C语言的库.使用方法如下. #!/usr/bin/tclsh set value [expr 8/5] puts $value set ...

  9. 安卓开发学习日记 DAY5——监听事件onClick的实现方法

    今天主要学习了监听事件的是实现方法,就是说,做了某些动作后,怎么监听这个动作并作出相应反应. 方法主要有三种: 1.匿名内部类的方法 2.独立类的方法 3.类似实现接口的方法 以下分别分析: 1.匿名 ...

  10. Vue-router 第10节 路由中的钩子

    Vue-router 第10节 路由中的钩子 [TOC] 第10节 路由中的钩子 我们知道一个组件从进入到销毁有很多的钩子函数,同样在路由中也设置了钩子函数.路由的钩子选项可以写在路由配置文件中,也可 ...