我遇到了涉及異常捕獲和簽名中的Java泛型的意外問題。事不宜遲,代碼有問題(解釋如下):帶有通用參數的Java方法從catch塊的結果中調用
public class StackOverflowTest {
private static class WrapperBuilder {
public static <T> ResultWrapper of(final T result) {
return new ResultWrapper<>(result);
}
public static ResultWrapper of(final RuntimeException exc) {
return new ResultWrapper<>(exc);
}
}
private static class ResultWrapper<T> {
private final T result;
private final RuntimeException exc;
ResultWrapper(final T result) {
this.result = result;
this.exc = null;
}
ResultWrapper(final RuntimeException exc) {
this.result = null;
this.exc = exc;
}
public Boolean hasException() {
return this.exc != null;
}
public T get() {
if (hasException()) {
throw exc;
}
return result;
}
}
private static class WrapperTransformer {
public ResultWrapper<Result> getResult(ResultWrapper originalWrappedResult) {
if (originalWrappedResult.hasException()) {
try {
originalWrappedResult.get();
} catch (Exception e) {
return WrapperBuilder.of(e);
}
}
return originalWrappedResult; // Transformation is a no-op, here
}
}
private static class Result {}
WrapperTransformer wrapper = new WrapperTransformer();
@Test
public void testBehaviour() {
ResultWrapper wrappedResult = WrapperBuilder.of(new RuntimeException());
final ResultWrapper<Result> result = wrapper.getResult(wrappedResult);
assertTrue(result.hasException()); // fails!
}
}
暫且不論,就目前而言,不良作風問題,(我完全承認,是更好的方法去做做我在做什麼!在這裏),這是下列業務邏輯的下調和匿名版本:
- 類
ResultWrapper
換到下游服務的調用的結果。它要麼包含調用,或造成異常的結果 - 類
WrapperTransformer
負責以某種方式轉化ResultWrapper(不過,在這裏,「轉型」是一個無操作)
測試上面給出的失敗。從調試中,我確定這是因爲WrapperBuilder.of(e)
實際上是調用通用方法(即of(final T result)
)。如果通用參數是「貪婪的」,那麼(有點)是有道理的,因爲這種方法是明智的(儘管是非預期的)選擇。
然而,當DownstreamWrapper::getResult
方法變更爲:
// i.e. explicitly catch RuntimeException, not Exception
} catch (RuntimeException e) {
return WrapperBuilder.of(e)
}
然後測試失敗 - 即Exception
被識別爲RuntimeException
,非泛型.of
方法被調用,並且因此所得到的ResultWrapper
具有人口稠密的exc
。
這對我來說完全是莫名其妙的。我相信,即使在catch (Exception e)
子句中,e
仍保留其原始類型(並且記錄消息System.out.println(e.getClass().getSimpleName()
表明該屬性爲真) - 那麼如何更改catch的「類型」覆蓋泛型方法簽名?
太棒了,謝謝! – scubbo