Sollte eine Abrufmethode „null“ zurückgeben oder eine Ausnahme auslösen, wenn sie den Rückgabewert nicht erzeugen kann?[geschlossen]

StackOverflow https://stackoverflow.com/questions/175532

  •  05-07-2019
  •  | 
  •  

Frage

Ich habe eine Methode, die ein Objekt zurückgeben soll, wenn es gefunden wird.

Wenn es nicht gefunden wird, sollte ich:

  1. null zurückgeben
  2. eine Ausnahme auslösen
  3. andere
War es hilfreich?

Lösung

Wenn Sie immer erwarten, einen Wert zu finden, werfen Sie die Ausnahme, wenn sie fehlt. Die Ausnahme würde bedeuten, dass es ein Problem gab.

Wenn der Wert fehlt oder vorhanden sein kann und beide für die Anwendungslogik gültig sind, geben Sie einen Null zurück.

Wichtiger: Was machen Sie andere Orte im Code? Konsistenz ist wichtig.

Andere Tipps

Wirf nur eine Ausnahme, wenn es wirklich ein Fehler ist. Wenn es erwartet wird, dass das Objekt nicht existiert, geben Sie den Null zurück.

Ansonsten ist es eine Frage der Präferenz.

Wenn die Methode immer ein Objekt zurückgeben sollte, gehen Sie in der Regel mit der Ausnahme. Wenn Sie gelegentlich Null erwarten und auf eine bestimmte Weise damit umgehen möchten, gehen Sie mit dem Null.

Was auch immer Sie tun, rate ich sehr gegen die dritte Option: eine Zeichenfolge mit der Aufschrift "WTF" zurückzugeben.

Wenn Null niemals einen Fehler angibt, geben Sie einfach NULL zurück.

Wenn Null immer ein Fehler ist, geben Sie eine Ausnahme.

Wenn Null manchmal eine Ausnahme ist, codieren Sie zwei Routinen. Eine Routine bringt eine Ausnahme aus und die andere ist eine boolesche Testroutine, die das Objekt in einem Ausgabeparameter zurückgibt, und die Routine gibt ein Falsch zurück, wenn das Objekt nicht gefunden wurde.

Es ist schwer, eine Versuchsroutine zu missbrauchen. Es ist wirklich leicht zu vergessen, nach Null zu suchen.

Wenn Null ein Fehler ist, schreiben Sie gerade

object o = FindObject();

Wenn der 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

Ich wollte nur die zuvor genannten Optionen zusammenfassen und einige neue hinzufügen:

  1. null zurückgeben
  2. eine Ausnahme auslösen
  3. Verwenden Sie das Nullobjektmuster
  4. Stellen Sie Ihrer Methode einen booleschen Parameter zur Verfügung, damit der Aufrufer auswählen kann, ob Sie eine Ausnahme auslösen möchten
  5. Geben Sie einen zusätzlichen Parameter an, damit der Aufrufer einen Wert festlegen kann, den er zurückerhält, wenn kein Wert gefunden wird

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 verfügt nur der erste über eine Implementierung des Suchalgorithmus, und die anderen umschließen einfach 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 sich dafür entscheiden, nur eine Implementierung bereitzustellen, möchten Sie möglicherweise eine solche Namenskonvention verwenden, um Ihren Vertrag zu verdeutlichen, und sie hilft Ihnen, falls Sie sich jemals dazu entschließen, auch andere Implementierungen hinzuzufügen.

Sie sollten es nicht übermäßig verwenden, aber es kann hilfreich sein, insbesondere beim Schreiben einer Hilfsklasse, die Sie in Hunderten verschiedener Anwendungen mit vielen verschiedenen Fehlerbehandlungskonventionen verwenden.

Verwenden Sie das Null -Objektmuster oder geben Sie eine Ausnahme.

Seien Sie mit den von Ihnen verwendeten API (en) überein.

Fragen Sie sich einfach: "Ist es ein außergewöhnlicher Fall, dass das Objekt nicht gefunden wird?" Wenn erwartet wird, dass es im normalen Verlauf Ihres Programms geschieht, sollten Sie wahrscheinlich keine Ausnahme ansprechen (da es sich nicht um ein außergewöhnliches Verhalten handelt).

Kurzversion: Verwenden Sie Ausnahmen, um ein außergewöhnliches Verhalten zu bewältigen und den normalen Kontrollfluss in Ihrem Programm nicht zu bewältigen.

-Alan.

Es hängt davon ab, ob Ihre Sprache und Ihr Code fördern: LBYL (schauen, bevor Sie springen) oder EAFP (leichter zu bitten um Vergebung als die Erlaubnis)

LBYL sagt, Sie sollten Werte überprüfen (also geben Sie ein Null zurück)
EAFP sagt, sie soll nur die Operation ausprobieren und prüfen, ob sie fehlschlägt (werfen Sie eine Ausnahme aus)

Obwohl ich oben zustimme, sollten Ausnahmen für außergewöhnliche/fehlerhafte Bedingungen verwendet werden, und die Rückgabe eines Nulls ist am besten bei der Verwendung von Schecks.


EAFP gegen LBYL in Python:
http://mail.python.org/pipermail/python-list/2003-may/205182.html (Webarchiv)

Vorteile eines Ausnahmees: Ausnahme:

  1. Reiniger Steuerfluss in Ihrem Anrufcode. Durch die Überprüfung nach Null wird ein bedingter Zweig injiziert, der durch Versuch/Fang nativ behandelt wird. Überprüfen Sie nach Null nicht, wonach Sie sich überprüfen. Überprüfen Sie nach NULL, da Sie nach einem Fehler suchen, den Sie erwarten, oder prüfen Sie nach Null, damit Sie es nicht weiter auf Downchain weitergeben ?
  2. Entfernt Unklarheit darüber, was "Null" bedeutet. Ist Null repräsentativ für einen Fehler oder ist Null, was tatsächlich im Wert gespeichert wird? Schwer zu sagen, wenn Sie nur eine Sache haben, um diese Entschlossenheit zu stützen.
  3. Verbesserte Konsistenz zwischen Methodenverhalten in einer Anwendung. Ausnahmen werden in der Regel in Methodensignaturen aufgedeckt, sodass Sie mehr verstehen können, auf welche Kantenfälle die Methoden in einer Anwendung berücksichtigen und auf welche Informationen Ihre Anwendung auf vorhersehbare Weise reagieren kann.

Weitere Erläuterungen mit Beispielen finden Sie unter: http://metatations.com/2011/11/17/returning-null-vs-wing-an-exception/

Ausnahmen beziehen sich auf das Design durch Vertrag.

Die Schnittstelle eines Objekts ist tatsächlich ein Vertrag zwischen zwei Objekten, der Anrufer muss den Vertrag erfüllen oder der Empfänger kann nur mit Ausnahme fehlschlagen. Es gibt zwei mögliche Verträge

1) Alle Eingaben Die Methode ist gültig. In diesem Fall müssen Sie Null zurückgeben, wenn das Objekt nicht gefunden wird.

2) Nur einige Eingaben sind gültig, dh das, was 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. Vertrags bereitstellen, dürfen Sie eine Ausnahme auswerfen, die nichts gefunden wird!

Ich ziehe es vor, nur einen Null zurückzugeben und mich auf den Anrufer zu verlassen, um ihn angemessen zu behandeln. Die (mangelnde Ausnahme eines besseren Wortes) ist, wenn ich absolut 'bestimmt' bin, diese Methode gibt ein Objekt zurück. In diesem Fall ist ein Versagen ein außergewöhnliches sollte und sollte werfen.

Hängt davon ab, was es bedeutet, dass das Objekt nicht gefunden wird.

Wenn es sich um einen normalen Zustand handelt, kehren Sie Null zurück. Dies ist nur etwas, was hin und wieder passieren könnte, und die Anrufer sollten sich danach überprüfen.

Wenn es sich um einen Fehler handelt, werfen Sie eine Ausnahme aus, die Anrufer sollten entscheiden, was mit der Fehlerbedingung des fehlenden Objekts zu tun ist.

Letztendlich würde beide funktionieren, obwohl die meisten Menschen es im Allgemeinen für eine gute Praxis betrachten, nur Ausnahmen zu verwenden, wenn etwas außergewöhnlich passiert ist.

Hier sind ein paar weitere Vorschläge.

Wenn Sie eine Sammlung zurückgeben, vermeiden Sie die Rückgabe von NULL, geben Sie eine leere Sammlung zurück, mit der die Aufzählung zuerst ohne Null -Check zu tun hat.

Mehrere .NET -API verwenden das Muster eines geworfenen Parameters, der dem Anrufer die Wahl gibt, ob es sich wirklich um eine außergewöhnliche Situation handelt oder nicht, wenn das Objekt nicht gefunden wird. Type.gettype ist ein Beispiel dafür. Ein weiteres gemeinsames Muster mit BCL ist das Tryget -Muster, bei dem ein Boolescher zurückgegeben wird und der Wert über einen Ausgangsparameter übergeben wird.

Sie können das Null -Objektmuster auch unter bestimmten Umständen berücksichtigen, die entweder eine Standardeinstellung oder eine Version ohne Verhalten sein können. Der Schlüssel ist, dass Null -Checks in der gesamten Codebasis vermieden werden. 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 Means Throw, falsche bedeutet, einen Fehler zurückzugeben. Auf diese Weise hat derjenige, der diese Funktion nutzt, beide Optionen. Der Standard sollte wahr sein, zum Nutzen derer, die die Fehlerbehandlung vergessen.

Gibt einen Null zurück, anstatt eine Ausnahme zu werfen, und dokumentieren Sie die Möglichkeit eines Null -Return -Werts in der API -Dokumentation klar. Wenn der Anrufcode die API nicht achtet und nach dem NULL -Fall achtet, wird dies höchstwahrscheinlich zu einer Art "Null -Zeiger -Ausnahme" führen :) :)

In C ++ kann ich mir 3 verschiedene Geschmacksrichtungen vorstellen, eine Methode einzurichten, die ein Objekt findet.

Option a

Object *findObject(Key &key);

Null zurückgeben, wenn ein Objekt nicht gefunden werden kann. Schön und einfach. Ich würde mit diesem gehen. Die nachstehenden alternativen Ansätze sind für Menschen, die Out-Params nicht hassen.

Option b

void findObject(Key &key, Object &found);

Geben Sie eine Verweise auf Variable weiter, die das Objekt empfängt. Die Methode hat eine Ausnahme ausgelöst, wenn ein Objekt nicht gefunden werden kann. Diese Konvention ist wahrscheinlich besser geeignet, wenn sie nicht wirklich erwartet wird, dass ein Objekt nicht gefunden wird - daher werfen Sie eine Ausnahme, um zu bedeuten, dass es sich um einen unerwarteten Fall handelt.

Option c

bool findObject(Key &key, Object &found);

Die Methode gibt falsch zurück, wenn ein Objekt nicht gefunden werden kann. Der Vorteil dieser Option A besteht darin, dass Sie in einem klaren Schritt nach dem Fehlerfall überprüfen können:

if (!findObject(myKey, myObj)) { ...

Bezieht sich 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 es nicht erforderlich ist, das Buch zu "lesen" oder "schauen, bevor Sie springen", wie hier gesagt wurde

also im Prinzip:

bool TryFindObject(RequestParam request, out ResponseParam response)

und dies bedeutet, dass der Code des Benutzers auch klar ist

...
if(TryFindObject(request, out response)
{
  handleSuccess(response)
}
else
{
  handleFailure()
}
...

Wenn es wichtig ist, dass der Client -Code den Unterschied zwischen gefunden und nicht gefunden hat und dies ein routinemäßiges Verhalten sein soll, dann ist es am besten, Null zurückzugeben. Der Client -Code kann dann entscheiden, was zu tun ist.

Im Allgemeinen sollte es null zurückkehren. Der Code, den die Methode aufruft, sollte entscheiden, ob eine Ausnahme oder etwas anderes versucht werden soll.

Oder eine Option zurückgeben

Eine Option ist im Grunde eine Containerklasse, die den Kunden dazu zwingt, Standkoffer zu behandeln. Scala hat dieses Konzept, schau nach seiner API.

Anschließend haben Sie Methoden wie T getorelse (t ValueIfnull) auf diesem Objekt, das entweder das gefundene Objekt zurückgibt, oder ein Allternativ des Clients spezifiziert.

Leider ist JDK inkonsistent. Wenn Sie versuchen, auf nicht vorhandene Schlüssel im Ressourcenpaket zuzugreifen, erhalten Sie keine Ausnahme. Wenn Sie einen Wert von MAP anfordern, erhalten Sie Null, wenn dies nicht vorhanden ist. Daher würde ich die Antwort der Gewinner auf Folgendes ändern, wenn der Wert gefunden wird, null sein kann, und dann die Ausnahme ausschöpfen, wenn er nicht gefunden wird, ansonsten null zurückgeben. Folgen Sie also der Regel mit einer Ausnahme, wenn Sie wissen müssen, warum Wert nicht gefunden wird, erhöhen Sie immer Ausnahme oder ..

Solange es zurückkehren soll a Hinweis Für das Objekt sollte die Rückgabe eines Nulls gut sein.

Wenn es jedoch das ganze blutige Ding zurückgibt (wie in C ++: "Return Bla;" anstatt "zurückzureisen" (oder "Blah" ist ein Zeiger), dann können Sie keine Null zurückgeben, weil es ist, weil es ist, weil es ist, weil es ist Nicht vom Typ "Objekt".

Glauben Sie nicht, dass jemand den Overhead in der Ausnahmebehandlung erwähnt hat - zusätzliche Ressourcen zum Laden und Verarbeiten der Ausnahme. Wenn es sich nicht um ein echtes App -Tötung oder ein Verarbeitungsereignis handelt (in Zukunft mehr Schaden als nützt), würde ich mich dafür entscheiden, eine zurückzugeben. Bewerten Sie, dass die Anrufumgebung so interpretieren könnte, wie sie für richtig hält.

Ich stimme dem zu sein, was hier der Konsens zu sein scheint (Rückkehr null, wenn "nicht gefunden" ein normales Ergebnis ist, oder eine Ausnahme auslegen, wenn die Semantik der Situation erfordert, dass das Objekt immer gefunden wird).

Es gibt jedoch eine dritte Möglichkeit, die je nach Ihrer jeweiligen Situation sinnvoll ist. Ihre Methode könnte ein Standardobjekt in der Bedingung "Nicht gefunden" zurückgeben, sodass das Aufrufen von Code sichergestellt werden kann, dass es immer ein gültiges Objekt empfängt, ohne dass Nullprüfung oder Ausnahmebehandel erforderlich ist.

Rückgabe eines Nulls, Ausnahmen sind genau das: Etwas, das Ihr Code nicht erwartet.

Ausnahmen sollten sein außergewöhnlich. Null zurückkehren Wenn es gültig ist, einen Null zurückzugeben.

Lieber zurückkehren null -

Wenn der Anrufer es ohne Überprüfung verwendet, tritt die Ausnahme sowieso genau dort vor.

Wenn der Anrufer es nicht wirklich benutzt, besteuern Sie ihn nicht a try/catch Block

Wenn die Methode eine Sammlung zurückgibt, geben Sie eine leere Sammlung zurück (wie oben). Aber bitte nicht Sammlungen.Empty_List oder so! (Im Falle von Java)

Wenn die Methode ein einzelnes Objekt zurückzieht, haben Sie einige Optionen.

  1. Wenn die Methode immer das Ergebnis finden sollte und es ein echter Ausnahmeregelung ist, das Objekt nicht zu finden, sollten Sie eine Ausnahme auslegen (in Java: Bitte eine ungeprüfte Ausnahme)
  2. (Java nur Java) Wenn Sie tolerieren können, dass die Methode eine geprüfte Ausnahme ausgelöst hat, werfen Sie ein projektspezifisches ObjectNotFoundException oder dergleichen. In diesem Fall sagt der Compiler, wenn Sie vergessen, die Ausnahme zu behandeln. (Dies ist meine bevorzugte Handhabung nicht gefundener Dinge in Java.)
  3. Wenn Sie sagen, dass es wirklich in Ordnung ist, wenn das Objekt nicht gefunden wird und Ihr Methodenname wie findbookforAuthorreturnnull (..) ist, können Sie NULL zurückgeben. In diesem Fall ist es stark Es wird empfohlen, eine Art statischer Überprüfung oder Compiler -Prüfung zu verwenden, und verhindert die Dererozierung des Ergebnisses ohne Nullprüfung. Im Falle von Java kann es zB sein. FindBugs (siehe DefaultAnnotation at http://findbugs.sourceforge.net/manual/annotations.html) oder Intellij-Checking.

Seien Sie vorsichtig, wenn Sie sich entscheiden, einen Null zurückzugeben. Wenn Sie nicht der einzige Programmierer im Projekt sind, erhalten Sie zur Laufzeit NullPointerexceptions (in Java oder was auch immer in anderen Sprachen)! Gehen Sie also keine Nulls zurück, die zur Kompilierung nicht überprüft werden.

Wenn Sie eine Bibliothek oder eine andere Klasse verwenden, die eine Ausnahme ausgelöst hat, sollten Sie sollten überdenken es. Hier ist ein Beispiel. Beispiel2.java ist wie Bibliothek und Beispiel. Java verwendet das Objekt. Main.java ist ein Beispiel für diese Ausnahme. Sie sollten eine aussagekräftige Nachricht und (falls erforderlich) an den Benutzer in der Anrufseite anweisen.

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 außergewöhnlich aufgetreten, dann:

  • Objekt gefunden; Objekt zurückgeben
  • Objekt nicht gefunden; Ausnahme machen

Ansonsten kehren Sie NULL zurück.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top