2014-09-27 120 views
1

我与Apache的HTTP客户端库在Eclipse异常已被其它异常错误

<dependency org="org.apache.httpcomponents" name="httpclient" rev="4.3.1"/> 

实验和下面的代码片段抛出checked异常,需要进行处理捕获。

HttpResponse response = httpClient.execute(httprequest); 

Eclipse中给出三点建议

  1. 添加抛出异常 - throws ClientProtocolException, IOException(正常工作)

  2. 与尝试捕捉环绕 -

    try { 
        HttpResponse response = httpClient.execute(httprequest); 
    } 
    catch (ClientProtocolException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
    } 
    catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
    } 
    

    (也工作正常)

  3. 环绕使用try/multicatch

    try { 
        HttpResponse response = httpClient.execute(httprequest); 
    } 
    catch (ClientProtocolException | IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
    } 
    

第三选项给出错误

The exception ClientProtocolException is already caught by the alternative IOException

只见source codeClientProtocolException,它IOException。就我的理解而言,当捕获多个异常时,我们可以在更具体的异常下捕获更通用的异常。所以在捕获IOException后我们赶不上ClientProtocolException

那么,为什么这会发生在多次尝试抓住?如果它不能工作,Eclipse为什么会在第一位给出这个建议?

回答

1

我们必须看看javac生成的字节码,以了解编译器错误出现的原因。

我修改了您的代码并添加了一个RuntimeException以便使其编译和分析生成的字节码。

下面的源代码

try { 
    HttpResponse response = httpClient.execute(request); 
} catch (ClientProtocolException | RuntimeException e) { 
    System.out.println("ClientProtocolException and RuntimeException"); 
} catch (IOException e) { 
    System.out.println("IOException"); 
} 

会导致这个字节码这样

TRYCATCHBLOCK L0 L1 L2 org/apache/http/client/ClientProtocolException 
TRYCATCHBLOCK L0 L1 L2 java/lang/RuntimeException 
TRYCATCHBLOCK L0 L1 L3 java/io/IOException 
... 
L2 
FRAME SAME1 java/lang/Exception 
ASTORE 1 
L5 
    LINENUMBER 18 L5 
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream; 
    LDC "ClientProtocolException and RuntimeException" 
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V 
L6 
    GOTO L4 
L3 
    LINENUMBER 19 L3 
    FRAME SAME1 java/io/IOException 
    ASTORE 1 
L7 
    LINENUMBER 20 L7 
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream; 
    LDC "IOException" 
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V 
L4 
... 

正如你所看到的编译器只是产生exception table entryTRYCATCHBLOCK)指向相同的字节码(L2)如果是ClientProtocolExceptionRuntimeException

所以,如果你尝试这样做

catch (ClientProtocolException | IOException e) 

比编译器必须生成指向同一个字节代码执行两个例外表项,他们有一个共同的层次结构(一个是会发生什么另一个的子类)。这意味着如果捕获到异常并且jvm尝试确定下一个要执行的字节代码,那么两个异常表条目将匹配。所以编译器会给你错误:The exception ClientProtocolException is already caught by the alternative IOException

只要删除ClientProtocolException,因为ClientProtocolExceptionIOException

1

的代码不应该根据JLS编译:

It is a compile-time error if a union of types contains two alternatives Di and Dj (i ≠ j) where Di is a subtype of Dj (§4.10.2).

通过Eclipse中的bug列表来看,有几个相关的速战速决多抓的建议。这看起来像Bug 388724

httpClient.execute当它只需要抛出IOException时会抛出两个异常,这是Eclipse开发人员在测试时不考虑的情况。

1

关于try/multicatch选项#3:ClientProtocolExceptionIOException的一个子类。既然你希望两者都有相同的catch-block行为,就不需要显式地捕获子类型的异常。任何此类抛出的异常都将被IOException超类捕获。

这个问题也回答了here