Class ScxFunctionException
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
cool.scx.function.ScxFunctionException
- All Implemented Interfaces:
Serializable
ScxFunctionException 是用于隔离执行者异常和执行目标异常的标记异常. 用于解决 "执行与被执行者之间的异常边界问题".
设计动机
设想一下有如下方法
public void read(Function1Void<byte[], Exception> bytesConsumer, int length) throws IOException {
// someCode
}
当我们在调用时就会遇到如下问题, 也就是异常来源的模糊性问题.
try {
read(bytes -> {
// someCode maybe throw IOException
}, 1024);
} catch (IOException e) {
// 该如何区分这个 IOException 是 read 本身的 还是 bytesConsumer 的 ?
e.printStackTrace();
}
针对这种情况 我们创建 ScxFunctionException 用于包装 如 高阶函数中由于 用户传递的 Function 所引发的异常.
当然 ScxFunctionException 不仅仅局限于函数式接口, 也适用于任何 "可动态修改, 由外部传入, 可能抛异常" 的可执行单元, 比如 装饰器模式中的被装饰者 (如 InputStream) 等 .
用法展示, 这里我展示 三种推荐用法 .
用法 1 : 包装所有异常.
public void read(Function1Void<byte[], Exception> bytesConsumer, int length) throws ScxFunctionException, IOException {
// someCode
try {
bytesConsumer.apply(new byte[]{1,2,3});
} catch (Exception e) {
throw new ScxFunctionException(e);
}
// someCode
}
这种用法的好处是我们永远不会错误的判断异常的来源, 不过缺点则是对于 read 的调用方, 异常堆栈可能总是很长.
用法 2 : 只包装可能引发混淆的异常, 同时允许穿透传递所有 运行时异常. 这种用法更适用于 Function 只抛出 运行时异常.
// 假设 NoPermissionException 是一个 RuntimeException.
public void checkPermission(Function0<String[], RuntimeException> permissionsSupplier, String department) throws ScxFunctionException, NoPermissionException {
// someCode
try {
permissionsSupplier.apply();
} catch (NoPermissionException e) {
// 只包装可能混淆的异常
throw new ScxFunctionException(e);
} catch (RuntimeException e) {
// 此处的 catch 代码块也可以直接删除, 此处为了演示.
throw e;
}
// someCode
}
这种方法的好处是对于 permissionsSupplier 中发生的 不会混淆的运行时异常 (比如空指针, 索引越界等). 会直接穿透到 checkPermission 的调用者, 在异常层级上会更干净, 而且更符合所谓的函数式哲学. 缺点是模糊了部分异常的层级, 在某些情况下可能不太适合.
用法 3 : 类似 用法 2, 只包装可能引发混淆的异常, 但允许泛型异常. 这样便不仅仅局限于 只能抛出运行时异常, 也能抛出受检异常 .
public <X extends Exception> void read(Function1Void<byte[], X> bytesConsumer, int length) throws X, ScxFunctionException, IOException {
// someCode
try {
bytesConsumer.apply(new byte[]{1,2,3});
} catch (Exception e) {
// 包装易混淆异常
if(e instanceof IOException) {
throw new ScxFunctionException(e);
}
// 其他异常直接抛出
throw e;
}
// someCode
}
小提示: 在实际使用过程中 X 会被推断为 bytesConsumer 抛出的所有异常的最小共同父类.
- Version:
- 0.0.1
- Author:
- scx567888
- See Also:
-
Constructor Summary
Constructors -
Method Summary
Methods inherited from class Throwable
addSuppressed, fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, getSuppressed, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toString
-
Constructor Details
-
ScxFunctionException
作为一个标记类 我们只保留一个构造函数, 同时不允许传入 null
-
-
Method Details
-
getRootCause
获取真正的异常
-