如果你在工作中经常使用lambda,那么你一定遇到过对已在使用lambda中处理异常的头疼问题,那么这篇文章就可以帮你优雅的处理lambda中遇到的异常处理问题。如果你还没有开始使用java8的lambda,作者劝你尽快加入,会发现函数式编程的很多乐趣,会让你的代码非常优雅,更加惊艳哦!
public static void main(String[] args) {
findClass(Collections.singletonList("hello"));
}
public static List<Class> findClass(List<String> classNameList) {
return classNameList.stream().map(className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}).collect(Collectors.toList());
}
在上面这段程序中,你会发现由于lambda表达式的机制,你无法将这个uncheck exception去抛给调用方必须自己处理这个异常,并且会让代码现在很臃肿,没有函数式编程的优雅。
这个问题在 stackoverflow上面也是有人很早就提出过——>stackoverflow链接
里面比较好的解答就是巧妙的解决的了这个问题
public final class LambdaExceptionUtil {
@FunctionalInterface
public interface ConsumerWithExceptions<T, E extends Exception> {
void accept(T t) throws E;
}
@FunctionalInterface
public interface BiConsumerWithExceptions<T, U, E extends Exception> {
void accept(T t, U u) throws E;
}
@FunctionalInterface
public interface FunctionWithExceptions<T, R, E extends Exception> {
R apply(T t) throws E;
}
@FunctionalInterface
public interface SupplierWithExceptions<T, E extends Exception> {
T get() throws E;
}
@FunctionalInterface
public interface RunnableWithExceptions<E extends Exception> {
void run() throws E;
}
/**
* .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println));
*/
public static <T, E extends Exception> Consumer<T> rethrowConsumer(ConsumerWithExceptions<T, E> consumer) throws E {
return t -> {
try {
consumer.accept(t);
} catch (Exception exception) {
throwAsUnchecked(exception);
}
};
}
public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumerWithExceptions<T, U, E> biConsumer) throws E {
return (t, u) -> {
try {
biConsumer.accept(t, u);
} catch (Exception exception) {
throwAsUnchecked(exception);
}
};
}
/**
* .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName))
*/
public static <T, R, E extends Exception> Function<T, R> rethrowFunction(FunctionWithExceptions<T, R, E> function) throws E {
return t -> {
try {
return function.apply(t);
} catch (Exception exception) {
throwAsUnchecked(exception);
return null;
}
};
}
/**
* rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
*/
public static <T, E extends Exception> Supplier<T> rethrowSupplier(SupplierWithExceptions<T, E> function) throws E {
return () -> {
try {
return function.get();
} catch (Exception exception) {
throwAsUnchecked(exception);
return null;
}
};
}
/**
* uncheck(() -> Class.forName("xxx"));
*/
public static void uncheck(RunnableWithExceptions t) {
try {
t.run();
} catch (Exception exception) {
throwAsUnchecked(exception);
}
}
/**
* uncheck(() -> Class.forName("xxx"));
*/
public static <R, E extends Exception> R uncheck(SupplierWithExceptions<R, E> supplier) {
try {
return supplier.get();
} catch (Exception exception) {
throwAsUnchecked(exception);
return null;
}
}
/**
* uncheck(Class::forName, "xxx");
*/
public static <T, R, E extends Exception> R uncheck(FunctionWithExceptions<T, R, E> function, T t) {
try {
return function.apply(t);
} catch (Exception exception) {
throwAsUnchecked(exception);
return null;
}
}
@SuppressWarnings("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E {
throw (E) exception;
}
}
那么我用LambdaExceptionUtil处理之前的程序
我们发现他将这个异常可以抛出给调用方使用了,这样就完美的解决了上面的问题,也让我们的代码很优雅了。