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?
Object
Parameter. Wenna
es sich nicht um eine Klasse handelt, die dieclone
Methode unterstützt (oder ist dies in definiertObject
?) Oder wenn während derclone
Methode 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.Cloneable
zu werfenCloneNotSupportedException
. Quelle: JavadocsAssertionError
statt gehenInternalError
. 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.Antworten:
Ein klarerer Weg ohne zusätzliche Rückgabeanweisung ist wie folgt. Ich würde es auch nicht fangen
CloneNotSupportedException
, aber es dem Anrufer überlassen.Es ist fast immer möglich, an der Reihenfolge herumzuspielen, um eine geradlinigere Syntax zu erhalten als ursprünglich.
quelle
AssertionError
ist eine eingebaute Klasse mit einer ähnlichen Absicht wieTotallyFooException
(die eigentlich nicht existiert).Es kann definitiv erreicht werden. Beachten Sie, dass Sie nur den Stacktrace in der
catch
Klausel drucken .In dem Szenario , wo
a != null
und es wird eine Ausnahme sein, dasreturn null
wird erreicht werden. Sie können diese Anweisung entfernen und durch ersetzenthrow new TotallyFooException();
.Im Allgemeinen * ist es keine gute Idee , wenn
null
ein 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 solltennull
.Nehmen Sie zum Beispiel die
Scanner#ioException
Methode:In diesem Fall hat der zurückgegebene Wert
null
eine klare Bedeutung. Wenn ich die Methode verwende, kann ich sicher sein, dass ichnull
nur 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,
null
auch wenn die Bedeutung nicht eindeutig ist. Zum Beispiel dieHashMap#get
:In diesem Fall
null
kann angegeben werden, dass der Wertnull
gefunden und zurückgegeben wurde oder dass die Hashmap den angeforderten Schlüssel nicht enthält.quelle
Optional<Throwable>
oder zurückgebenOptional<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.)null
jedoch kein gültiger Rückgabewert ist, ist die Rückgabenull
eine noch schlechtere Idee. Mit anderen Worten, eine Rückkehrnull
in eine unerwartete Situation ist niemals eine gute Idee.null
, und dannnull
niemals 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).null
ein 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 diereturn null;
Aussage "nicht erreichbar" ist, was impliziert, dass die Rückgabenull
falsch ist. Es solltethrow new AssertionError();
stattdessen ein…Ich denke, es
return null
ist eine schlechte Praxis für die Endstation eines nicht erreichbaren Zweigs. Es ist besser, ein zu werfenRuntimeException
(AssertionError
wä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
InternalError
sei denn, ich bin mir sehr sicher, dass der Code nicht erreichbar ist (zum Beispiel nach aSystem.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.quelle
AssertionError
könnte ein auch eine vernünftige Wahl sein, um ein "Kann nicht passieren" -Ereignis auszulösen.SomeJerkImplementedClonableAndStillThrewACloneNotSupportedExceptionException
. Es würde sichRuntimeException
natürlich erstrecken.Cloneable
implementiert keine öffentlicheclone()
Methode undclone()
im Objekt wirdprotected
der obige Code nicht tatsächlich kompiliert.JerkException
, ich glaube nicht, dass es geschätzt wird).Sie haben das gefangen,
CloneNotSupportedException
was 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 sollenCloneNotSupportedException
.quelle
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
CloneNotSupportedException
als werfenRuntimeException
.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.
quelle
In einer solchen Situation würde ich schreiben
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 Typa
istCloneable
. Zumindest der Compiler von Eclipse sagt dies. Ausdrucka.clone()
gibt FehlerWas ich für Ihren speziellen Fall tun würde, ist
Wo
PubliclyCloneable
ist definiert durchWenn Sie den Parametertyp unbedingt benötigen
Cloneable
, wird zumindest Folgendes kompiliert.quelle
Cloneable
nichtclone
als ö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=4098033Die 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:
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.)
quelle
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.
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.
quelle
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.
quelle
Ich würde dies umschreiben, um die Rückkehr am Ende zu haben. Pseudocode:
quelle
Das hat noch niemand erwähnt.
Ich mag
return
Innenblöcke austry
genau diesem Grund nicht.quelle
Wenn Sie Details zu den Eingaben so kennen, dass Sie wissen, dass die
try
Anweisung niemals fehlschlagen kann, wozu ist sie dann sinnvoll? Vermeiden Sie das,try
wenn 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
return
Anweisung unten, so wie Sie sie haben.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.
return
Stellen 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 diesereturn
Aussage 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öchstwahrscheinlichreturn
wird es einfacher sein, mit der Aussage umzugehen.Das heißt, speziell zu diesem Teil:
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/catch
einen Transaktionsmechanismus vorstellen.try
Wenn diese Änderungen fehlschlagen und wir in dencatch
Block verzweigen , tun Sie dies (was auch immer imcatch
Block 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,
getClone
um manuell nach Fehlern zu suchen. Möglicherweise möchten Sie dieCloneNotSupportedException
Ausnahme 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/catch
dort haben. Während destrying
Ladens 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/catch
damit 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.quelle
Ihr Beispiel ist nicht ideal, um Ihre Frage zu veranschaulichen, wie im letzten Absatz angegeben:
Ein besseres Beispiel wäre die Implementierung des Klons selbst:
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
InternalError
verwendet, um auf einen schwerwiegenden VM-Zustand hinzuweisen.quelle
CloneNotSupportedException
ist kein "VM-Bug" - es ist völlig legal, dass aCloneable
es 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 einenRuntimeException
oder möglicherweise einenAssertionError
(aber keinenInternalError
) einzuschließen. Oder Sie könnten sich einfach der Ausnahme entziehen - wenn Ihre Oberklasse das Klonen nicht unterstützt, tun Sie dies auch nicht,CloneNotSupportedException
was semantisch angemessen ist.