Изключението вече е уловено от друга грешка на изключение

Експериментирах с HTTP клиентска библиотека на Apache в Eclipse

<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();
    }
    

3-та опция дава грешка

Изключението ClientProtocolException вече е уловено от алтернативното IOException

Видях изходния код за ClientProtocolException и то IOException. Доколкото разбирам, когато улавяме множество изключения, можем да уловим по-генерично изключение под по-конкретно. Така че не можем да хванем ClientProtocolException, след като хванем IOException.

Така че защо това се случва при много опити за улавяне? И ако не се предполага, че работи, защо Eclipse дава това предложение на 1-во място?


person Aniket Thakur    schedule 27.09.2014    source източник


Отговори (3)


Кодът не трябва да се компилира според JLS :

Това е грешка по време на компилиране, ако обединение на типове съдържа две алтернативи Di и Dj (i ≠ j), където Di е подтип на Dj (§4.10.2).

Преглеждайки списъка с грешки на Eclipse, има няколко, свързани с предложенията за бързо коригиране на множество грешки. Това изглежда като Буг 388724.

httpClient.execute хвърля и двете изключения, когато трябва да хвърля само IOException, което е случай, който разработчиците на Eclipse не са взели предвид при тестване.

person fgb    schedule 27.09.2014

Човек трябва да погледне байт кода, генериран от 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
...

Както можете да видите, компилаторът просто генерира запис в таблицата с изключения (TRYCATCHBLOCK), който сочи към същия байт код (L2) в случай на ClientProtocolException или RuntimeException.

И така, какво ще се случи, ако се опитате да направите това

catch (ClientProtocolException | IOException e)

След това компилаторът ще трябва да генерира два записа в таблицата с изключения, които сочат към един и същ байтов код за изпълнение и имат обща йерархия (единият е подклас на другия). Това означава, че ако бъде уловено изключение и jvm се опита да определи следващия байт код за изпълнение, два записа в таблицата с изключения ще съвпаднат. Така че компилаторът ви дава грешката: The exception ClientProtocolException is already caught by the alternative IOException.

Просто премахнете ClientProtocolException, защото ClientProtocolException е IOException.

person René Link    schedule 27.09.2014

По отношение на опцията try/multicatch #3: ClientProtocolException е подклас на IOException. Тъй като искате едно и също поведение на catch-block и за двете, няма нужда изрично да улавяте изключения от типа подклас. Всички такива хвърлени изключения ще бъдат уловени от суперкласа IOException.

На този въпрос също беше отговорено тук.

person fwc    schedule 11.01.2016