lambda表达式有利于我们写出非常简洁的代码,但是Java8中lambda表达式无法抛出受检异常,这样会使我们在lambda表达式中使用抛出Checked Exception的方法时,会出现一些问题,接下来我们就来探讨一下这个问题。
首先看一下出现问题的代码:
// 获取文件里的文本内容 public Stream<String> readFiles(String path) throws IOException { return Files.lines(Paths.get(getClass().getClassLoader().getResource(path).getPath())); public void test3() { Stream.of("a.txt") .flatMap(this::readFiles) // 这里会出现编译异常 .forEach(System.out::println); 到这里,我们就会发现一个编译问题: Error:(64, 26) java: 方法引用中抛出的类型java.io.IOException不兼容 这是由于flatMap()支持的函数式接口 @FunctionalInterface public interface Function<T, R> { * 并不支持抛出异常(没有申明throw) * Applies this function to the given argument. * @param t the function argument * @return the function result R apply(T t); 二 问题处理这种受检异常时,我们可以先捕获,然后包装并抛出一个非受检异常。 方法一public void test1() { Stream.of("a.txt") .flatMap(path -> { try { return readFiles(path); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(); .forEach(System.out::println); 这样可以解决问题,但是会损失lambda的简洁性。 方法二出现编译时异常的主要问题还是由于Function的apply方法不支持抛出异常,我们可以定义自己的函数式接口: @FunctionalInterface public interface ThrowingFunction<T,R,E extends Throwable> { R apply(T arg) throws E; 然后在使用一个包装器 static <T, R, E extends Exception> Function<T, R> unchecked(ThrowingFunction<T, R, E> f) { return t -> { try { return apply(t); } catch (final Throwable e) { throw new WrappedException(e); 然后就可以这样使用了: @Test public void test5() { Stream.of("a.txt") .flatMap(unchecked(this::readFiles)) .forEach(System.out::println); 这样的话就保证了代码的间接性,但是我们又不得不定义对应的函数式接口和对应的包装器。对于这个问题,我们可以利用一个开源库ThrowingFunction来解决。方法如下: 1 添加依赖 <dependency> <groupId>pl.touk</groupId> <artifactId>throwing-function</artifactId> <version>1.3</version> </dependency> @Test public void test4() { Stream.of("a.txt") .flatMap(ThrowingFunction.unchecked(this::readFiles)) .forEach(System.out::println); 到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!
// 获取文件里的文本内容 public Stream<String> readFiles(String path) throws IOException { return Files.lines(Paths.get(getClass().getClassLoader().getResource(path).getPath())); public void test3() { Stream.of("a.txt") .flatMap(this::readFiles) // 这里会出现编译异常 .forEach(System.out::println); 到这里,我们就会发现一个编译问题: Error:(64, 26) java: 方法引用中抛出的类型java.io.IOException不兼容 这是由于flatMap()支持的函数式接口
到这里,我们就会发现一个编译问题:
Error:(64, 26) java: 方法引用中抛出的类型java.io.IOException不兼容
这是由于flatMap()支持的函数式接口
flatMap()
@FunctionalInterface public interface Function<T, R> { * 并不支持抛出异常(没有申明throw) * Applies this function to the given argument. * @param t the function argument * @return the function result R apply(T t); 二 问题处理这种受检异常时,我们可以先捕获,然后包装并抛出一个非受检异常。 方法一public void test1() { Stream.of("a.txt") .flatMap(path -> { try { return readFiles(path); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(); .forEach(System.out::println); 这样可以解决问题,但是会损失lambda的简洁性。 方法二出现编译时异常的主要问题还是由于Function的apply方法不支持抛出异常,我们可以定义自己的函数式接口: @FunctionalInterface public interface ThrowingFunction<T,R,E extends Throwable> { R apply(T arg) throws E; 然后在使用一个包装器 static <T, R, E extends Exception> Function<T, R> unchecked(ThrowingFunction<T, R, E> f) { return t -> { try { return apply(t); } catch (final Throwable e) { throw new WrappedException(e); 然后就可以这样使用了: @Test public void test5() { Stream.of("a.txt") .flatMap(unchecked(this::readFiles)) .forEach(System.out::println); 这样的话就保证了代码的间接性,但是我们又不得不定义对应的函数式接口和对应的包装器。对于这个问题,我们可以利用一个开源库ThrowingFunction来解决。方法如下: 1 添加依赖 <dependency> <groupId>pl.touk</groupId> <artifactId>throwing-function</artifactId> <version>1.3</version> </dependency> @Test public void test4() { Stream.of("a.txt") .flatMap(ThrowingFunction.unchecked(this::readFiles)) .forEach(System.out::println); 到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!
@FunctionalInterface public interface Function<T, R> { * 并不支持抛出异常(没有申明throw) * Applies this function to the given argument. * @param t the function argument * @return the function result R apply(T t);
二 问题处理这种受检异常时,我们可以先捕获,然后包装并抛出一个非受检异常。 方法一public void test1() { Stream.of("a.txt") .flatMap(path -> { try { return readFiles(path); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(); .forEach(System.out::println); 这样可以解决问题,但是会损失lambda的简洁性。 方法二出现编译时异常的主要问题还是由于Function的apply方法不支持抛出异常,我们可以定义自己的函数式接口: @FunctionalInterface public interface ThrowingFunction<T,R,E extends Throwable> { R apply(T arg) throws E; 然后在使用一个包装器 static <T, R, E extends Exception> Function<T, R> unchecked(ThrowingFunction<T, R, E> f) { return t -> { try { return apply(t); } catch (final Throwable e) { throw new WrappedException(e); 然后就可以这样使用了: @Test public void test5() { Stream.of("a.txt") .flatMap(unchecked(this::readFiles)) .forEach(System.out::println); 这样的话就保证了代码的间接性,但是我们又不得不定义对应的函数式接口和对应的包装器。对于这个问题,我们可以利用一个开源库ThrowingFunction来解决。方法如下: 1 添加依赖 <dependency> <groupId>pl.touk</groupId> <artifactId>throwing-function</artifactId> <version>1.3</version> </dependency> @Test public void test4() { Stream.of("a.txt") .flatMap(ThrowingFunction.unchecked(this::readFiles)) .forEach(System.out::println); 到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!
处理这种受检异常时,我们可以先捕获,然后包装并抛出一个非受检异常。
public void test1() { Stream.of("a.txt") .flatMap(path -> { try { return readFiles(path); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(); .forEach(System.out::println); 这样可以解决问题,但是会损失lambda的简洁性。 方法二出现编译时异常的主要问题还是由于Function的apply方法不支持抛出异常,我们可以定义自己的函数式接口: @FunctionalInterface public interface ThrowingFunction<T,R,E extends Throwable> { R apply(T arg) throws E; 然后在使用一个包装器 static <T, R, E extends Exception> Function<T, R> unchecked(ThrowingFunction<T, R, E> f) { return t -> { try { return apply(t); } catch (final Throwable e) { throw new WrappedException(e); 然后就可以这样使用了: @Test public void test5() { Stream.of("a.txt") .flatMap(unchecked(this::readFiles)) .forEach(System.out::println); 这样的话就保证了代码的间接性,但是我们又不得不定义对应的函数式接口和对应的包装器。对于这个问题,我们可以利用一个开源库ThrowingFunction来解决。方法如下: 1 添加依赖 <dependency> <groupId>pl.touk</groupId> <artifactId>throwing-function</artifactId> <version>1.3</version> </dependency> @Test public void test4() { Stream.of("a.txt") .flatMap(ThrowingFunction.unchecked(this::readFiles)) .forEach(System.out::println); 到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!
public void test1() { Stream.of("a.txt") .flatMap(path -> { try { return readFiles(path); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(); .forEach(System.out::println); 这样可以解决问题,但是会损失lambda的简洁性。
这样可以解决问题,但是会损失lambda的简洁性。
方法二出现编译时异常的主要问题还是由于Function的apply方法不支持抛出异常,我们可以定义自己的函数式接口: @FunctionalInterface public interface ThrowingFunction<T,R,E extends Throwable> { R apply(T arg) throws E; 然后在使用一个包装器 static <T, R, E extends Exception> Function<T, R> unchecked(ThrowingFunction<T, R, E> f) { return t -> { try { return apply(t); } catch (final Throwable e) { throw new WrappedException(e); 然后就可以这样使用了: @Test public void test5() { Stream.of("a.txt") .flatMap(unchecked(this::readFiles)) .forEach(System.out::println); 这样的话就保证了代码的间接性,但是我们又不得不定义对应的函数式接口和对应的包装器。对于这个问题,我们可以利用一个开源库ThrowingFunction来解决。方法如下: 1 添加依赖 <dependency> <groupId>pl.touk</groupId> <artifactId>throwing-function</artifactId> <version>1.3</version> </dependency> @Test public void test4() { Stream.of("a.txt") .flatMap(ThrowingFunction.unchecked(this::readFiles)) .forEach(System.out::println); 到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!
出现编译时异常的主要问题还是由于Function的apply方法不支持抛出异常,我们可以定义自己的函数式接口:
@FunctionalInterface public interface ThrowingFunction<T,R,E extends Throwable> { R apply(T arg) throws E; 然后在使用一个包装器 static <T, R, E extends Exception> Function<T, R> unchecked(ThrowingFunction<T, R, E> f) { return t -> { try { return apply(t); } catch (final Throwable e) { throw new WrappedException(e); 然后就可以这样使用了: @Test public void test5() { Stream.of("a.txt") .flatMap(unchecked(this::readFiles)) .forEach(System.out::println); 这样的话就保证了代码的间接性,但是我们又不得不定义对应的函数式接口和对应的包装器。对于这个问题,我们可以利用一个开源库ThrowingFunction来解决。方法如下: 1 添加依赖 <dependency> <groupId>pl.touk</groupId> <artifactId>throwing-function</artifactId> <version>1.3</version> </dependency> @Test public void test4() { Stream.of("a.txt") .flatMap(ThrowingFunction.unchecked(this::readFiles)) .forEach(System.out::println); 到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!
然后在使用一个包装器
static <T, R, E extends Exception> Function<T, R> unchecked(ThrowingFunction<T, R, E> f) { return t -> { try { return apply(t); } catch (final Throwable e) { throw new WrappedException(e); 然后就可以这样使用了: @Test public void test5() { Stream.of("a.txt") .flatMap(unchecked(this::readFiles)) .forEach(System.out::println); 这样的话就保证了代码的间接性,但是我们又不得不定义对应的函数式接口和对应的包装器。对于这个问题,我们可以利用一个开源库ThrowingFunction来解决。方法如下: 1 添加依赖 <dependency> <groupId>pl.touk</groupId> <artifactId>throwing-function</artifactId> <version>1.3</version> </dependency> @Test public void test4() { Stream.of("a.txt") .flatMap(ThrowingFunction.unchecked(this::readFiles)) .forEach(System.out::println); 到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!
然后就可以这样使用了:
@Test public void test5() { Stream.of("a.txt") .flatMap(unchecked(this::readFiles)) .forEach(System.out::println); 这样的话就保证了代码的间接性,但是我们又不得不定义对应的函数式接口和对应的包装器。对于这个问题,我们可以利用一个开源库ThrowingFunction来解决。方法如下: 1 添加依赖 <dependency> <groupId>pl.touk</groupId> <artifactId>throwing-function</artifactId> <version>1.3</version> </dependency> @Test public void test4() { Stream.of("a.txt") .flatMap(ThrowingFunction.unchecked(this::readFiles)) .forEach(System.out::println); 到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!
这样的话就保证了代码的间接性,但是我们又不得不定义对应的函数式接口和对应的包装器。对于这个问题,我们可以利用一个开源库ThrowingFunction来解决。方法如下:
ThrowingFunction
1 添加依赖
<dependency> <groupId>pl.touk</groupId> <artifactId>throwing-function</artifactId> <version>1.3</version> </dependency>
@Test public void test4() { Stream.of("a.txt") .flatMap(ThrowingFunction.unchecked(this::readFiles)) .forEach(System.out::println); 到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!
到此为止,我们可以ThrowingFunction很好的解决这种检测异常问题!