我正在Eclipse中试验Apache HTTP客户端库
<dependency org="org.apache.httpcomponents" name="httpclient" rev="4.3.1"/>
以下代码片段抛出已检查的异常,需要进行处理。
HttpResponse response = httpClient.execute(httprequest);
Eclipse提供3条建议
添加抛出异常 - throws ClientProtocolException, IOException
(正常工作)
环绕尝试捕获 -
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();
}
(也可以正常工作)
使用try / multicatch进行环绕
try {
HttpResponse response = httpClient.execute(httprequest);
}
catch (ClientProtocolException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
第3个选项提供错误
异常ClientProtocolException已被替代IOException
捕获
我看到了ClientProtocolException
的{{3}}和IOException
。根据我的理解,当捕获多个异常时,我们可以在更具体的异常下捕获更多的通用异常。因此,在抓取ClientProtocolException
之后,我们无法抓住IOException
。
那为什么会在多次尝试捕获中发生这种情况?如果它没有被认为可以工作,为什么Eclipse会在第一时间提出这个建议呢?
答案 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 entry(TRYCATCHBLOCK
),如果L2
或{{ClientProtocolException
,则指向相同的字节代码(RuntimeException
) 1}}。
那么如果你试图这样做会发生什么
catch (ClientProtocolException | IOException e)
编译器必须生成两个异常表条目,这些条目指向要执行的相同字节代码,并且它们具有公共层次结构(一个是另一个的子类)。这意味着如果捕获到异常并且jvm尝试确定要执行的下一个字节代码,则两个异常表条目将匹配。所以编译器会给你错误:The exception ClientProtocolException is already caught by the alternative IOException
。
只需删除ClientProtocolException
,因为ClientProtocolException
是IOException
。
答案 1 :(得分:1)
代码不应该根据JLS编译:
如果类型的并集包含两个,则是编译时错误 替代Di和Dj(i≠j)其中Di是Dj的子类型(§4.10.2)。
查看Eclipse的错误列表,有一些与快速修复多捕获提案有关。这看起来像Bug 388724。
httpClient.execute
抛出两个异常,只需要抛出IOException
,这是Eclipse开发人员在测试时没有考虑的情况。
答案 2 :(得分:1)
关于try / multicatch选项#3:ClientProtocolException
是IOException
的子类。由于您希望两者都具有相同的catch-block行为,因此无需显式捕获子类类型的异常。任何此类抛出的异常都将被IOException
超类捕获。
此问题也得到了解答here。