Java 在不抛出异常类型时出现异常类型处理问题-需要更通用的multi-catch版本
为TL道歉;博士,但我觉得这需要一些解释,否则会被误解 我有一个方法可以调用(通常是外部的)代码,我希望有时会抛出RuntimeException,并使用可以抛出InterruptedException或ExecutionException的futures,我希望能够从调用中返回一组有序的返回值,直到抛出异常,以及引发的异常。我写了一些有用的东西,但不幸的是,代码的外观让我觉得我做错了什么。我想我真正想要的是多捕获是一个更通用的概念。这将允许相当干净的代码来解决它,有点像这样:Java 在不抛出异常类型时出现异常类型处理问题-需要更通用的multi-catch版本,java,exception,generics,java-7,checked-exceptions,Java,Exception,Generics,Java 7,Checked Exceptions,为TL道歉;博士,但我觉得这需要一些解释,否则会被误解 我有一个方法可以调用(通常是外部的)代码,我希望有时会抛出RuntimeException,并使用可以抛出InterruptedException或ExecutionException的futures,我希望能够从调用中返回一组有序的返回值,直到抛出异常,以及引发的异常。我写了一些有用的东西,但不幸的是,代码的外观让我觉得我做错了什么。我想我真正想要的是多捕获是一个更通用的概念。这将允许相当干净的代码来解决它,有点像这样: public c
public class SomeResults {
private final Set<SomeReturnType> valuesReturned;
private final @Nullable RuntimeException | ExecutionException | InterruptedException exception;
public SomeResults(Set<SomeReturnType> valuesReturned, RuntimeException | ExecutionException exception {
this.valuesReturned = valuesReturned;
this.exception = exception;
}
public Set<SomeReturnType> getValuesReturned() {
return valuesReturned;
}
public @Nullable RuntimeException | ExecutionException | InterruptedException getException();
}
MyResult generateResults(Bar bar) {
// Setup code
Set<SomeReturnType> valuesReturned = new LinkedHashSet<>();
// …
// loop
{
// stuff
// … exceptions in this method should throw except for this one external code call
try {
valuesReturned.add(externalCodeCallGetSomeReturnValue(bar));
}
catch( RuntimeException | ExecutionException | InterruptedException e) {
// In Java 8 you would say: new MyResult(valuesReturned, ()->{ throw e });
return new MyResult(valuesReturned, new ReThrower() {
public void reThrow()
throws RuntimeException, ExecutionException, InterruptedException {
throw e;
}
});
}
//...
}
return new MyResult(valuesReturned, null);
}
请注意,我始终希望立即重新显示异常-这取决于谁在使用这些结果以及他们希望如何处理这些结果。我可能会这样做
try {
SomeResults myResults = foo.generateResults(new Bar());
Foobar Foobar = new Foobar(myResults);
}
catch(Exception e) {
// I don't want to see any exceptions from externalCodeCallGetSomeReturnValue(bar) here
...
}
当然,我可以在生成结果的函数中抛出异常,而不是捕获异常并将其作为结果返回。这有两个相当大的问题:
1.现在返回一组值会很尴尬-我可能会将一个集合传递给需要“返回”结果的方法,然后它会修改该集合而不是返回集合。这允许在返回异常时设置为最新。乙二醇
generateResults(Bar bar, Set<SomeReturnType> orderedListForMeToWrite) throws ExecutionException, InterruptedException
generateResults(条形图,Set-orderedListForMeToWrite)引发ExecutionException、InterruptedException
public static class SomeResults {
private final Set<SomeReturnType> orderedReturnValues;
private final @Nullable Exception exception;
AsyncEchoesResult(Set<SomeReturnType> responses) {
this.orderedResponses = responses;
this.exception = null;
}
AsyncEchoesResult(Set<SomeReturnType> responses, RuntimeException exception) {
this.orderedResponses = responses;
this.exception = exception;
}
AsyncEchoesResult(Set<SomeReturnType> responses, ExecutionException exception) {
this.orderedResponses = responses;
this.exception = exception;
}
AsyncEchoesResult(Set<SomeReturnType> responses, InterruptedException exception) {
this.orderedResponses = responses;
this.exception = exception;
}
public Set<SomeReturnType> getResponses() {
return orderedResponses;
}
public @Nullable Exception getException() {
return exception;
}
public void throwExceptionIfExists() throws ExecutionException, InterruptedException {
try {
throw (exception);
}
catch (RuntimeException | ExecutionException | InterruptedException e) {
throw e;
}
catch (Exception e) {
throw new RuntimeException("Unexpected exception type in SomeResults",e);
}
}
}
公共静态类SomeResults{
私有最终集OrderedReturnValue;
私有final@Nullable异常;
AsyncEchosResult(设置响应){
this.orderedResponses=响应;
this.exception=null;
}
AsyncEchosResult(设置响应、运行时异常){
this.orderedResponses=响应;
this.exception=异常;
}
AsyncEchosResult(设置响应、ExecutionException异常){
this.orderedResponses=响应;
this.exception=异常;
}
AsyncEchoseResult(设置响应、中断异常){
this.orderedResponses=响应;
this.exception=异常;
}
公共集getResponses(){
返回orderedResponses;
}
public@Nullable异常getException(){
返回异常;
}
public void throwExceptionIfExists()抛出ExecutionException、InterruptedException{
试一试{
抛出(异常);
}
捕获(RuntimeException | ExecutionException | InterruptedException e){
投掷e;
}
捕获(例外e){
抛出新的RuntimeException(“SomeResults中的意外异常类型”,e);
}
}
}
显然,这很难看。如果我讨厌构造函数,我可以很容易地用一个接受异常的构造函数来替换它们,但这会削弱类型检查,使其仅限于throwException()的运行时调用。不管怎样,有没有更好的替代方案?请注意,我使用的是JDK 7,因此虽然JDK 8的答案会很有趣,但这并不能解决我正在处理的问题。因为Java不允许将变量声明为“这些类型之一”,所以必须使用唯一支持此类类型集的构造来封装异常:一段引发该异常的代码 请考虑以下类型定义:
interface ReThrower {
void reThrow() throws RuntimeException, ExecutionException, InterruptedException;
}
static class MyResult
{
private final Set<SomeReturnType> valuesReturned;
private final @Nullable ReThrower exception;
public MyResult(Set<SomeReturnType> valuesReturned, ReThrower exception) {
this.valuesReturned = valuesReturned;
this.exception = exception;
}
public Set<SomeReturnType> getValuesReturned() {
return valuesReturned;
}
public void reThrowException()
throws RuntimeException, ExecutionException, InterruptedException
{
if(exception!=null) exception.reThrow();
}
}
请注意,内部类(或Java 8中的lambda表达式)隐式存储异常,并且该隐式变量具有所需的“列出的异常类型之一”。然后,您可以安全地重新引发异常:
MyResult results = new MultiCatchAndStore().generateResults(new Bar());
try
{
results.reThrowException();
} catch(RuntimeException | ExecutionException | InterruptedException ex)
{
// handle, of course, you could also have separate catch clauses here
}
我欢迎就如何改进这一问题提出建议。然而,没有任何评论的否决票让我没有任何有用的信息。有人心情不好?有人意外单击了按钮?您的多构造函数方法不起作用,因为您无法从multi-catch子句调用其中任何一个。multi-catch子句的代码将捕获的异常视为具有公共基类的类型。我知道,这就是为什么我讨厌这个,并且想要一个更好的方法的原因之一。调用构造函数的异常代码看起来像是多批次前的几天:-(
MyResult generateResults(Bar bar) {
// Setup code
Set<SomeReturnType> valuesReturned = new LinkedHashSet<>();
// …
// loop
{
// stuff
// … exceptions in this method should throw except for this one external code call
try {
valuesReturned.add(externalCodeCallGetSomeReturnValue(bar));
}
catch( RuntimeException | ExecutionException | InterruptedException e) {
// In Java 8 you would say: new MyResult(valuesReturned, ()->{ throw e });
return new MyResult(valuesReturned, new ReThrower() {
public void reThrow()
throws RuntimeException, ExecutionException, InterruptedException {
throw e;
}
});
}
//...
}
return new MyResult(valuesReturned, null);
}
MyResult results = new MultiCatchAndStore().generateResults(new Bar());
try
{
results.reThrowException();
} catch(RuntimeException | ExecutionException | InterruptedException ex)
{
// handle, of course, you could also have separate catch clauses here
}