Frage

Ich benutze object != null viel zu vermeiden NullPointerException .

Gibt es eine gute Alternative dazu?

Zum Beispiel:

if (someobject != null) {
    someobject.doCalc();
}

Dies vermeidet einen NullPointerException, wenn nicht bekannt ist, ob das Objekt null ist oder nicht.

Beachten Sie, dass die akzeptierte Antwort veraltet sein können, finden Sie unter https://stackoverflow.com/a/2386013/12943 für einen neuen Ansatz.

War es hilfreich?

Lösung

Das klingt für mich wie ein recht häufiges Problem, dass junior Zwischen Entwickler an einem gewissen Punkt Gesicht neigt: sie entweder nicht wissen oder nicht vertrauen, die Verträgen sie in und defensiv Überkaro beteiligt sind für NULL-Werte. Zusätzlich wird, wenn ihre eigenen Code zu schreiben, neigen sie bei der Rückkehr nulls verlassen etwas damit zeigen, um den Anrufer erfordern für NULL-Werte zu überprüfen.

Dies ist ein weiterer Weg zu legen, gibt es zwei Fälle, in denen null Prüfung kommt:

  1. Wo null ist eine gültige Antwort in Bezug auf den Vertrag; und

  2. Wenn es keine gültige Antwort ist.

(2) ist einfach. Entweder Verwendung assert Aussagen (Aussagen) oder Fehler erlauben (zB Nullpointer ). Assertions sind eine hoch-zu wenig genutzt Java-Funktion, die in 1.4 hinzugefügt wurde. Die Syntax lautet:

assert <condition>

oder

assert <condition> : <object>

wobei <condition> ist ein boolescher Ausdruck und <object> ist ein Objekt, deren toString() Methode der Ausgabe in dem Fehler aufgenommen werden.

Eine assert Anweisung löst eine Error (AssertionError), wenn die Bedingung nicht wahr ist. In der Standardeinstellung ignoriert Java Behauptungen. Sie können Behauptungen aktivieren, indem Sie die Option -ea an die JVM übergeben. Sie können Aussagen für einzelne Klassen und Pakete aktivieren und deaktivieren. Dies bedeutet, dass Sie Code mit den Behauptungen bestätigen können, während die Entwicklung und das Testen und deaktivieren Sie sie in einer Produktionsumgebung, obwohl meine Prüfung so gut wie keine Auswirkungen auf die Leistung von Behauptungen gezeigt hat.

Nicht Behauptungen in diesem Fall verwendet, ist in Ordnung, weil der Code nur fehlschlagen, das, was passiert, wenn Sie Aussagen verwenden. Der einzige Unterschied besteht darin, dass mit Behauptungen es früher geschehen könnte, in einem mehr sinnvoll und möglicherweise mit zusätzlichen Informationen, die Sie herausfinden können helfen, warum es passiert ist, wenn man es nicht erwartet haben.

(1) ist ein wenig schwieriger. Wenn Sie keine Kontrolle über den Code haben Sie anrufen, dann sind Sie stecken. Wenn null eine gültige Antwort ist, müssen Sie es überprüfen.

Wenn es Code ist, dass Sie die Kontrolle tun, aber (und das ist oft der Fall ist), dann ist es eine andere Geschichte. Vermeiden Sie nulls als Antwort verwendet wird. Mit Methoden, die Sammlungen zurückkehren, ist es einfach: leere Sammlungen zurückkehren (oder Arrays) anstelle von NULL-Werte so ziemlich die ganze Zeit

.

Mit nicht-Sammlungen könnte es schwieriger sein. Betrachten Sie dies als Beispiel: wenn Sie diese Schnittstellen:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

wo Parser Eingang roh Benutzer nehmen und finden etwas zu tun, vielleicht, wenn Sie eine Befehlszeilenschnittstelle für etwas sind zu implementieren. Nun könnte man den Vertrag machen, dass es null zurückgibt, wenn es keine geeignete Maßnahme ist. Das führt die Null Überprüfung Sie sprechen.

Eine alternative Lösung ist nie null zurück und stattdessen die Null-Objekt Muster :

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

vergleichen:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}

ParserFactory.getParser().findAction(someInput).doSomething();

das ist ein viel besseres Design, weil es führt zu prägnantem Code.

Das heißt, vielleicht ist es durchaus angemessen, dass die findAction () -Methode eine Ausnahme mit einer aussagekräftigen Fehlermeldung zu werfen - vor allem in diesem Fall, in dem Sie auf Benutzereingaben setzen. Es wäre viel besser für die findAction Methode eine Ausnahme, als für die Rufmethode zu werfen mit einem einfachen Nullpointer ohne Erklärung zu sprengen.

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

Oder wenn Sie denken, die try / catch-Mechanismus zu hässlich ist, anstatt Do Nothing Ihre Standardaktion Feedback für den Benutzer zur Verfügung stellen soll.

public Action findAction(final String userInput) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}

Andere Tipps

Wenn Sie (oder die Planung zu verwenden) eine Java-IDE wie JetBrains IntelliJ IDEA , Eclipse- oder Netbeans oder ein Tool wie findbugs dann können Sie Anmerkungen, um dieses Problem zu lösen.

Im Grunde du hast @Nullable und @NotNull.

Sie können in Verfahren und Parameter verwenden, wie folgt aus:

@NotNull public static String helloWorld() {
    return "Hello World";
}

oder

@Nullable public static String helloWorld() {
    return "Hello World";
}

Das zweite Beispiel nicht kompiliert (in IntelliJ IDEA).

Wenn Sie die erste helloWorld() Funktion in einem anderen Stück Code:

public static void main(String[] args)
{
    String result = helloWorld();
    if(result != null) {
        System.out.println(result);
    }
}

Nun ist die IntelliJ IDEA-Compiler wird Ihnen sagen, dass der Scheck ist nutzlos, da die helloWorld() Funktion nicht null zurückkehren wird, je.

Mit dem Parameter

void someMethod(@NotNull someParameter) { }

Wenn Sie schreiben, so etwas wie:

someMethod(null);

Dies wird nicht kompiliert werden.

Letztes Beispiel mit @Nullable

@Nullable iWantToDestroyEverything() { return null; }

Auf diesem

iWantToDestroyEverything().something();

Und Sie können sicher sein, dass dies nicht geschehen wird. :)

Es ist eine nette Art und Weise des Compiler Scheck etwas mehr zu lassen, als es in der Regel tut und Ihre Verträge zu erzwingen, stärker zu sein. Leider ist es nicht von allen Compilern unterstützt.

In IntelliJ IDEA 10.5 und fügten sie Unterstützung für andere @Nullable @NotNull Implementierungen.

Siehe Blogeintrag Mehr flexibel und konfigurierbar @ Nullable / @ NotNull Anmerkungen .

Wenn Null-Werte sind nicht zulässig

Wenn Ihre Methode extern aufgerufen wird, beginnen Sie mit etwas wie folgt aus:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

Dann wird im Rest dieser Methode, Sie wissen, dass object nicht null ist.

Wenn es ein internes Verfahren (nicht Teil einer API) ist, dokumentieren nur, dass es nicht null sein kann, und das ist es.

Beispiel:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

Allerdings, wenn Ihre Methode übergibt nur den Wert an, und die nächste Methode übergibt es an usw. könnte es problematisch bekommen. In diesem Fall können Sie das Argument, wie oben zu überprüfen.

Wenn null ist erlaubt

Das ist wirklich hängt. Wenn feststellen, dass ich so etwas wie dies oft tun:

if (object == null) {
  // something
} else {
  // something else
}

So I-Zweig und tun zwei völlig verschiedene Dinge. Es gibt keinen hässlichen Code-Schnipsel, weil ich wirklich zwei verschiedene Dinge tun müssen, um in Abhängigkeit von den Daten. Zum Beispiel soll ich am Eingang arbeiten, oder soll ich einen guten Standardwert berechnen?


Es ist wirklich selten für mich das Idiom "if (object != null && ..." zu verwenden.

Es kann einfacher sein, Ihnen Beispiele zu geben, wenn Sie Beispiele zeigen, wo Sie in der Regel das Idiom verwenden.

Wow, ich hasse es fast eine andere Antwort hinzufügen, wenn wir 57 verschiedene Arten haben die NullObject pattern zu empfehlen, aber ich denke, dass einige Leute mit Interesse an dieser Frage wissen mögen, dass es ein Vorschlag auf dem Tisch ist für Java 7 hinzufügen "null-safe handling" -a rationalisierte Syntax für if-not-equal-null-Logik.

Das Beispiel von Alex Miller gegeben sieht wie folgt aus:

public String getPostcode(Person person) {  
  return person?.getAddress()?.getPostcode();  
}  

Die ?. bedeutet nur de-reference der linken Kennung, wenn es nicht null, sonst bewerten den Rest des Ausdrucks als null ist. Einige Leute, wie Java Posse Mitglied Dick Mauer und der bei Devoxx Wählern wirklich diesen Vorschlag lieben, aber es gibt auch Widerstand, mit der Begründung, dass es tatsächlich mehr Gebrauch von null als Sentinel-Wert fördern.


Update: Ein offizieller Vorschlag für einen null sicheren Operator in Java 7 wurde unter Projekt Münze eingereicht. die Syntax ist ein wenig anders als das Beispiel oben, aber es ist die gleiche Idee.


Update: Der Null-safe Betreiber Vorschlag es nicht in Projekt-Münze machen. Also, werden Sie nicht diese Syntax in Java 7 sehen werden.

Wenn undefinierte Werte sind nicht zulässig:

Sie können konfigurieren Sie Ihre IDE Sie über mögliche null dereferenzierenden zu warnen. Z.B. in Eclipse finden Sie unter Einstellungen> Java> Compiler> Fehler / Warnungen / Null-Analyse .

Wenn nicht definierten Werte sind möglich:

Wenn Sie eine neue API definieren möchten, undefinierte Werte Sinn machen , verwenden Sie die Option Pattern (kann von funktionalen Sprachen vertraut sein). Es hat die folgenden Vorteile:

  • Es wird explizit in der API angegeben, ob ein Ein- oder Ausgang vorhanden ist oder nicht.
  • Der Compiler zwingen Sie den "undefiniert" Fall zu behandeln.
  • Option ist eine Monade , so gibt es keine Notwendigkeit für die ausführliche null Prüfung ist, nur Karte / foreach / getOrElse oder ein ähnliches combinator, um sicher den Wert verwenden (Beispiel) .

Java 8 verfügt über eine integrierte in Optional Klasse (empfohlen); für frühere Versionen gibt es Bibliothek Alternativen, zum Beispiel Guava 's < a href = "https://google.github.io/guava/releases/19.0/api/docs/com/google/common/base/Optional.html" rel = "noreferrer"> Optional oder FunctionalJava 's Option . Aber wie viele funktionelle Stil-Muster, mit Option in Java (auch 8) Ergebnisse in einigen ziemlich vorformulierten, was können Sie eine weniger ausführlich JVM Sprache reduzieren, z.B. Scala oder Xtend.

Wenn Sie mit einer API zu tun haben, die NULL-Werte zurückgeben könnte , können Sie viel in Java nicht. Xtend und Groovy haben die Elvis Operator ?: und die null-safe ?. Dereferenzierungsoperator, aber beachten sie, dass dies im Falle einer Nullreferenz null zurück, so dass es nur" „der richtige Umgang mit null aufschiebt.

Nur für diese Situation -

Überprüfung nicht, ob eine Variable ein Gleichheits Verfahren vor dem Aufruf (ein String vergleichen Beispiel unten) null ist:

if ( foo.equals("bar") ) {
 // ...
}

in einem NullPointerException führt, wenn foo existiert nicht.

können Sie vermeiden, dass, wenn Sie vergleichen Sie Ihre Strings wie folgt aus:

if ( "bar".equals(foo) ) {
 // ...
}

Mit Java 8 kommt die neue java.util.Optional Klasse, die wohl einige des Problems löst. Man kann zumindest sagen, dass es die Lesbarkeit des Codes verbessert, und im Fall von öffentlichen APIs macht die API Vertrag klarer an den Client-Entwickler.

Sie arbeiten wie folgt aus:

Ein optionales Objekt für einen bestimmten Typ (Fruit) als Rückgabetyp einer Methode erstellt. Es kann leer sein oder ein Fruit Objekt enthalten:

public static Optional<Fruit> find(String name, List<Fruit> fruits) {
   for (Fruit fruit : fruits) {
      if (fruit.getName().equals(name)) {
         return Optional.of(fruit);
      }
   }
   return Optional.empty();
}

Nun an diesem Code schauen, wo wir eine Liste von Fruit (fruits) für eine bestimmte Frucht Instanz suchen:

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

Sie können den map() Operator verwenden, um eine Berechnung auf auszuführen - oder einen Wert aus extrahieren - einem optionalen Objekt. orElse() können Sie für fehlende Werte, um einen Rückfall zur Verfügung stellen.

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

Natürlich ist die Prüfung auf null / leer Wert ist immer noch notwendig, aber zumindest der Entwickler ist sich bewusst, dass der Wert leer sein könnte und die Gefahr des Vergessens ist zu prüfen, beschränkt.

In einer API von Grund auf neu gebaut mit Optional, wenn ein Rückgabewert leer sein könnte, und die Rückkehr nur ein einfaches Objekt, wenn es nicht (convention) null werden kann, kann der Client-Code null Kontrollen auf einfache Objekt Rückgabewerte im Stich lassen ...

Natürlich Optional auch als Methode Argument verwendet werden könnte, vielleicht eine bessere Möglichkeit optionale Argumente als 5 oder 10 Überladungsmethoden in einigen Fällen anzuzeigen.

Optional bietet andere geeignete Verfahren, wie orElse, die die Verwendung eines Standardwert ermöglichen und ifPresent, die mit Lambda-Ausdrücke .

Ich lade Sie diesen Artikel zu lesen (meine Hauptquelle für das Schreiben dieser Antwort), in dem die NullPointerException (und im allgemeinen Null-Zeiger) problematisch sowie die (Teil-) Lösung von Optional gebracht ist gut erklärt: < a href = "http://java.dzone.com/articles/java-optional-objects" rel = "noreferrer"> Java Optional Objekte .

Je nachdem, welche Art von Objekten Sie überprüfen Sie in der Lage sein können, einige der Klassen in dem Apache Commons wie zu verwenden: apache commons lang und apache commons Sammlungen

Beispiel:

String foo;
...
if( StringUtils.isBlank( foo ) ) {
   ///do something
}

oder (je nachdem, was Sie überprüfen müssen):

String foo;
...
if( StringUtils.isEmpty( foo ) ) {
   ///do something
}

Die StringUtils Klasse ist nur eine von vielen; gibt es durchaus ein paar gute Klassen in den Gemeinen, die null sichere Manipulation zu tun.

Hier folgt ein Beispiel, wie Sie null vallidation in JAVA verwenden können, wenn Sie Apache-Bibliothek (commons-lang-2.4.jar)

schließen
public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
    Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
    return read(new StringReader(xml), true, validationEventHandler);
}

Und wenn Sie Frühling verwenden, Frühling hat auch die gleiche Funktionalität in der Verpackung finden Sie Bibliothek (feder 2.4.6.jar)

Beispiel, wie diese statische classf von Feder zu verwenden (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
  • Wenn Sie ein Objekt betrachten nicht null sein sollte (oder es ist ein Fehler) verwenden, um eine Assertion.
  • Wenn Ihre Methode nicht akzeptiert null params es in der javadoc sagen und zu einer Assertion verwenden.

Sie haben für das Objekt zu überprüfen! = Null nur, wenn Sie den Fall, in dem das Objekt kann null sein ...

behandeln möchten

Es gibt einen Vorschlag neue Annotationen in Java7 hinzuzufügen mit null / notnull params zu helfen: http://tech.puredanger.com/java7/#jsr308

Ich bin ein Fan von Code "fast nicht bestanden". Fragen Sie sich - Sie sind etwas Nützliches in dem Fall zu tun, wo der Parameter null ist? Wenn Sie noch keine klare Antwort für das, was Ihr Code in diesem Fall tun soll ... D. h es sollte nie in erster Linie null sein, dann ignorieren und erlauben eine Nullpointer geworfen werden. Der aufrufende Code wird nur so viel Sinn eines NPE machen als wäre es eine Illegal, aber es wird für den Entwickler zu debuggen einfacher sein und verstehen, was falsch gelaufen ist, wenn ein NPE eher geworfen wird, als der Code versucht, andere unerwartete Kontingenz auszuführen Logik - die letztlich in der Anwendung führt andernfalls ohnehin.

Die Google Sammlungen Framework bietet eine gute und elegante Art und Weise, die NULL-Prüfung zu erreichen.

Es ist eine Methode, die in einer Bibliothek Klasse wie folgt:

static <T> T checkNotNull(T e) {
   if (e == null) {
      throw new NullPointerException();
   }
   return e;
}

Und die Nutzung ist (mit import static):

...
void foo(int a, Person p) {
   if (checkNotNull(p).getAge() > a) {
      ...
   }
   else {
      ...
   }
}
...

oder in Ihrem Beispiel:

checkNotNull(someobject).doCalc();

Manchmal Sie haben Methoden, die auf ihren Parametern arbeiten, die einen symmetrischen Betrieb definieren:

a.f(b); <-> b.f(a);

Wenn Sie b wissen nie null sein, können Sie es einfach tauschen. Es ist sehr nützlich für die Gleichen: Statt foo.equals("bar"); besser "bar".equals(foo);.

Anstatt Null Object Pattern -, die seinen Nutzen hat -. Sie können Situationen überlegen, wo die Null-Objekt ist ein Fehler

Wenn die Ausnahme ausgelöst wird, untersuchen Sie den Stack-Trace und Arbeit durch den Bug.

Java 7 hat eine neue java.util.Objects Utility-Klasse, auf das es eine requireNonNull() Methode. tut dies alles ist eine NullPointerException werfen, wenn ihr Argument null ist, aber es reinigt den Code ein wenig. Beispiel:

Objects.requireNonNull(someObject);
someObject.doCalc();

Das Verfahren ist besonders nützlich für kurz vor einer Zuweisung Überprüfung in einem Konstruktor, wobei jeder Gebrauch davon drei Zeilen Code speichern kann:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

wird

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}

Null ist kein 'Problem'. Es ist ein integraler Bestandteil eines vervollständigen Set-Modellierungs-Tool. Software zielt darauf ab, die Komplexität der Welt zu modellieren und zu null trägt seine Last. Null zeigt 'Keine Daten' oder 'Unknown' in Java und dergleichen. So ist es angebracht, nulls für diese Zwecke zu verwenden. Ich ziehe es nicht die ‚Null-Objekt‘ Muster; Ich denke, es steigt die ‚ die bewahre Das Problem ‚Wächter .
Wenn Sie mich fragen, was der Name meiner Freundin werde ich Ihnen sagen, dass ich keine Freundin haben. In der Programmiersprache Java werde ich null zurück. Eine Alternative wäre sinnvolle Ausnahme zu werfen einige Probleme, um anzuzeigen, die nicht sein können (oder wollen nicht sein) genau dort gelöst und es irgendwo höher im Stapel delegiert Berichtsdatenzugriffsfehler an den Benutzer wiederholen oder.

  1. Für eine ‚unbekannte Frage‘ geben ‚unbekannt Antwort‘. (Be null-Safe, in dem die aus betriebswirtschaftlicher Sicht richtig ist) Argument für null Überprüfung einmal innerhalb einer Methode vor der Verwendung mehr Anrufer entlastet von ihnen vor einem Aufruf zu überprüfen.

    public Photo getPhotoOfThePerson(Person person) {
        if (person == null)
            return null;
        // Grabbing some resources or intensive calculation
        // using person object anyhow.
    }
    

    Zurück führt zu normalen Logikfluss kein Foto von einer nicht existierenden Freundin aus meiner Foto-Bibliothek zu erhalten.

    getPhotoOfThePerson(me.getGirlfriend())
    

    Und sie paßt mit neuen kommenden Java API (Suche vorwärts)

    getPhotoByName(me.getGirlfriend()?.getName())
    

    Während es eher ‚normalen Geschäftsablauf‘ nicht Foto in der DB für einige Person gespeichert zu finden, habe ich Paare für einige andere Fälle wie unten verwenden

    public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException
    public static MyEnum parseMyEnumOrNull(String value);
    

    Und verabscheue nicht <alt> + <shift> + <j> eingeben (generieren javadoc in Eclipse) und schreiben drei zusätzliche Wörter für Sie öffentliche API. Dies wird mehr als genug für alle, aber diejenigen, die Dokumentation nicht lesen.

    /**
     * @return photo or null
     */
    

    oder

    /**
     * @return photo, never null
     */
    
  2. Dies ist eher theoretischer Fall, und in den meisten Fällen sollen Sie java null sicheren API bevorzugen (in Fall wird es in weiteren 10 Jahren veröffentlicht werden), aber NullPointerException ist Unterklasse eines Exception. So ist es eine Form von Throwable die Bedingungen, dass eine vernünftige Anwendung angibt könnte ( javadoc )! Um die ersten meisten Vorteile von Ausnahmen zu verwenden und separaten Fehlerbehandlungscode von ‚normalen‘ Code ( nach Machern von Java ) es angemessen ist, was mich betrifft, NullPointerException zu fangen.

    public Photo getGirlfriendPhoto() {
        try {
            return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
        } catch (NullPointerException e) {
            return null;
        }
    }
    

    Fragen entstehen könnten:

    Q. Was passiert, wenn getPhotoDataSource() null zurück?
    A. Es ist bis zu Business-Logik. Wenn ich nicht ein Fotoalbum finden werde ich Ihnen keine Fotos zeigen. Was passiert, wenn appContext nicht initialisiert? Diese Methode der Business-Logik setzt damit auf. Wenn die gleiche Logik sollte strenger sein dann eine Ausnahme werfen sie Teil der Geschäftslogik und explizite Prüfung auf null verwendet werden soll (Fall 3). Die neue Java-Null-sichere API passt hier besser selektiv zu spezifizieren, was bedeutet, und was nicht bedeutet, initialisiert werden, um sein schnelle scheitern bei Programmierfehlern.

    Q. Redundanter Code könnte ausgeführt und unnötige Ressourcen werden könnten ergriffen werden.
    A. Es könnte dann erfolgen, wenn getPhotoByName() versuchen würde, eine Datenbankverbindung zu öffnen, erstellen PreparedStatement und verwenden Sie die Personennamen als SQL-Parameter schließlich. Der Ansatz für eine unbekannte Frage gibt eine unbekannte Antwort (Fall 1) hier arbeitet. Bevor Grabbing Ressourcen sollte die Methode Parameter überprüfen und zurück ‚unbekannt‘ Ergebnis, wenn nötig.

    Q. Dieser Ansatz hat eine Leistungseinbuße aufgrund der try Verschlussöffnung.
    A. Software sollte zunächst leicht zu verstehen und zu ändern sein. Nur diese nach, könnte mandenken über die Leistung, und nur bei Bedarf! und, wo nötig! ( Quelle ) und viele andere).

    PS. Dieser Ansatz wird als sinnvoll sein, zu verwenden, da den separate Fehlerbehandlungscode von „normalen“ Code Prinzip ist sinnvoll in einem Ort zu verwenden. Betrachten Sie das folgende Beispiel:

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }
    

    PPS. Für diejenigen, schnell zu downvote (und nicht so schnell Dokumentation zu lesen) würde Ich mag sagen, dass ich noch nie eine Null-Zeiger-Ausnahme (NPE) in meinem Leben gefangen. Aber diese Möglichkeit war absichtlich entworfen von dem Java-Schöpfer, weil NPE eine Unterklasse von Exception ist. Wir haben einen Präzedenzfall in Java Geschichte, wenn ThreadDeath eine Error ist nicht, weil es tatsächlich ein Anwendungsfehler ist, sondern nur, weil sie nicht gefangen werden soll! Wie viel NPE passt ein Error als ThreadDeath sein! Aber es ist nicht.

  3. Nach 'Keine Daten' nur dann, wenn die Geschäftslogik impliziert es.

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }
    

    und

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }
    

    Wenn appContext oder Datasource nicht initialisiert ist nicht behandelte Laufzeit Nullpointer aktuellen Thread töten und wird von Thread.defaultUncaughtExceptionHandler (für Sie Ihre Lieblings-Logger oder andere Benachrichtigung mechanizm definieren und zu verwenden). Wenn nicht gesetzt, Thread # uncaughtException wird stacktrace zu System err drucken. Man sollte Anwendungsfehlerprotokoll und öffnet Jira Ausgabe für jede nicht behandelte Ausnahme, die in der Tat Fehler in der Anwendung überwachen. Programmierer sollten Fehler irgendwo in der Initialisierung Sachen beheben.

Schließlich ist der einzige Weg, um dieses Problem vollständig zu lösen, ist durch eine andere Programmiersprache:

Allgemein "Problem" in Java in der Tat.

Zuerst meine Gedanken dazu:

Ich denke, dass es schlecht ist, „essen“ etwas, wenn NULL übergeben wurde, wo NULL kein gültiger Wert ist. Wenn Sie nicht die Methode mit irgendeiner Art von Fehler austritt, dann bedeutet das nichts schief gelaufen ist in Ihrer Methode, die nicht wahr ist. Dann kehren Sie wahrscheinlich in diesem Fall null, und in dem Empfangsverfahren prüfen Sie erneut für null und es endet nie, und Sie am Ende mit „if! = Null“, etc ..

Also, meiner Meinung nach, null muss ein kritischer Fehler sein, die weitere Ausführung verhindert (das heißt, wo null kein gültiger Wert ist).

So wie ich dieses Problem lösen, ist dies:

Zuerst, ich folge dieser Konvention:

  1. Alle öffentlichen Methoden / API immer seine Argumente für null prüfen
  2. Alle privaten Methoden prüfen nicht für null, da sie Methoden gesteuert werden (lassen Sie nur mit Nullpointer Ausnahme im Fall sterben sie wurde oben nicht behandelt)
  3. Die einzigen anderen Methoden, die für null nicht überprüfen sind Utility-Methoden. Sie sind öffentlich, aber wenn man sie aus irgendeinem Grund nennen, wissen Sie, welche Parameter Sie übergeben. Das ist wie der Versuch, Wasser in dem Kessel zu kochen ohne Wasser bietet ...

Und schließlich, im Code, geht die erste Zeile der öffentlichen Methode wie folgt:

ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

Beachten Sie, dass addParam () gibt sich selbst, so dass Sie mehr Parameter hinzufügen können, überprüfen.

Methode validate() werfen wird geprüft ValidationException, wenn einer der Parameter null ist (aktiviert oder deaktiviert ist mehr ein Design / Geschmack Problem, aber mein ValidationException geprüft wird).

void validate() throws ValidationException;

Die Nachricht wird den folgenden Text enthält, wenn zum Beispiel, "plant" ist null:

" Illegal Argument Wert null für Parameter angetroffen [Pläne] "

Wie Sie sehen können, der zweite Wert in der addParam () -Methode (string) für die Benutzernachricht benötigt, weil man nicht so leicht übergebenen in detect kann Variablennamen, auch mit Reflexion (nicht von diesem Beitrag Thema sowieso .. )..

Und ja, wir wissen, dass jenseits dieser Linie werden wir nicht mehr einen Nullwert begegnen, so dass wir nur sicher Methoden aufrufen auf diese Objekte.

Auf diese Weise ist der Code sauber, leicht wartbar und lesbar.

diese Frage Vorstellung weist darauf hin, dass Sie in Strategien zur Fehlerbehandlung interessiert sein könnten. Ihr Team des Architekten sollte entscheiden, wie Fehler zu arbeiten. Es gibt mehrere Möglichkeiten, dies zu tun:

  1. erlaubt den Ausnahmen durch Kräuselung -. Sie auf der ‚Hauptschleife‘ catch oder in einer anderen Routine Verwaltung

    • Überprüfen auf Fehlerbedingungen und diese entsprechend behandeln

Sie haben sicher einen Blick auf Aspect Oriented Programming, auch - sie haben ordentlich Wege if( o == null ) handleNull() in Ihre Bytecode einfügen

.

Neben der Verwendung von assert Sie verwenden können, die folgenden:

if (someobject == null) {
    // Handle null here then move on.
}

Das ist etwas besser als:

if (someobject != null) {
    .....
    .....



    .....
}

Nur nicht immer null verwenden. Tun Sie es nicht zulassen.

In meinen Klassen, die meisten Felder und lokale Variablen nicht-Null-Standardwerte, und ich füge hinzu Vertragsabschluss (always-on behauptet) überall im Code sicherzustellen, dass dies erzwungen wird (da es prägnante und ausdruck es kommt als NPE als im Stich gelassen und dann die Zeilennummer zu lösen hat, usw.).

Wenn ich diese Praxis angenommen, bemerkte ich, dass die Probleme selbst zu beheben schienen. Sie würden die Dinge viel früher im Entwicklungsprozess fangen nur durch Zufall und erkennen Sie eine Schwachstelle hatte .. und was noch wichtiger ist .. es hilft, verschiedene Module kapseln die Sorgen, können verschiedene Module ‚Vertrauen‘ einander, und nicht mehr Littering die Code mit if = null else Konstrukten!

Dies ist defensive Programmierung und Ergebnisse in vielen sauberen Code auf langer Sicht. Immer sanieren die Daten, z.B. hier durch starre Normen durchzusetzen, und die Probleme verschwinden.

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

Die Verträge sind wie Mini-Unit-Tests, die immer aktiv sind, auch in der Produktion, und wenn die Dinge nicht, wissen Sie warum, eher als eine zufällige NPE Sie müssen irgendwie herausfinden.

Guava, eine sehr nützliche Kern-Bibliothek von Google, hat eine schöne und nützliche API nulls zu vermeiden. Ich finde UsingAndAvoidingNullExplained sehr hilfreich.

Wie im Wiki erklärt:

  

Optional<T> ist ein Weg, um eine Nullable-T-Referenz mit einem zu ersetzen,   Nicht-Null-Wert. Ein Optional kann entweder eine Nicht-Null-T-Referenz enthalten   (Wobei in diesem Fall sagen wir die Referenz ist „present“), oder es kann enthalten   nichts (in diesem Fall sagen, dass wir die Referenz „abwesend“ ist). Es ist nie   sagte zu "null enthalten."

Verbrauch:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

Dies ist ein sehr häufiges Problem für jeden Java-Entwickler. So gibt es offizielle Unterstützung in Java 8, diese Probleme ohne unübersichtlich Code zu adressieren.

Java 8 hat java.util.Optional<T> eingeführt. Es ist ein Container, der einen Nicht-Null-Wert nicht halten oder nicht. Java 8 hat eine sicherere Art und Weise gegeben, ein Objekt, dessen Wert zu handhaben kann in einigen Fällen null sein. Es wird von den Ideen der Haskell und Scala .

Auf dem Punkt gebracht, enthalten die optionalen Klassenmethoden explizit mit den Fällen zu befassen, wo ein Wert vorhanden ist oder nicht. Im Vergleich der Vorteil Verweise auf null ist, dass das Fakultativ Klasse zwingt Sie über den Fall zu denken, wenn der Wert nicht vorhanden ist. Als Folge können Sie unbeabsichtigte Null-Zeiger-Ausnahmen verhindern.

Im obigen Beispiel haben wir ein Haus Service-Fabrik, die einen Griff, um mehrere Geräte in dem nach Hause zurückkehrt. Aber diese Dienste können oder nicht verfügbar / funktionsfähig sein; es bedeutet, dass es in einer Nullpointer führen kann. Statt eine Null if Bedingung hinzuzufügen, bevor Sie Service, machen wir es wickeln, um Optional .

Umwicklung OPTION

Lassen Sie sich ein Verfahren betrachtet eine Referenz eines Service aus einer Fabrik zu bekommen. Statt den Dienstverweis zurückkehrt, wickeln Sie es mit Optional. Damit können die API-Nutzer wissen, dass der zurück Dienst kann oder nicht verfügbar / funktional, defensiv

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

Wie Sie Optional.ofNullable() sehen eine einfache Möglichkeit bietet wickelte die Referenz zu erhalten. Es gibt andere Möglichkeiten, um die Referenz von Wunsch entweder Optional.empty() & Optional.of() zu bekommen. Eine für ein leeres Objekt statt Neuabstimmung null zurückkehrt und der andere ein Nicht-Nullable-Objekt zu wickeln sind.

Wie genau es hilft NULL PRÜFEN ZU VERHINDERN?

Wenn Sie ein Referenzobjekt gewickelt haben, Optional viele nützliche Methoden stellt Verfahren auf einem eingewickelt Referenz ohne NPE aufzurufen.

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

Optional.ifPresent ruft den gegebenen Verbraucher mit einer Referenz, wenn es sich um eine nicht-Null-Wert ist. Ansonsten tut es nichts.

@FunctionalInterface
public interface Consumer<T>

Stellt eine Operation, die einen einzelnen Eingabeargument akzeptiert und gibt kein Ergebnis. Im Gegensatz zu den meisten anderen funktionalen Schnittstellen wird Consumer über Nebenwirkungen funktionieren erwartet. Es ist so sauber und leicht zu verstehen. In dem obigen Codebeispiel wird HomeService.switchOn(Service) aufgerufen, wenn die optionale Haltereferenz nicht null ist.

Wir verwenden den ternären Operator sehr oft für Nullzustand überprüft und einen anderen Wert oder Standardwert zurück. Optional bietet eine weitere Möglichkeit, die gleiche Bedingung, ohne zu überprüfen null zu handhaben. Optional.orElse (defaultObj) gibt defaultObj, wenn die optionalen einen Nullwert hat. Lassen Sie uns dies in unserem Beispielcode verwenden:

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

Jetzt HomeServices.get () tut Gleiche, aber in einer besseren Art und Weise. Es wird überprüft, ob der Dienst bereits von nicht initialisiert wird. Wenn es dann gleich zurückgeben oder einen neuen New-Service erstellen. Optional .orElse (T) hilft, einen Standardwert zurück.

Schließlich ist hier unsere NPE sowie null Check-freien Code:

import java.util.Optional;
public class HomeServices {
    private static final int NOW = 0;
    private static Optional<HomeServices> service;

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

public Optional<Service> getRefrigertorControl() {
    Service s = new  RefrigeratorService();
    //...
    return Optional.ofNullable(s);
}

public static void main(String[] args) {
    /* Get Home Services handle */
    Optional<HomeServices> homeServices = HomeServices.get();
    if(homeServices != null) {
        Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
        refrigertorControl.ifPresent(HomeServices::switchItOn);
    }
}

public static void switchItOn(Service s){
         //...
    }
}

Der komplette Beitrag wird NPE sowie Null Check-freien Code ... Wirklich? .

Ich mag Artikel von Nat Pryce. Hier sind die Links:

In den Artikeln gibt es auch einen Link zu einer Git-Repository für Java Vielleicht Art, die ich interessant finde, aber ich glaube nicht, dass der Rückgang allein könnte Prüfcodes aufblasen. einige der Forschung über das Internet nach tun, ich denke, ! = null Code aufblasen durch sorgfältiges Design verringert hauptsächlich wird.

Ich habe die NullObjectPattern versucht, aber für mich ist nicht immer der beste Weg zu gehen. Es gibt manchmal, wenn eine „keine Aktion“ nicht sachgemäßer ist.

NullPointerException ist ein Runtime Ausnahme , die es Entwicklern Fehler und mit genug Erfahrung bedeutet, es sagt Ihnen genau, wo ist der Fehler.

Nun zur Antwort:

Versuchen Sie, alle wie möglich Ihre Attribute und ihre Accessoren als privat zu machen oder zu vermeiden, sie überhaupt zu den Kunden verfügbar zu machen. Sie können die Werte der Argumente im Konstruktor natürlich haben, aber durch den Umfang reduzieren Sie lassen Sie sich nicht die Client-Klasse einen ungültigen Wert übergeben. Wenn Sie die Werte ändern müssen, können Sie immer eine neue object erstellen. Sie überprüfen die Werte im Konstruktor nur einmal und in dem Rest der Methoden kann man fast sicher sein, dass die Werte nicht null.

Natürlich Erfahrung ist der bessere Weg, diesen Vorschlag zu verstehen und anzuwenden.

Byte!

Wahrscheinlich die beste Alternative für Java 8 oder höher ist, die Optional Klasse.

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

Das ist besonders praktisch für lange Ketten von möglichen Nullwerten. Beispiel:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

Beispiel, wie Ausnahme auf null werfen:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

Java 7 eingeführt, um die Objects.requireNonNull Methode, die sehr nützlich sein kann, wenn sollte etwas für nicht-nullness geprüft werden. Beispiel:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();

Darf ich annehmen, wird er allgemein!

Wir in der Regel Gesicht dieses Problem, wenn die Methoden, um die Parameter in die Quere kommen wir nicht zu erwarten (schlechte Methodenaufruf Programmierer Fehler ist). Zum Beispiel: Sie erwarten ein Objekt zu bekommen, anstatt Sie ein Null erhalten. Sie erwarten einen String mit mindestens einem Charakter zu erhalten, anstatt eine leere String bekommen ...

So gibt es keinen Unterschied zwischen:

if(object == null){
   //you called my method badly!

}

oder

if(str.length() == 0){
   //you called my method badly again!
}

Sie wollen beide sicher stellen, dass wir gültige Parameter empfangen werden, bevor wir das tun alle anderen Funktionen.

Wie in einigen anderen Antworten erwähnt, über Probleme vermeiden Sie das Design by Vertrag können folgen Muster. Bitte finden Sie unter http://en.wikipedia.org/wiki/Design_by_contract .

Um dieses Muster in Java zu implementieren, können Sie Core Java-Annotationen wie javax.annotation.NotNull oder verwenden Sie anspruchsvollere Bibliotheken wie Hibernate Validator .

Nur ein Beispiel:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

Jetzt können Sie sicher die Kernfunktion Ihrer Methode entwickeln, ohne Eingabeparameter zu überprüfen, sie schützen Ihre Methoden aus unerwarteten Parametern.

Sie können einen Schritt weiter gehen und stellen Sie sicher, dass nur gültige POJOs in Ihrer Anwendung erstellt werden kann. (Probe von Hibernate Validator Website)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

ich sehr außer Acht lassen Antworten, die die Null-Objekte in jeder Situation empfehlen die Verwendung. Dieses Muster kann den Vertrag brechen und begraben Probleme tiefer und tiefer, anstatt sie zu lösen, nicht schaffen wird unpassend einen weiteren Stapel von Standardcode verwendet zu erwähnen, dass die künftige Wartung benötigen.

In Wirklichkeit, wenn etwas von einer Methode zurückgegeben wird, kann null sein und der Angerufene Code hat Entscheidung über das zu machen, sollte es einen früheren Aufruf, der den Zustand gewährleistet.

Denken Sie auch daran, dass Null-Objekt Muster hungrig Speicher sein wird, wenn ohne Sorgfalt verwendet. Dazu -. Die Instanz eines NullObject sollte zwischen Eigentümern geteilt werden, und nicht eine unigue Instanz für jede dieser sein

Auch würde ich nicht empfehlen, dieses Muster verwendet, wo der Typ eine primitive Typ seine Darstellung gemeint ist - wie mathematische Entitäten, die nicht Skalare sind: Vektoren, Matrizen, komplexe Zahlen und POD (Plain Old Data) Objekte, die gemeint sind Zustand in Form von Java integrierten Typen zu halten. Im letzteren Fall würden Sie auf Aufruf Getter-Methoden mit willkürlichen Ergebnissen enden. Zum Beispiel, was sollte eine NullPerson.getName () -Methode Rückkehr?

Es ist eine Überlegung wert, solche Fälle um absurde Ergebnisse zu vermeiden.

  1. Nie Variablen auf null initialisiert werden.
  2. Wenn (1) nicht möglich ist, setzen Sie alle Sammlungen und Arrays zu leeren Sammlungen / Arrays.

Tun Sie dies in Ihrem eigenen Code und Sie können vermeiden! = Null überprüft.

Die meiste Zeit null Kontrollen scheinen Schleifen über Sammlungen oder Arrays zu schützen, so initialisieren nur sie leer ist, werden Sie keine Null-Kontrollen müssen.

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

Es ist ein winziges Kopf in diesem, aber es lohnt sich für sauberere Code und weniger Nullpointerexceptions.

Dies ist der häufigste Fehler für die meisten Entwickler aufgetreten.

Wir haben Reihe von Möglichkeiten, dies zu umgehen.

Ansatz 1:

org.apache.commons.lang.Validate //using apache framework

NotNull (Object Objekt, String message)

Ansatz 2:

if(someObject!=null){ // simply checking against null
}

Ansatz 3:

@isNull @Nullable  // using annotation based validation

Ansatz 4:

// by writing static method and calling it across whereever we needed to check the validation

static <T> T isNull(someObject e){  
   if(e == null){
      throw new NullPointerException();
   }
   return e;
}
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top