我实现了自己的async
,我无法以正确的方式处理异常。为什么呢?
val expected = IllegalStateException();
val it = async<Any> {
throw expected;
};
assert.that({ it.get() }, throws(equalTo(expected)));
// ^--- but it throws a IllegalStateException(cause = expected)
interface Response<in T> {
suspend fun yield(value: T);
}
interface Request<out T> {
fun get(): T;
fun <R> then(mapping: (T) -> R): Request<R>;
}
private val executor: ExecutorService = ForkJoinPool(20);
fun <T> async(block: suspend Response<T>.() -> Unit): Request<T> {
return object : Request<T>, Response<T> {
@Volatile var value: T? = null;
var request: Continuation<Unit>? = block.createCoroutine(this, delegate {}).let {
var task: Future<*>? = executor.submit { it.resume(Unit); };
return@let delegate {
try {
val current = task!!;
task = null;
current.get();
} catch(e: ExecutionException) {
throw e.cause ?: e;
}
};
};
override fun <R> then(mapping: (T) -> R): Request<R> = async<R> {
yield(mapping(get()));
};
override fun get(): T {
return value ?: wait();
}
private fun wait(): T {
val it = request!!;
request = null;
it.resume(Unit);
return value!!;
}
suspend override fun yield(value: T) {
this.value = value;
}
};
}
inline fun <T> delegate(noinline exceptional: (Throwable) -> Unit = { throw it; }, crossinline resume: (T) -> Unit): Continuation<T> {
return object : Continuation<T> {
override val context: CoroutineContext = EmptyCoroutineContext;
override fun resumeWithException(exception: Throwable) {
exceptional(exception);
}
override fun resume(value: T) {
resume(value);
}
}
}
答案 0 :(得分:0)
奇怪的行为来自java。 ForkJoinTask#getThrowableException
将重新抛出给定任务的异常:
返回给定任务的 rethrowable 异常,如果 可用。如果异常,提供准确堆栈跟踪 当前线程没有抛出,我们尝试创建一个新的 异常与抛出的异常相同,但是与 记录异常是其原因。如果没有这样的话 构造函数,我们改为尝试使用 no-arg构造函数, 然后是
initCause
,效果相同。如果没有这些 申请,或由于其他例外的任何失败,我们返回 记录的异常,虽然可能,但仍然是正确的 包含误导性的堆栈跟踪。
这意味着如果您不想为请求任务重新抛出异常,则可以非公开地设置异常构造函数,例如:
val exception = object: IllegalStateException(){/**/};
// ^--- its constructor only available in its scope