异常已被其他异常错误捕获

时间:2014-09-27 09:31:43

标签: java try-catch httpclient java-7

我正在Eclipse中试验Apache HTTP客户端库

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

以下代码片段抛出已检查的异常,需要进行处理。

 HttpResponse response = httpClient.execute(httprequest);

Eclipse提供3条建议

  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();
    }
    
  4. 第3个选项提供错误

      

    异常ClientProtocolException已被替代IOException

    捕获

    我看到了ClientProtocolException的{​​{3}}和IOException。根据我的理解,当捕获多个异常时,我们可以在更具体的异常下捕获更多的通用异常。因此,在抓取ClientProtocolException之后,我们无法抓住IOException

    那为什么会在多次尝试捕获中发生这种情况?如果它没有被认为可以工作,为什么Eclipse会在第一时间提出这个建议呢?

3 个答案:

答案 0 :(得分: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或{{ClientProtocolException,则指向相同的字节代码(RuntimeException) 1}}。

那么如果你试图这样做会发生什么

catch (ClientProtocolException | IOException e)

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

只需删除ClientProtocolException,因为ClientProtocolExceptionIOException

答案 1 :(得分:1)

代码不应该根据JLS编译:

  

如果类型的并集包含两个,则是编译时错误   替代Di和Dj(i≠j)其中Di是Dj的子类型(§4.10.2)。

查看Eclipse的错误列表,有一些与快速修复多捕获提案有关。这看起来像Bug 388724

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

答案 2 :(得分:1)

关于try / multicatch选项#3:ClientProtocolExceptionIOException的子类。由于您希望两者都具有相同的catch-block行为,因此无需显式捕获子类类型的异常。任何此类抛出的异常都将被IOException超类捕获。

此问题也得到了解答here