Java 以功能方式处理异常的更好方法
当在Java8中使用FP习惯用法时,异常(尤其是检查过的异常)会严重中断程序逻辑流。以下是一个任意示例:Java 以功能方式处理异常的更好方法,java,java-8,java-stream,Java,Java 8,Java Stream,当在Java8中使用FP习惯用法时,异常(尤其是检查过的异常)会严重中断程序逻辑流。以下是一个任意示例: String s1 = "oeu", s2 = "2"; Stream.of(s1, s2).forEach(s -> System.out.println(Optional.of(s).map(Integer::parseInt).get())); 当不可解析字符串出现异常时,上述代码将中断。但是假设我只想用一个默认值替换它,就像我可以用Optional一样: Strea
String s1 = "oeu", s2 = "2";
Stream.of(s1, s2).forEach(s ->
System.out.println(Optional.of(s).map(Integer::parseInt).get()));
当不可解析字符串出现异常时,上述代码将中断。但是假设我只想用一个默认值替换它,就像我可以用Optional
一样:
Stream.of(s1, s2).forEach(s ->
System.out.println(Optional.of(s)
.map(Integer::parseInt)
.orElse(-1)));
当然,这仍然失败,因为Optional
只处理null
s。我想要的东西如下:
Stream.of(s1, s2).forEach(s ->
System.out.println(
Exceptional.of(s)
.map(Integer::parseInt)
.handle(NumberFormatException.class, swallow())
.orElse(-1)));
注意:这是一个自我回答的问题。下面给出的是
例外类的完整代码。它有一个相当大的API,它是Optional
API的纯扩展,因此它可以作为任何现有代码中的替代品,但它不是finalOptional
类的子类型。该类可以被视为与monad具有相同的关系,就像Optional
与Maybe
monad一样:它从中汲取了灵感,但适应了Java习惯用法(例如实际抛出异常,甚至来自非终端操作)
以下是本课程遵循的一些关键指导原则:
- 与一元方法相反,它不忽略Java的异常机制
- 相反,它减轻了异常和高阶函数之间的阻抗失配
- 异常处理不是静态类型安全的(由于鬼鬼祟祟的抛出),但在运行时总是安全的(除非显式请求,否则从不接受异常)
该类试图涵盖处理异常的所有典型方法:
recover
使用一些提供替代值的处理代码李>
flatRecover
类似于flatMap
,它允许返回一个新的异常
实例,该实例将被展开并适当更新当前实例的状态李>
propagate
异常,从exception
表达式中抛出它,并使propagate
调用声明此异常类型李>
在包装成另一个异常后传播
它(翻译它)李>
句柄
它,导致一个空的异常
李>
- 作为处理的一种特殊情况,
使用空处理程序块吞下它
propagate
方法允许用户有选择地选择要从代码中公开哪些已检查异常。在调用终端操作时未处理的异常(如get
)将在没有声明的情况下偷偷抛出。这通常被认为是一种高级且危险的方法,但通常被用作某种方式,以减轻检查异常与不声明异常的lambda形状相结合所带来的麻烦。exceptive
类希望提供一个更干净、更具选择性的选择,以取代偷偷摸摸的投掷
如果允许java.util.function
提供的每个函数接口抛出异常会怎么样
public interface ThrowingSupplier<R, X extends Throwable> {
public R get() throws X;
}
(是一个永远不能抛出的运行时异常
你最初的例子会变成
ThrowingFunction<String, Integer, NumberFormatException> parse = Integer::parseInt;
Function<String, Optional<Integer>> safeParse = parse.fallbackTo(s -> null)
.andThen(Optional::ofNullable);
Stream.of(s1, s2)
.map(safeParse)
.map(i -> i.orElse(-1))
.forEach(System.out::println);
ThrowingFunction parse=Integer::parseInt;
函数safeParse=parse.fallbackTo(s->null)
.第四(可选::不可用);
水流(s1、s2)
.map(安全解析)
.map(i->i.orElse(-1))
.forEach(System.out::println);
有一个名为的第三方库。它具有提供必要功能的monad。它还具有TryMapFunction
和TrySupplier
功能接口,可以使用Try
monad,但有选中的异常。以下是我以前在这个主题上做过的一些介绍
我做了一个关于推理的界面。结果
要么是类型为T
的成功,要么是类型为异常的失败。它是的一个子类型,作为一个立即完成的异步操作,但这在这里并不重要
创造结果-
Result.success( value )
Result.failure( exception )
Result.call( callable )
然后可以通过各种方式变换结果-变换、映射、然后、偷看、捕捉、最后
等
Async<Integer> rInt = Result.success( s )
.map( Integer::parseInt )
.peek( System.out::println )
.catch_( NumberFormatException.class, ex->42 ) // default
.catch_( Exception.class, ex-> { ex.printStacktrace(); throw ex; } )
.finally_( ()->{...} )
Async rInt=Result.success
.map(整数::parseInt)
.peek(System.out::println)
.catch(NumberFormatException.class,ex->42)//默认值
.catch_(Exception.class,ex->{ex.printStacktrace();throw ex;})
.最后(()->{…})
不幸的是,API关注的是异步,所以有些方法返回异步。其中一些可以被Result覆盖以返回Result;但有些不能,例如then()
(这是平面地图)。但是如果有兴趣的话,,提取与异步无关的独立结果API很容易。如果您决定将该类放入某个存储库,请不要忘记更新您的答案:)@8472 Stackoverflow=>另一个由Mario Fusco为java编写的“Try”monad示例可以在这里找到:。@MarkoTopolnik当编译器试图推断X的类型时扩展可抛出的< /代码>它将:<代码>它指导解析优化α的实例化,以便如果可能的话,它不是一个检查异常类型< /代码>。有建议将一个类似的类型添加到C++中,在名称>代码>预期< /代码>下。在中,预期的
应为int
,但如果不是,原因是异常
。请看——这与异常类似,但与异常的联系较少。实际上,我设计类是为了响应我在或和Try
中看到的内容。它们只是重复了同一个著名的单子主题,在哈斯克尔之外,我并不觉得它特别实用。他们严格遵守纯FP、无国籍和不变性的宗教。几乎所有的东西都表示为类型转换,它比Java更适合Haskell这样的强大类型系统。而且,它们与你的头脑不太协调
@FunctionalInterface
public interface ThrowingSupplier<R, X extends Throwable> {
public R get() throws X;
default public Supplier<R> fallbackTo(Supplier<? extends R> supplier) {
ThrowingSupplier<R, Nothing> t = supplier::get;
return orTry(t)::get;
}
default public <Y extends Throwable> ThrowingSupplier<R, Y> orTry(
ThrowingSupplier<? extends R, ? extends Y> supplier) {
Objects.requireNonNull(supplier, "supplier");
return () -> {
try {
return get();
} catch (Throwable x) {
try {
return supplier.get();
} catch (Throwable y) {
y.addSuppressed(x);
throw y;
}
}
};
}
}
ThrowingFunction<String, Integer, NumberFormatException> parse = Integer::parseInt;
Function<String, Optional<Integer>> safeParse = parse.fallbackTo(s -> null)
.andThen(Optional::ofNullable);
Stream.of(s1, s2)
.map(safeParse)
.map(i -> i.orElse(-1))
.forEach(System.out::println);
Result.success( value )
Result.failure( exception )
Result.call( callable )
Async<Integer> rInt = Result.success( s )
.map( Integer::parseInt )
.peek( System.out::println )
.catch_( NumberFormatException.class, ex->42 ) // default
.catch_( Exception.class, ex-> { ex.printStacktrace(); throw ex; } )
.finally_( ()->{...} )