Ich habe eine Methode, die ein Objekt zurückgeben soll, wenn es gefunden wird.
Wenn es nicht gefunden wird, sollte ich:
- return null
- eine Ausnahme auslösen
- andere
Ich habe eine Methode, die ein Objekt zurückgeben soll, wenn es gefunden wird.
Wenn es nicht gefunden wird, sollte ich:
Antworten:
Wenn Sie immer erwarten, einen Wert zu finden, lösen Sie die Ausnahme aus, wenn sie fehlt. Die Ausnahme würde bedeuten, dass es ein Problem gab.
Wenn der Wert fehlen oder vorhanden sein kann und beide für die Anwendungslogik gültig sind, geben Sie eine Null zurück.
Wichtiger: Was machen Sie an anderen Stellen im Code? Konsistenz ist wichtig.
GetPersonById(25)
würde werfen, wenn diese Person gelöscht wurde, GetPeopleByHairColor("red")
würde aber ein leeres Ergebnis zurückgeben. Ich denke, die Parameter sagen etwas über die Erwartungen aus.
Eine Ausnahme nur auslösen, wenn es sich wirklich um einen Fehler handelt. Wenn erwartet wird, dass das Verhalten des Objekts nicht vorhanden ist, geben Sie die Null zurück.
Ansonsten ist es eine Frage der Präferenz.
Wenn die Methode immer ein Objekt zurückgeben soll, gehen Sie in der Regel mit der Ausnahme vor. Wenn Sie die gelegentliche Null antizipieren und auf bestimmte Weise damit umgehen möchten, wählen Sie die Null.
Was auch immer Sie tun, ich rate dringend von der dritten Option ab: Rückgabe einer Zeichenfolge mit der Aufschrift "WTF".
Wenn null niemals einen Fehler anzeigt, geben Sie einfach null zurück.
Wenn null immer ein Fehler ist, wird eine Ausnahme ausgelöst.
Wenn null manchmal eine Ausnahme ist, codieren Sie zwei Routinen. Eine Routine löst eine Ausnahme aus und die andere ist eine boolesche Testroutine, die das Objekt in einem Ausgabeparameter zurückgibt, und die Routine gibt eine falsche zurück, wenn das Objekt nicht gefunden wurde.
Es ist schwer, eine Try-Routine zu missbrauchen. Es ist wirklich leicht zu vergessen, nach Null zu suchen.
Wenn also null ein Fehler ist, schreiben Sie einfach
object o = FindObject();
Wenn die Null kein Fehler ist, können Sie so etwas wie codieren
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
find
und findOrFail
von Laravel Eloquent
TryFindObject
Methode zurückgegeben wird? Tupel scheinen eher ein faules Paradigma für Programmierer zu sein, die sich nicht die Zeit nehmen möchten, ein Objekt zu definieren, das mehrere Werte enthält. Das heißt, im Wesentlichen sind sowieso alle Tupel im Kern.
Ich wollte nur die zuvor genannten Optionen zusammenfassen und einige neue hinzufügen:
Oder Sie kombinieren diese Optionen:
Stellen Sie mehrere überladene Versionen Ihres Getters bereit, damit der Anrufer entscheiden kann, welchen Weg er einschlagen möchte. In den meisten Fällen hat nur der erste eine Implementierung des Suchalgorithmus, und die anderen umschließen nur den ersten:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
Selbst wenn Sie nur eine Implementierung bereitstellen, möchten Sie möglicherweise eine solche Namenskonvention verwenden, um Ihren Vertrag zu verdeutlichen. Dies hilft Ihnen, falls Sie sich jemals dazu entschließen sollten, auch andere Implementierungen hinzuzufügen.
Sie sollten es nicht überbeanspruchen, aber es kann hilfreich sein, insbesondere beim Schreiben einer Hilfsklasse, die Sie in Hunderten verschiedener Anwendungen mit vielen verschiedenen Konventionen zur Fehlerbehandlung verwenden.
Expected<T> findObject(String)
wo Expected<T>
die Funktionen hat orNull()
, orThrow()
, orSupplied(Supplier<T> supplier)
, orDefault(T default)
. Dies abstrahiert das
Verwenden Sie das Nullobjektmuster oder lösen Sie eine Ausnahme aus.
Person somePerson = personRepository.find("does-not-exist");
diese Methode gibt ein Nullobjekt für die ID zurück does-not-exist
. Wofür wäre dann das richtige Verhalten somePerson.getAge()
? Derzeit bin ich noch nicht davon überzeugt, dass das Nullobjektmuster die richtige Lösung für die Suche nach Entitäten ist.
Vorteile einer Ausnahme:
Weitere Erläuterungen mit Beispielen finden Sie unter: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
Es hängt davon ab, ob Ihre Sprache und Ihr Code für Folgendes werben: LBYL (schauen Sie, bevor Sie springen) oder EAFP (leichter um Vergebung zu bitten als um Erlaubnis)
LBYL sagt, Sie sollten nach Werten suchen (also eine Null zurückgeben)
EAFP sagt, Sie sollen einfach die Operation versuchen und sehen, ob sie fehlschlägt (eine Ausnahme ).
obwohl ich oben einverstanden bin .. Ausnahmen sollten für Ausnahme- / Fehlerbedingungen verwendet werden, und die Rückgabe einer Null ist am besten, wenn Prüfungen verwendet werden.
EAFP vs. LBYL in Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html
( Webarchiv )
Fragen Sie sich einfach: "Ist es ein Ausnahmefall, dass das Objekt nicht gefunden wird?" Wenn dies im normalen Verlauf Ihres Programms erwartet wird, sollten Sie wahrscheinlich keine Ausnahme auslösen (da es sich nicht um ein außergewöhnliches Verhalten handelt).
Kurzversion: Verwenden Sie Ausnahmen, um außergewöhnliches Verhalten zu behandeln, nicht um den normalen Kontrollfluss in Ihrem Programm zu behandeln.
-Alan.
Ausnahmen beziehen sich auf Design by Contract.
Die Schnittstelle eines Objekts ist eigentlich ein Vertrag zwischen zwei Objekten, der Anrufer muss den Vertrag erfüllen, sonst kann der Empfänger nur mit einer Ausnahme ausfallen. Es gibt zwei mögliche Verträge
1) Alle Eingaben der Methode sind gültig. In diesem Fall müssen Sie null zurückgeben, wenn das Objekt nicht gefunden wird.
2) nur eine Eingabe ist gültig, dh die, die zu einem gefundenen Objekt führt. In diesem Fall MÜSSEN Sie eine zweite Methode anbieten, mit der der Anrufer feststellen kann, ob die Eingabe korrekt ist. Zum Beispiel
is_present(key)
find(key) throws Exception
WENN und NUR WENN Sie beide Methoden des 2. Vertrages angeben, dürfen Sie eine Ausnahme auslösen, wenn nichts gefunden wird!
Ich ziehe es vor, nur eine Null zurückzugeben und mich darauf zu verlassen, dass der Anrufer angemessen damit umgeht. Die (mangels eines besseren Wortes) Ausnahme ist, wenn ich absolut "sicher" bin, dass diese Methode ein Objekt zurückgibt. In diesem Fall ist ein Fehler ein außergewöhnliches sollte und sollte werfen.
Kommt darauf an, was es bedeutet, dass das Objekt nicht gefunden wird.
Wenn es sich um einen normalen Zustand handelt, geben Sie null zurück. Dies ist nur etwas, das gelegentlich passieren kann, und die Anrufer sollten es überprüfen.
Wenn es sich um einen Fehler handelt, lösen Sie eine Ausnahme aus. Die Aufrufer sollten entscheiden, was mit der Fehlerbedingung eines fehlenden Objekts geschehen soll.
Letztendlich würde beides funktionieren, obwohl die meisten Leute es im Allgemeinen für eine gute Praxis halten, Ausnahmen nur dann zu verwenden, wenn etwas Außergewöhnliches passiert ist.
Hier noch ein paar Vorschläge.
Wenn Sie eine Sammlung zurückgeben, vermeiden Sie die Rückgabe von null. Geben Sie eine leere Sammlung zurück, wodurch die Aufzählung ohne vorherige Nullprüfung einfacher zu handhaben ist.
Mehrere .NET-APIs verwenden das Muster eines throwOnError-Parameters, der dem Aufrufer die Wahl lässt, ob es sich wirklich um eine Ausnahmesituation handelt oder nicht, wenn das Objekt nicht gefunden wird. Type.GetType ist ein Beispiel dafür. Ein weiteres häufiges Muster bei BCL ist das TryGet-Muster, bei dem ein Boolescher Wert zurückgegeben und der Wert über einen Ausgabeparameter übergeben wird.
Unter bestimmten Umständen können Sie auch das Nullobjektmuster berücksichtigen, das entweder eine Standardversion oder eine Version ohne Verhalten sein kann. Der Schlüssel ist, Nullprüfungen in der gesamten Codebasis zu vermeiden. Weitere Informationen finden Sie hier http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
In einigen Funktionen füge ich einen Parameter hinzu:
..., bool verify = true)
True bedeutet werfen, false bedeutet, einen Fehlerrückgabewert zurückzugeben. Auf diese Weise hat jeder, der diese Funktion verwendet, beide Optionen. Der Standardwert sollte true sein, zum Nutzen derer, die die Fehlerbehandlung vergessen.
Geben Sie eine Null zurück, anstatt eine Ausnahme auszulösen, und dokumentieren Sie die Möglichkeit eines Null-Rückgabewerts in der API-Dokumentation. Wenn der aufrufende Code die API nicht berücksichtigt und nach dem Nullfall sucht, führt dies höchstwahrscheinlich ohnehin zu einer Art "Nullzeigerausnahme" :)
In C ++ kann ich mir drei verschiedene Varianten des Einrichtens einer Methode vorstellen, die ein Objekt findet.
Option A.
Object *findObject(Key &key);
Gibt null zurück, wenn ein Objekt nicht gefunden werden kann. Schön und einfach. Ich würde mit diesem gehen. Die folgenden alternativen Ansätze richten sich an Personen, die Out-Params nicht hassen.
Option B.
void findObject(Key &key, Object &found);
Übergeben Sie einen Verweis auf eine Variable, die das Objekt empfangen soll. Die Methode hat eine Ausnahme ausgelöst, wenn ein Objekt nicht gefunden werden kann. Diese Konvention ist wahrscheinlich besser geeignet, wenn nicht wirklich erwartet wird, dass ein Objekt nicht gefunden wird. Daher wird eine Ausnahme ausgelöst, um anzuzeigen, dass es sich um einen unerwarteten Fall handelt.
Option C.
bool findObject(Key &key, Object &found);
Die Methode gibt false zurück, wenn ein Objekt nicht gefunden werden kann. Der Vorteil gegenüber Option A besteht darin, dass Sie in einem klaren Schritt nach dem Fehlerfall suchen können:
if (!findObject(myKey, myObj)) { ...
Ich beziehe mich nur auf den Fall, in dem null nicht als außergewöhnliches Verhalten angesehen wird. Ich bin definitiv für die try-Methode. Es ist klar, dass Sie nicht "das Buch lesen" oder "schauen müssen, bevor Sie springen", wie hier gesagt wurde
also im Grunde genommen:
bool TryFindObject(RequestParam request, out ResponseParam response)
und dies bedeutet, dass der Code des Benutzers ebenfalls klar ist
...
if(TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
Im Allgemeinen sollte null zurückgegeben werden. Der Code, der die Methode aufruft, sollte entscheiden, ob eine Ausnahme ausgelöst oder etwas anderes versucht werden soll.
Oder geben Sie eine Option zurück
Eine Option ist im Grunde eine Containerklasse, die den Kunden zwingt, Standfälle zu bearbeiten. Scala hat dieses Konzept, schauen Sie sich die API an.
Dann haben Sie Methoden wie T getOrElse (T valueIfNull) für dieses Objekt, die entweder das gefundene Objekt oder eine vom Client angegebene Allternative zurückgeben.
Leider ist JDK inkonsistent. Wenn Sie versuchen, auf einen nicht vorhandenen Schlüssel im Ressourcenpaket zuzugreifen, wird keine Ausnahme gefunden. Wenn Sie einen Wert von map anfordern, erhalten Sie null, wenn dieser nicht vorhanden ist. Daher würde ich die Antwort des Gewinners wie folgt ändern: Wenn der gefundene Wert null sein kann, dann eine Ausnahme auslösen, wenn er nicht gefunden wird, andernfalls null zurückgeben. Befolgen Sie also die Regel mit einer Ausnahme. Wenn Sie wissen möchten, warum der Wert nicht gefunden wird, lösen Sie immer eine Ausnahme aus.
Solange ein Verweis auf das Objekt zurückgegeben werden soll, sollte die Rückgabe von NULL gut sein.
Wenn es jedoch das ganze blutige Ding zurückgibt (wie in C ++, wenn Sie dies tun: 'return bla;' anstatt 'return & bla;' (oder 'bla' ist ein Zeiger), können Sie kein NULL zurückgeben, weil es ist nicht vom Typ 'Objekt'. In diesem Fall würde ich das Problem lösen, indem ich eine Ausnahme auslöse oder ein leeres Objekt zurückgebe, für das kein Erfolgsflag gesetzt ist.
Denken Sie nicht, dass irgendjemand den Overhead bei der Ausnahmebehandlung erwähnt hat - benötigt zusätzliche Ressourcen zum Laden und Verarbeiten der Ausnahme. Wenn es sich also nicht um ein echtes App-Killing- oder Prozessstopp-Ereignis handelt (in Zukunft würde dies mehr schaden als nützen), würde ich mich dafür entscheiden, a zurückzugeben Wert, den die aufrufende Umgebung nach eigenem Ermessen interpretieren könnte.
Ich stimme dem Konsens hier zu (geben Sie null zurück, wenn "nicht gefunden" ein normales mögliches Ergebnis ist, oder lösen Sie eine Ausnahme aus, wenn die Semantik der Situation erfordert, dass das Objekt immer gefunden wird).
Es gibt jedoch eine dritte Möglichkeit, die je nach Ihrer speziellen Situation sinnvoll sein kann. Ihre Methode könnte ein Standardobjekt in der Bedingung "nicht gefunden" zurückgeben, sodass der aufrufende Code sicher sein kann, dass er immer ein gültiges Objekt empfängt, ohne dass eine Nullprüfung oder ein Ausnahmefangen erforderlich ist.
Ausnahmen sollten außergewöhnlich sein . Geben Sie null zurück, wenn es gültig ist, eine Null zurückzugeben .
Wenn die Methode eine Sammlung zurückgibt, geben Sie eine leere Sammlung zurück (wie oben angegeben). Aber bitte nicht Collections.EMPTY_LIST oder so! (im Fall von Java)
Wenn die Methode ein einzelnes Objekt abruft, haben Sie einige Optionen.
Seien Sie vorsichtig, wenn Sie eine Null zurückgeben möchten. Wenn Sie nicht der einzige Programmierer im Projekt sind, erhalten Sie zur Laufzeit NullPointerExceptions (in Java oder was auch immer in anderen Sprachen)! Geben Sie also keine Nullen zurück, die beim Kompilieren nicht überprüft werden.
null
. Weitere Informationen finden Sie in der Antwort mit der höchsten Bewertung.
Wenn Sie eine Bibliothek oder eine andere Klasse verwenden, die eine Ausnahme auslöst , sollten Sie erneut werfen sie erneut . Hier ist ein Beispiel. Example2.java ist wie eine Bibliothek und Example.java verwendet das Objekt. Main.java ist ein Beispiel für diese Ausnahme. Sie sollten dem Benutzer auf der aufrufenden Seite eine aussagekräftige Nachricht und (falls erforderlich) eine Stapelverfolgung anzeigen.
Main.java
public class Main {
public static void main(String[] args) {
Example example = new Example();
try {
Example2 obj = example.doExample();
if(obj == null){
System.out.println("Hey object is null!");
}
} catch (Exception e) {
System.out.println("Congratulations, you caught the exception!");
System.out.println("Here is stack trace:");
e.printStackTrace();
}
}
}
Beispiel.java
/**
* Example.java
* @author Seval
* @date 10/22/2014
*/
public class Example {
/**
* Returns Example2 object
* If there is no Example2 object, throws exception
*
* @return obj Example2
* @throws Exception
*/
public Example2 doExample() throws Exception {
try {
// Get the object
Example2 obj = new Example2();
return obj;
} catch (Exception e) {
// Log the exception and rethrow
// Log.logException(e);
throw e;
}
}
}
Beispiel2.java
/**
* Example2.java
* @author Seval
*
*/
public class Example2 {
/**
* Constructor of Example2
* @throws Exception
*/
public Example2() throws Exception{
throw new Exception("Please set the \"obj\"");
}
}
Das hängt wirklich davon ab, ob Sie erwarten, das Objekt zu finden oder nicht. Wenn Sie der Denkschule folgen, dass Ausnahmen verwendet werden sollten, um etwas anzuzeigen, dann ist eine Ausnahme aufgetreten:
Andernfalls geben Sie null zurück.