Ist es eine schlechte Praxis, eine return-Anweisung zu haben, um die Syntax zu erfüllen?

82

Betrachten Sie den folgenden Code:

public Object getClone(Cloneable a) throws TotallyFooException {

    if (a == null) {
        throw new TotallyFooException();
    }
    else {
        try {
            return a.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
    //cant be reached, in for syntax
    return null;
}

Dies return null;ist erforderlich, da möglicherweise eine Ausnahme abgefangen wird. In einem solchen Fall haben wir jedoch bereits überprüft, ob sie null ist (und wir nehmen an, dass die von uns aufgerufene Klasse das Klonen unterstützt), sodass wir wissen, dass die try-Anweisung niemals fehlschlagen wird.

Ist es eine schlechte Praxis, die zusätzliche return-Anweisung am Ende einzufügen, um die Syntax zu erfüllen und Kompilierungsfehler zu vermeiden (mit einem Kommentar, der erklärt, dass sie nicht erreicht werden), oder gibt es eine bessere Möglichkeit, so etwas so zu codieren, dass das Extra return-Anweisung ist nicht erforderlich?

yitzih
quelle
25
Ihre Methode verwendet einen ObjectParameter. Wenn aes sich nicht um eine Klasse handelt, die die cloneMethode unterstützt (oder ist dies in definiert Object?) Oder wenn während der cloneMethode ein Fehler auftritt (oder ein anderer Fehler, an den ich momentan nicht denken kann), könnte eine Ausnahme ausgelöst werden und Sie würden erreichen die return-Anweisung.
Arc676
26
Ihre Annahme, dass die endgültige Rendite nicht erreicht werden kann, ist falsch. Es ist absolut gültig für eine Klasse, die implementiert, um a Cloneablezu werfen CloneNotSupportedException. Quelle: Javadocs
Kopffüßer
20
Der Code, den Sie als "nicht erreichbar" kommentiert haben, ist erreichbar. Wie oben erwähnt, gibt es einen Codepfad von der CloneNotSupportedException zu dieser Zeile.
David Waterworth
7
Die Kernfrage hier: Wenn Sie davon ausgehen, dass die von Ihnen aufgerufene Klasse das Klonen unterstützt, warum fangen Sie die Ausnahme überhaupt ab? Ausnahmen sollten für außergewöhnliches Verhalten geworfen werden.
Deworde
3
@wero würde ich AssertionErrorstatt gehen InternalError. Letzteres scheint für den besonderen Gebrauch zu sein, wenn etwas in der JVM schief geht. Und Sie behaupten im Grunde, dass der Code nicht erreicht wird.
Kap

Antworten:

134

Ein klarerer Weg ohne zusätzliche Rückgabeanweisung ist wie folgt. Ich würde es auch nicht fangen CloneNotSupportedException, aber es dem Anrufer überlassen.

if (a != null) {
    try {
        return a.clone();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
}
throw new TotallyFooException();

Es ist fast immer möglich, an der Reihenfolge herumzuspielen, um eine geradlinigere Syntax zu erhalten als ursprünglich.

Kayaman
quelle
28
Dies zeigt einen wirklich guten allgemeinen Punkt. Wenn Sie gegen die Anforderungen von Java kämpfen, bedeutet dies im Allgemeinen, dass Sie versuchen, etwas nicht optimal zu tun. Wenn ich mich unwohl fühle, trete ich normalerweise zurück und schaue mir das ganze Bild an und versuche herauszufinden, ob es auf eine andere Weise codiert werden könnte, die es klarer macht - im Allgemeinen gibt es das. Die meisten der kleinen Nitpicks von Java sind erstaunlich hilfreich, wenn Sie sie einmal umarmen.
Bill K
3
@ BillK: Dieser Code hat jedoch eine andere Semantik, wie von Maroun Maroun hervorgehoben.
Deduplikator
5
AssertionErrorist eine eingebaute Klasse mit einer ähnlichen Absicht wie TotallyFooException(die eigentlich nicht existiert).
user253751
5
@BillK: "Wenn Sie gegen die Anforderungen von Java kämpfen, bedeutet dies im Allgemeinen, dass Sie versuchen, etwas nicht optimal zu tun." oder dass Java beschlossen hat, keine Funktion zu unterstützen, die Ihnen das Leben erleichtert.
user541686
5
@Mehrdad, ... aber wenn Sie es so betrachten, sind Sie praktisch nirgendwo nützlich, es sei denn, Sie arbeiten an RFEs für zukünftige Java-Versionen oder eine alternative Sprache. Das Erlernen der lokalen Redewendungen hat einen echten, praktischen Vorteil, wohingegen die Schuld an der Sprache (jede Sprache, es sei denn, sie unterstützt die Metaprogrammierung a-la-LISP, um das Hinzufügen neuer Syntax selbst zu ermöglichen) dafür verantwortlich ist, dass sie die Art und Weise, wie Sie zuerst etwas tun wollten, nicht unterstützt.
Charles Duffy
100

Es kann definitiv erreicht werden. Beachten Sie, dass Sie nur den Stacktrace in der catchKlausel drucken .

In dem Szenario , wo a != nullund es wird eine Ausnahme sein, das return null wird erreicht werden. Sie können diese Anweisung entfernen und durch ersetzen throw new TotallyFooException();.

Im Allgemeinen * ist es keine gute Idee , wenn nullein gültiges Ergebnis einer Methode vorliegt (dh der Benutzer erwartet es und es bedeutet etwas), es als Signal für "Daten nicht gefunden" oder aufgetretene Ausnahme zurückzugeben, keine gute Idee. Ansonsten sehe ich kein Problem, warum Sie nicht zurückkehren sollten null.

Nehmen Sie zum Beispiel die Scanner#ioExceptionMethode:

Gibt den IOExceptionzuletzt vom zugrunde liegenden Readable dieses Scanners ausgelösten Wert zurück. Diese Methode gibt null zurück, wenn keine solche Ausnahme vorliegt .

In diesem Fall hat der zurückgegebene Wert nulleine klare Bedeutung. Wenn ich die Methode verwende, kann ich sicher sein, dass ich nullnur erhalten habe, weil es keine solche Ausnahme gab und nicht, weil die Methode versucht hat, etwas zu tun, und es fehlgeschlagen ist.

* Beachten Sie, dass Sie manchmal zurückkehren möchten, nullauch wenn die Bedeutung nicht eindeutig ist. Zum Beispiel die HashMap#get:

Ein Rückgabewert von null bedeutet nicht unbedingt, dass die Zuordnung keine Zuordnung für den Schlüssel enthält. Es ist auch möglich, dass die Karte den Schlüssel explizit auf null abbildet . Die containsKeyOperation kann verwendet werden, um diese beiden Fälle zu unterscheiden.

In diesem Fall nullkann angegeben werden, dass der Wert null gefunden und zurückgegeben wurde oder dass die Hashmap den angeforderten Schlüssel nicht enthält.

Maroun
quelle
4
Obwohl Ihre Punkte gültig sind, möchte ich darauf hinweisen, dass dies einfach beschissenes API-Design ist. Beide Methoden sollten jeweils ein Optional<Throwable>oder zurückgeben Optional<TValue>. Hinweis: Dies ist keine Kritik an Ihrer Antwort, sondern am API-Design dieser beiden Methoden. (Es ist jedoch ein ziemlich häufiger Designfehler, der nicht nur in der gesamten Java-API, sondern auch in .NET verbreitet ist.)
Jörg W Mittag,
4
"crappy" ist ziemlich hart, wenn Sie nicht wissen, ob Java 8-Funktionen verwendet werden können oder nicht.
Thorbjørn Ravn Andersen
2
Wenn dies nulljedoch kein gültiger Rückgabewert ist, ist die Rückgabe nulleine noch schlechtere Idee. Mit anderen Worten, eine Rückkehr nullin eine unerwartete Situation ist niemals eine gute Idee.
Holger
1
@Holger Was ich unter ungültig verstehe , ist beispielsweise, wenn der Benutzer erwartet, einen Wert aus einer Datenstruktur zu erhalten, die nicht enthalten kann null, und dann nullniemals ein "gültiger" Rückgabewert in dem Sinne sein kann, dass er etwas anderes als einen normalen angeben muss Rückgabewert. In diesem Fall hat die Rücksendung eine besondere Bedeutung, und ich sehe nichts Falsches an diesem Design (natürlich sollte der Benutzer wissen, wie er mit dieser Situation umgeht).
Maroun
1
Das ist der Punkt: "Der Benutzer sollte wissen, wie er mit dieser Situation umgehen soll" bedeutet, dass Sie angeben müssen, dass dies nullein möglicher Rückgabewert ist, mit dem sich der Anrufer befassen muss. Das macht es zu einem gültigen Wert, und wir haben hier das gleiche Verständnis von "gültig", wie Sie "gültig" beschreiben, wie "der Benutzer es erwartet und es etwas bedeutet". Aber hier ist die Situation trotzdem anders. Das OP gibt pro Codekommentar an, dass er behauptet, dass die return null;Aussage "nicht erreichbar" ist, was impliziert, dass die Rückgabe nullfalsch ist. Es sollte throw new AssertionError();stattdessen ein…
Holger
26

Ist es eine schlechte Praxis, die zusätzliche return-Anweisung am Ende einzufügen, um die Syntax zu erfüllen und Kompilierungsfehler zu vermeiden (mit einem Kommentar, der erklärt, dass sie nicht erreicht wird)?

Ich denke, es return nullist eine schlechte Praxis für die Endstation eines nicht erreichbaren Zweigs. Es ist besser, ein zu werfen RuntimeException( AssertionErrorwäre auch akzeptabel), um an diese Zeile zu gelangen. Etwas ist sehr schief gelaufen und die Anwendung befindet sich in einem unbekannten Zustand. Am ähnlichsten ist dies (wie oben), weil der Entwickler etwas übersehen hat (Objekte können nicht null und nicht klonbar sein).

Ich würde es wahrscheinlich nicht verwenden, es InternalErrorsei denn, ich bin mir sehr sicher, dass der Code nicht erreichbar ist (zum Beispiel nach a System.exit()), da es wahrscheinlicher ist, dass ich einen Fehler mache als die VM.

Ich würde nur eine benutzerdefinierte Ausnahme (z. B. TotallyFooException) verwenden, wenn das Erreichen dieser "nicht erreichbaren Zeile" dasselbe bedeutet wie überall, wo Sie diese Ausnahme auslösen.

Michael Lloyd Lee mlk
quelle
3
Wie an anderer Stelle in den Kommentaren erwähnt, AssertionErrorkönnte ein auch eine vernünftige Wahl sein, um ein "Kann nicht passieren" -Ereignis auszulösen.
Ilmari Karonen
2
Persönlich würde ich eine werfen SomeJerkImplementedClonableAndStillThrewACloneNotSupportedExceptionException. Es würde sich RuntimeExceptionnatürlich erstrecken.
25.
@ w25r Ich verwende nicht den obigen Code, sondern beantworte die zugrunde liegende Frage. Gegeben Cloneableimplementiert keine öffentliche clone()Methode und clone()im Objekt wird protectedder obige Code nicht tatsächlich kompiliert.
Michael Lloyd Lee mlk
Ich würde keine passiv-aggressive Ausnahme verwenden, nur für den Fall, dass sie entkommt (so lustig es für einen unserer Kunden wäre, eine zu bekommen JerkException, ich glaube nicht, dass es geschätzt wird).
Michael Lloyd Lee mlk
14

Sie haben das gefangen, CloneNotSupportedExceptionwas bedeutet, dass Ihr Code damit umgehen kann. Aber nachdem Sie es verstanden haben, haben Sie buchstäblich keine Ahnung, was Sie tun sollen, wenn Sie das Ende der Funktion erreicht haben, was bedeutet, dass Sie damit nicht umgehen konnten. Sie haben also Recht, dass es in diesem Fall nach Code riecht, und meiner Ansicht nach bedeutet dies, dass Sie nicht hätten fangen sollen CloneNotSupportedException.

Djechlin
quelle
12

Ich würde es vorziehen, Objects.requireNonNull()zu überprüfen, ob der Parameter a nicht null ist. Wenn Sie den Code lesen, ist klar, dass der Parameter nicht null sein sollte.

Und um geprüfte Ausnahmen zu vermeiden, würde ich das CloneNotSupportedExceptionals werfen RuntimeException.

Für beide könnten Sie einen schönen Text hinzufügen, mit der Absicht, warum dies nicht passieren sollte oder der Fall sein sollte.

public Object getClone(Object a) {

    Objects.requireNonNull(a);

    try {
        return a.clone();
    } catch (CloneNotSupportedException e) {
        throw new IllegalArgumentException(e);
    }

}
Kuchi
quelle
7

In einer solchen Situation würde ich schreiben

public Object getClone(SomeInterface a) throws TotallyFooException {
    // Precondition: "a" should be null or should have a someMethod method that
    // does not throw a SomeException.
    if (a == null) {
        throw new TotallyFooException() ; }
    else {
        try {
            return a.someMethod(); }
        catch (SomeException e) {
            throw new IllegalArgumentException(e) ; } }
}

Interessanterweise sagen Sie, dass die "try-Anweisung niemals fehlschlagen wird", aber Sie haben sich trotzdem die Mühe gemacht, eine Anweisung zu schreiben e.printStackTrace();, von der Sie behaupten, dass sie niemals ausgeführt wird. Warum?

Vielleicht ist Ihr Glaube nicht so fest. Das ist gut (meiner Meinung nach), da Ihre Überzeugung nicht auf dem von Ihnen geschriebenen Code basiert, sondern auf der Erwartung, dass Ihr Kunde die Voraussetzung nicht verletzt. Besser öffentliche Methoden defensiv programmieren.

Ihr Code wird übrigens nicht für mich kompiliert. Sie können nicht anrufen, a.clone()auch wenn der Typ aist Cloneable. Zumindest der Compiler von Eclipse sagt dies. Ausdruck a.clone()gibt Fehler

Die Methode clone () ist für den Typ Cloneable nicht definiert

Was ich für Ihren speziellen Fall tun würde, ist

public Object getClone(PubliclyCloneable a) throws TotallyFooException {
    if (a == null) {
        throw new TotallyFooException(); }
    else {
        return a.clone(); }
}

Wo PubliclyCloneableist definiert durch

interface PubliclyCloneable {
    public Object clone() ;
}

Wenn Sie den Parametertyp unbedingt benötigen Cloneable, wird zumindest Folgendes kompiliert.

public static Object getClone(Cloneable a) throws TotallyFooException {
//  Precondition: "a" should be null or point to an object that can be cloned without
// throwing any checked exception.
    if (a == null) {
        throw new TotallyFooException(); }
    else {
        try {
            return a.getClass().getMethod("clone").invoke(a) ; }
        catch( IllegalAccessException e ) {
            throw new AssertionError(null, e) ; }
        catch( InvocationTargetException e ) {
            Throwable t = e.getTargetException() ;
            if( t instanceof Error ) {
                // Unchecked exceptions are bubbled
                throw (Error) t ; }
            else if( t instanceof RuntimeException ) {
                // Unchecked exceptions are bubbled
                throw (RuntimeException) t ; }
            else {
                // Checked exceptions indicate a precondition violation.
                throw new IllegalArgumentException(t) ; } }
        catch( NoSuchMethodException e ) {
            throw new AssertionError(null, e) ; } }
}
Theodore Norvell
quelle
Der Fehler beim Kompilieren hat mich dazu gebracht, mich zu fragen, warum Cloneablenicht cloneals öffentliche Methode deklariert wird, die keine überprüften Ausnahmen auslöst. Es gibt eine interessante Diskussion unter bugs.java.com/view_bug.do?bug_id=4098033
Theodore Norvell
2
Ich möchte erwähnen, dass die überwiegende Mehrheit des Java-Codes keine Lisp-ähnlichen Klammern verwendet und Sie ein schmutziges Aussehen erhalten, wenn Sie versuchen, dies in einer Jobumgebung zu verwenden.
Fund Monica Klage
1
Dank dafür. Eigentlich war ich nicht sehr konsequent. Ich habe die Antwort bearbeitet, um meinen bevorzugten Klammerstil konsequent zu verwenden.
Theodore Norvell
6

Die obigen Beispiele sind gültig und sehr Java. Hier ist jedoch, wie ich die Frage des OP zum Umgang mit dieser Rückgabe beantworten würde:

public Object getClone(Cloneable a) throws CloneNotSupportedException {
    return a.clone();
}

Es hat keinen Vorteil zu überprüfen a, ob es null ist. Es geht um NPE. Das Drucken einer Stapelverfolgung ist ebenfalls nicht hilfreich. Die Stapelverfolgung ist unabhängig davon, wo sie verarbeitet wird, dieselbe.

Es hat keinen Vorteil, den Code mit nicht hilfreichen Nulltests und nicht hilfreicher Ausnahmebehandlung zu verschrotten. Durch das Entfernen des Mülls ist das Rückgabeproblem umstritten.

(Beachten Sie, dass das OP einen Fehler in die Ausnahmebehandlung aufgenommen hat. Aus diesem Grund war die Rückgabe erforderlich. Das OP hätte die von mir vorgeschlagene Methode nicht falsch verstanden.)

Tony Ennis
quelle
5

Ist es eine schlechte Praxis, eine return-Anweisung zu haben, um die Syntax zu erfüllen?

Wie bereits erwähnt, gilt dies in Ihrem Fall nicht.

Um die Frage zu beantworten, haben Lint-Programme es sicher nicht herausgefunden! Ich habe zwei verschiedene gesehen, die sich in einer switch-Anweisung darum gestritten haben.

    switch (var)
   {
     case A:
       break;
     default:
       return;
       break;    // Unreachable code.  Coding standard violation?
   }

Man beklagte sich darüber, dass das Nichteinhalten der Pause eine Verletzung des Kodierungsstandards sei. Der andere beklagte sich darüber, dass es einer war, weil es nicht erreichbarer Code war.

Ich bemerkte dies, weil zwei verschiedene Programmierer den Code immer wieder eincheckten, wobei die Unterbrechung hinzugefügt, dann entfernt und dann entfernt wurde, je nachdem, welchen Codeanalysator sie an diesem Tag ausgeführt hatten.

Wenn Sie in dieser Situation enden, wählen Sie eine aus und kommentieren Sie die Anomalie, die die gute Form ist, die Sie sich gezeigt haben. Das ist der beste und wichtigste Imbiss.

Jos
quelle
5

Es geht nicht nur darum, die Syntax zu erfüllen. Es ist eine semantische Anforderung der Sprache, dass jeder Codepfad zu einer Rückkehr oder einem Wurf führt. Dieser Code entspricht nicht. Wenn die Ausnahme abgefangen wird, ist eine folgende Rückgabe erforderlich.

Keine "schlechte Praxis" darüber oder darüber, den Compiler im Allgemeinen zufrieden zu stellen.

Egal ob Syntax oder Semantik, Sie haben keine Wahl.

Marquis von Lorne
quelle
2

Ich würde dies umschreiben, um die Rückkehr am Ende zu haben. Pseudocode:

if a == null throw ...
// else not needed, if this is reached, a is not null
Object b
try {
  b = a.clone
}
catch ...

return b
Pablo Pazos
quelle
Als verwandte Randnotiz können Sie Ihren Code fast immer so umgestalten, dass die return-Anweisung am Ende steht. Tatsächlich ist dies ein guter Codierungsstandard, da der Code ein wenig einfacher zu warten und Fehler zu beheben ist, da Sie nicht viele Exit-Punkte berücksichtigen müssen. Aus dem gleichen Grund ist es auch empfehlenswert, alle Variablen zu Beginn der Methode zu deklarieren. Bedenken Sie auch, dass für die Rückgabe am Ende möglicherweise mehr Variablen deklariert werden müssen, wie in meiner Lösung, ich benötigte die zusätzliche Variable "Objekt b".
Pablo Pazos
2

Das hat noch niemand erwähnt.

public static final Object ERROR_OBJECT = ...

//...

public Object getClone(Cloneable a) throws TotallyFooException {
Object ret;

if (a == null) 
    throw new TotallyFooException();

//no need for else here
try {
    ret = a.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
    //something went wrong! ERROR_OBJECT could also be null
    ret = ERROR_OBJECT; 
}

return ret;

}

Ich mag returnInnenblöcke aus trygenau diesem Grund nicht.

rath
quelle
2

Die Rückgabe null; Dies ist erforderlich, da möglicherweise eine Ausnahme abgefangen wird. In einem solchen Fall haben wir jedoch bereits überprüft, ob sie null ist (und wir nehmen an, dass die von uns aufgerufene Klasse das Klonen unterstützt), sodass wir wissen, dass die try-Anweisung niemals fehlschlagen wird.

Wenn Sie Details zu den Eingaben so kennen, dass Sie wissen, dass die tryAnweisung niemals fehlschlagen kann, wozu ist sie dann sinnvoll? Vermeiden Sie das, trywenn Sie sicher sind, dass die Dinge immer erfolgreich sein werden (obwohl es selten vorkommt, dass Sie während der gesamten Lebensdauer Ihrer Codebasis absolut sicher sein können).

In jedem Fall ist der Compiler leider kein Gedankenleser. Es sieht die Funktion und ihre Eingaben und benötigt angesichts der Informationen, die es hat, diese returnAnweisung unten, so wie Sie sie haben.

Ist es eine schlechte Praxis, die zusätzliche return-Anweisung am Ende einzufügen, um die Syntax zu erfüllen und Kompilierungsfehler zu vermeiden (mit einem Kommentar, der erklärt, dass sie nicht erreicht werden), oder gibt es eine bessere Möglichkeit, so etwas so zu codieren, dass das Extra return-Anweisung ist nicht erforderlich?

Im Gegenteil, ich würde empfehlen, Compiler-Warnungen zu vermeiden, z. B. auch wenn dies eine weitere Codezeile kostet. Sorgen Sie sich hier nicht zu sehr um die Anzahl der Zeilen. Stellen Sie die Zuverlässigkeit der Funktion durch Testen fest und fahren Sie dann fort. returnStellen Sie sich vor, Sie könnten die Aussage weglassen , stellen Sie sich vor, Sie würden ein Jahr später auf diesen Code zurückkommen, und versuchen dann zu entscheiden, ob diese returnAussage unten mehr Verwirrung stiftet als ein Kommentar, in dem die Details aufgeführt sind, warum sie aufgrund möglicher Annahmen weggelassen wurde Machen Sie über die Eingabeparameter. Höchstwahrscheinlich returnwird es einfacher sein, mit der Aussage umzugehen.

Das heißt, speziell zu diesem Teil:

try {
    return a.clone();
} catch (CloneNotSupportedException e) {
   e.printStackTrace();
}
...
//cant be reached, in for syntax
return null;

Ich denke, dass die Einstellung zur Ausnahmebehandlung hier etwas seltsam ist. Im Allgemeinen möchten Sie Ausnahmen an einer Stelle schlucken, an der Sie etwas Sinnvolles haben, das Sie als Antwort tun können.

Sie können sich try/catcheinen Transaktionsmechanismus vorstellen. tryWenn diese Änderungen fehlschlagen und wir in den catchBlock verzweigen , tun Sie dies (was auch immer im catchBlock enthalten ist) als Reaktion auf den Rollback- und Wiederherstellungsprozess.

In diesem Fall ist das bloße Drucken eines Stacktraces und das anschließende Zurückgeben von Null nicht gerade eine Transaktions- / Wiederherstellungs-Denkweise. Der Code überträgt die Verantwortung für die Fehlerbehandlung auf alle Code-Aufrufe, getCloneum manuell nach Fehlern zu suchen. Möglicherweise möchten Sie die CloneNotSupportedExceptionAusnahme lieber abfangen und in eine andere, aussagekräftigere Form der Ausnahme übersetzen und diese auslösen. In diesem Fall möchten Sie die Ausnahme jedoch nicht einfach verschlucken und eine Null zurückgeben, da dies nicht wie eine Transaktionswiederherstellungssite ist.

Sie verlieren am Ende die Verantwortung für die Anrufer, Fehler manuell zu überprüfen und auf diese Weise zu behandeln, wenn das Auslösen einer Ausnahme dies vermeiden würde.

Wenn Sie eine Datei laden, ist dies die Transaktion auf hoher Ebene. Sie könnten eine try/catchdort haben. Während des tryingLadens einer Datei können Sie Objekte klonen. Wenn irgendwo in dieser übergeordneten Operation (Laden der Datei) ein Fehler auftritt, möchten Sie normalerweise Ausnahmen bis zu diesem Transaktionsblock der obersten Ebene zurückwerfen, try/catchdamit Sie einen Fehler beim Laden einer Datei ordnungsgemäß beheben können (unabhängig davon, ob dies der Fall ist) aufgrund eines Fehlers beim Klonen oder irgendetwas anderem). Daher möchten wir im Allgemeinen nicht einfach eine Ausnahme an einer bestimmten Stelle wie dieser verschlucken und dann eine Null zurückgeben, z. B. da dies einen Großteil des Werts und Zwecks von Ausnahmen zunichte machen würde. Stattdessen möchten wir Ausnahmen bis zu einer Site weitergeben, an der wir sinnvoll damit umgehen können.

Drachenenergie
quelle
0

Ihr Beispiel ist nicht ideal, um Ihre Frage zu veranschaulichen, wie im letzten Absatz angegeben:

Ist es eine schlechte Praxis, die zusätzliche return-Anweisung am Ende einzufügen, um die Syntax zu erfüllen und Kompilierungsfehler zu vermeiden (mit einem Kommentar, der erklärt, dass sie nicht erreicht werden), oder gibt es eine bessere Möglichkeit, so etwas so zu codieren, dass das Extra return-Anweisung ist nicht erforderlich?

Ein besseres Beispiel wäre die Implementierung des Klons selbst:

 public class A implements Cloneable {
      public Object clone() {
           try {
               return super.clone() ;
           } catch (CloneNotSupportedException e) {
               throw new InternalError(e) ; // vm bug.
           }
      }
 }

Hier sollte die catch-Klausel niemals eingegeben werden. Trotzdem muss die Syntax entweder etwas auslösen oder einen Wert zurückgeben. Da die Rückgabe nicht sinnvoll ist, wird ein InternalErrorverwendet, um auf einen schwerwiegenden VM-Zustand hinzuweisen.

wero
quelle
5
Die Superklasse, die a wirft, CloneNotSupportedExceptionist kein "VM-Bug" - es ist völlig legal, dass a Cloneablees wirft. Es könnte einen Fehler in Ihrem Code und / oder in der Oberklasse darstellen. In diesem Fall könnte es angebracht sein, ihn in einen RuntimeExceptionoder möglicherweise einen AssertionError(aber keinen InternalError) einzuschließen. Oder Sie könnten sich einfach der Ausnahme entziehen - wenn Ihre Oberklasse das Klonen nicht unterstützt, tun Sie dies auch nicht, CloneNotSupportedExceptionwas semantisch angemessen ist.
Ilmari Karonen
@IlmariKaronen Vielleicht möchten Sie diesen Rat an Oracle senden, damit sie alle
Klonmethoden
@wero Jemand hat zweifellos schon, aber das riecht nach altem Code.
Deworde