2017-02-02 3 views
1

Ich habe eine Frage über Java-Methode Introspektion, speziell in Bezug auf Ausnahmen. Sagen wir, ich habe den folgenden Code:Java Exception-werfen Introspektion

private String getCustomReportResponse(HttpsURLConnection customReportConnection) { 
    int responseCode = 0; 

    try { 
     responseCode = customReportConnection.getResponseCode(); 
     return httpResponseBodyExtractor.extractResponseBodyFrom(customReportConnection); 
    } catch (IOException e) { 
     translateIntoRelevantException(responseCode, e); 
    } 
} 

Sagen wir beide Aussagen im try-Block eine IOException werfen fähig sind - in diesem Fall wird die translateIntoRelevantException Methode aufgerufen, die wie folgt aussieht:

private void translateIntoRelevantException(int responseCode, IOException e) { 
    if(is5xxResponseCode(responseCode)) { 
     throw new ServerResponseException("Could not generate report - returned response code " + responseCode, e); 
    } 

    throw new ReportException("GeminiReportException: Unable to parse response from HTTP body when requesting custom Gemini report.", e); 
} 

Also, was auch immer passiert, entweder wird ein String zurückgegeben oder eine Ausnahme wird ausgelöst. Nur die getCustomReportResponse-Methode kompiliert nicht, ohne nach dem catch-Block eine return-Anweisung hinzuzufügen, die absolut unerreichbar ist. In der Tat, wenn ich den Inhalt von translateIntoRelevantException in den Catch-Block, kompiliert es, was mir daft scheint.

ich hinzufügen sollte, wobei die Ausnahmen geworfen werden Runtime-Ausnahmen, aber ich habe auch versucht, Ausnahmen sie geprüft zu machen, aber das Problem bestand.

Könnte jemand bitte erklären, warum?

Antwort

1

Dies ist ein common problem, dass „rethrow“ Hilfsmethoden konfrontiert.

Der Compiler nicht weiß (und es gibt keinen Weg, um anzuzeigen), dass die Methode translateIntoRelevantException wird nie wieder zurückkehren.

Als solches denkt, dass es ein Code-Pfad, der nach try Block weiter. Also muss man in einem "dead-Code" put return null (oder throw new RuntimeException("should never come here").

Sie müssen es nicht setzen nach dem try Block, können Sie es innerhalb des catch setzen.

try { 
    responseCode = customReportConnection.getResponseCode(); 
    return httpResponseBodyExtractor.extractResponseBodyFrom(customReportConnection); 
} catch (IOException e) { 
    translateIntoRelevantException(responseCode, e); 
    throw new RuntimeException("should never come here"); 
} 

Es ist wahrscheinlich schönere haben die Helfer nur return die Ausnahme, anstatt sie zu werfen. Dann können Sie

throw translateIntoRelevantException(responseCode, e); 
+0

Dank für die Beantwortung. Wenn ich also den Inhalt der Methode (translateIntoRelevantException) in den catch-Block verschiebe (der Inhalt ist implizit ungültig, da in 100% der Fälle eine Ausnahme ausgelöst wird), funktioniert es. Ich dachte, der Compiler würde in der Lage sein, in die Methode zu schauen, und in jedem Fall wird eine Ausnahme ausgelöst. Es sieht so aus, als würde der Compiler die Modularisierung bestrafen, was merkwürdig ist. –

+0

Hier ist ein weiterer cooler Trick: http: // stackoverflow.com/a/39719455/14955 – Thilo

+1

Nein, der Compiler sieht nicht * in * Methoden, nur bei der angegebenen Signatur. Und es gibt keine Möglichkeit zu deklarieren, dass eine Methode niemals zurückkehrt (in Scala können Sie zum Beispiel sagen, dass der Rückgabetyp "Nichts" ist, um genau das zu tun). Das Betrachten von Methodenimplementierungen kann für private Methoden in derselben Klasse funktionieren, aber sobald der dynamische Methodenversand (Sub-Classing) involviert ist, wird das nicht mehr funktionieren. Von beiden zu unterscheiden scheint sich nicht zu lohnen. – Thilo

1

Compilation von getCustomReportResponse tun sollte nicht auf die Umsetzung vonverlassenaus mehreren Gründen:

  • Implementierung von translateIntoRelevantException möglicherweise nicht verfügbar (es ist in einer separaten Klasse, in einer separaten Bibliothek sein könnte);
  • sonst jede Änderung in translateIntoRelevantException könnten alle der Aufruf Methoden brechen.

Als Alternative Sie eine Ausnahme zurückgeben kann und es dann in einem Client-Code werfen:

private IOException translateIntoRelevantException(int responseCode, IOException e) { 
    if(is5xxResponseCode(responseCode)) { 
     return new ServerResponseException("Could not generate report - returned response code " + responseCode, e); 
    } 

    return new ReportException("GeminiReportException: Unable to parse response from HTTP body when requesting custom Gemini report.", e); 
} 

dann es so nennen:

throw translateIntoRelevantException(responseCode, e); 
+0

@DannyNoam 父 Der Compiler muss die getString-Implementierung nicht überprüfen. Die Methodensignatur ist mehr als genug, um zu überprüfen, ob sie korrekt aufgerufen wurde. –

+1

Vielen Dank für die Hilfe! –