我有一些代码可能会抛出检查和运行时异常。
我想捕获已检查的异常并将其包装为运行时异常。但是如果抛出RuntimeException,我不必包装它,因为它已经是运行时异常。
我所拥有的解决方案有点开销而且不是“整洁”:
try {
// some code that can throw both checked and runtime exception
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
想要更优雅的方式吗?
答案 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
块,这就是我喜欢的原因。