如何包装已检查的异常但在Java中保留原始运行时异常

时间:2016-09-27 08:06:38

标签: java runtimeexception checked-exceptions

我有一些代码可能会抛出检查和运行时异常。

我想捕获已检查的异常并将其包装为运行时异常。但是如果抛出RuntimeException,我不必包装它,因为它已经是运行时异常。

我所拥有的解决方案有点开销而且不是“整洁”:

try {
  // some code that can throw both checked and runtime exception
} catch (RuntimeException e) {
  throw e;
} catch (Exception e) {
  throw new RuntimeException(e);
}

想要更优雅的方式吗?

7 个答案:

答案 0 :(得分:28)

我使用“盲目”重新抛出来传递已检查的异常。我已经使用它来传递Streams API,我不能使用抛出已检查异常的lambdas。例如,我们有ThrowingXxxxx功能接​​口,因此可以传递经过检查的异常。

这允许我自然地在调用者中捕获已检查的异常,而不需要知道被调用者必须通过不允许检查异常的接口传递它。

try {
  // some code that can throw both checked and runtime exception

} catch (Exception e) {
  throw rethrow(e);
}

在调用方法中,我可以再次声明已检查的异常。

public void loadFile(String file) throws IOException {
   // call method with rethrow
}
/**
 * Cast a CheckedException as an unchecked one.
 *
 * @param throwable to cast
 * @param <T>       the type of the Throwable
 * @return this method will never return a Throwable instance, it will just throw it.
 * @throws T the throwable as an unchecked throwable
 */
@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
    throw (T) throwable; // rely on vacuous cast
}

处理异常有很多不同的选择。我们使用其中一些。

https://vanilla-java.github.io/2016/06/21/Reviewing-Exception-Handling.html

答案 1 :(得分:17)

Guava的Throwables.propagate()就是这样做的:

try {
    // some code that can throw both checked and runtime exception
} catch (Exception e) {
    throw Throwables.propagate(e);
}

更新:此方法现已弃用。有关详细说明,请参阅this page

答案 2 :(得分:5)

不是。

如果你经常这么做,你可以把它塞进一个辅助方法。

static RuntimeException unchecked(Throwable t){
    if (t instanceof RuntimeException){
      return (RuntimeException) t;
    } else if (t instanceof Error) { // if you don't want to wrap those
      throw (Error) t;
    } else {
      return new RuntimeException(t);
    }
}

try{
 // ..
}
catch (Exception e){
   throw unchecked(e);
}

答案 3 :(得分:2)

我有一个特殊编译的.class文件,其中包含以下内容:

public class Thrower {
    public static void Throw(java.lang.Throwable t) {
        throw t;
    }
}

它只是有效。 java编译器通常会拒绝编译它,但字节码验证器根本不关心。

该课程的使用类似于Peter Lawrey的答案:

try {
  // some code that can throw both checked and runtime exception

} catch (Exception e) {
    Thrower.Throw(e);
}

答案 4 :(得分:1)

您可以使用instanceof运算符

重写相同的内容
try {
    // some code that can throw both checked and runtime exception
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        throw e;
    } else {
        throw new RuntimeException(e);
    }
}

但是,您的解决方案看起来更好。

答案 5 :(得分:1)

问题是Exception过于宽泛。您应该确切知道可能的已检查异常是什么。

try {
    // code that throws checked and unchecked exceptions
} catch (IOException | SomeOtherException ex) {
    throw new RuntimeException(ex);
}

这不起作用的原因揭示了应该解决的更深层次的问题:

如果方法声明它throws Exception,那么它太宽泛了。知道&#34;某些事情可能出错&#34;没有进一步的信息对呼叫者没用。该方法应该在有意义的层次结构中使用特定的异常类,或者在适当的情况下使用未经检查的异常。

如果一个方法抛出太多不同类型的已检查异常,那么它太复杂了。它应该被重构为多个更简单的方法,或者异常应该根据情况安排在合理的继承层次结构中。

当然可以有规则的例外情况。如果方法throws Exception被某种交叉框架(例如JUnit或AspectJ或Spring)使用而不是包含供其他人使用的API,那么声明方法var isAdvancedUpload = function() { var div = document.createElement('div'); return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && 'FormData' in window && 'FileReader' in window; }(); var $form = $('ui form'); var $fileBox = $('.box'); var $input = $fileBox.find('input[type="file"]'), $label = $fileBox.find('label'); showFiles = function(files) { $label.text(files.length > 1 ? ($input.attr('data-multiple-caption') || '').replace('{count}', files.length) : files[0].name); }; if (isAdvancedUpload) { var droppedFiles = false; $fileBox.addClass('has-advanced-upload'); $fileBox.on('drag dragstart dragend dragover dragenter dragleave drop', function(e) { e.preventDefault(); e.stopPropagation(); }); $fileBox.on('dragover dragenter', function() { $fileBox.addClass('is-dragover'); }); $fileBox.on('dragleave dragend drop', function() { $fileBox.removeClass('is-dragover'); }); $fileBox.on('drop', function(e) { droppedFiles = e.originalEvent.dataTransfer.files; var $imgDiv = $('.selected-images'); $.each(droppedFiles, function(index, file) { var img = document.createElement('img'); img.onload = function() { window.URL.revokeObjectURL($.src); }; img.height = 100; img.src = window.URL.createObjectURL(file); $imgDiv.append(img); showFiles(droppedFiles); }); }); } $form.on('submit', function(e) { if ($fileBox.hasClass('is-uploading')) return false; $fileBox.addClass('is-uploading').removeClass('is-error'); if (isAdvancedUpload) { e.preventDefault(); var ajaxData = new FormData($form.get(0)); if (droppedFiles) { $.each(droppedFiles, function(i, file) { ajaxData.append($input.attr('name'), file); }); } $.ajax({ url: $form.attr('action'), type: $form.attr('method'), data: ajaxData, dataType: 'json', cache: false, contentType: false, processData: false, complete: function() { $fileBox.removeClass('is-uploading'); }, success: function(data) { $fileBox.addClass(data.success == true ? 'is-success' : 'is-error'); if (!data.success) $errorMsg.text(data.error); }, error: function() { console.log(data.error); } }); } else { var iframeName = 'uploadiframe' + new Date().getTime(); $iframe = $('<iframe name="' + iframeName + '" style="display: none;"></iframe>'); $('body').append($iframe); $form.attr('target', iframeName); $iframe.one('load', function() { var data = JSON.parse($iframe.contents().find('body').text()); $form .removeClass('is-uploading') .addClass(data.success == true ? 'is-success' : 'is-error') .removeAttr('target'); if (!data.success) $errorMsg.text(data.error); $form.removeAttr('target'); $iframe.remove(); }); }; }); $input.on('change', function(e) { showFiles(e.target.files); });可能是完全合理的。

答案 6 :(得分:1)

我通常使用相同类型的代码结构,但是在三元运算符实际使代码更好的几次之一中将其压缩到一行:

catch

这不需要额外的方法或Set块,这就是我喜欢的原因。