协程异常处理程序为什么使原始异常加倍?

我实现了我自己的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); } } } 

奇怪的行为是来自java。 ForkJoinTask#getThrowableException将重新抛出给定任务的异常:

如果可用,则返回给定任务的可重新抛出的异常。 为了提供准确的堆栈跟踪,如果当前线程没有抛出异常,我们尝试创建与抛出异常相同类型的新异常 ,但记录异常是其原因。 如果没有这样的构造函数,我们可以尝试使用无参数构造函数 ,然后使用initCause来达到同样的效果。 如果这些都不适用,或由于其他异常而导致任何失败,我们将返回记录的异常,但仍可能包含误导性的堆栈跟踪。

这意味着如果您不想为give任务重新引发异常,则可以非公开地构造异常构造函数,例如:

 val exception = object: IllegalStateException(){/**/}; // ^--- its constructor only available in its scope