java == check - Vermeiden von! = Null-Anweisungen



15 Answers

Wenn Sie eine Java-IDE wie JetBrains IntelliJ IDEA , Eclipse oder Netbeans oder ein Tool wie findbugs verwenden (oder die Verwendung planen), können Sie dieses Problem mithilfe von Anmerkungen beheben.

Grundsätzlich haben Sie @Nullable und @NotNull .

Sie können in Methoden und Parametern wie folgt verwenden:

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

oder

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

Das zweite Beispiel wird nicht kompiliert (in IntelliJ IDEA).

Wenn Sie die erste helloWorld() Funktion in einem anderen Code verwenden:

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

Jetzt sagt Ihnen der IntelliJ IDEA-Compiler, dass die Prüfung unbrauchbar ist, da die helloWorld() Funktion niemals null wird.

Parameter verwenden

void someMethod(@NotNull someParameter) { }

wenn du so etwas schreibst:

someMethod(null);

Das wird nicht kompiliert.

Letztes Beispiel mit @Nullable

@Nullable iWantToDestroyEverything() { return null; }

Dies tun

iWantToDestroyEverything().something();

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

Es ist eine gute Möglichkeit, den Compiler etwas mehr als üblich prüfen zu lassen und Ihre Verträge stärker durchzusetzen. Leider wird es nicht von allen Compilern unterstützt.

In IntelliJ IDEA 10.5 und @Nullable Unterstützung für alle anderen @Nullable @NotNull Implementierungen @NotNull .

Siehe Blogbeitrag. Flexibler und konfigurierbar @ Nullable / @ NotNull-Anmerkungen .

best practice if

Ich verwende object != null , um die NullPointerException zu vermeiden.

Gibt es eine gute Alternative dazu?

Zum Beispiel:

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

Dadurch wird eine NullPointerException , wenn unbekannt ist, ob das Objekt null oder nicht.

Beachten Sie, dass die akzeptierte Antwort möglicherweise nicht mehr aktuell ist. Weitere Informationen finden Sie unter https://.com/a/2386013/12943 .




Wow, ich hasse es fast, eine andere Antwort hinzuzufügen, wenn wir 57 verschiedene Möglichkeiten haben, das NullObject pattern zu empfehlen. Ich denke jedoch, dass einige an dieser Frage interessierte Personen gerne wissen NullObject pattern , dass es in der Tabelle einen Vorschlag gibt, der "null" hinzufügt -safe handling " - eine optimierte Syntax für die if-not-gleich-null-Logik.

Das von Alex Miller gegebene Beispiel sieht folgendermaßen aus:

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

Die ?. bedeutet, dass der linke Bezeichner nur aufgehoben wird, wenn er nicht null ist. Andernfalls wird der Rest des Ausdrucks als null ausgewertet. Einige Leute wie Java Posse-Mitglied Dick Wall und die Wähler von Devoxx lieben diesen Vorschlag sehr, aber es gibt auch Widerstand, da er die Verwendung von null als Wachposten-Wert tatsächlich fördern wird.

Update: Unter Project Coin wurde ein proposed für einen nullsicheren Operator in Java 7 eingereicht . Die Syntax unterscheidet sich ein wenig von dem obigen Beispiel, aber es ist derselbe Begriff.

Update: Der Vorschlag für einen nullsicheren Operator wurde nicht in die Projektmünze aufgenommen. Daher wird diese Syntax in Java 7 nicht angezeigt.




Nur für diese Situation -

Es wird nicht geprüft, ob eine Variable vor dem Aufruf einer equals-Methode null ist (ein Beispiel zum Vergleich von Zeichenfolgen):

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

führt zu einer NullPointerException wenn foo nicht vorhanden ist.

Sie können dies vermeiden, wenn Sie Ihre String wie folgt vergleichen:

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



Abhängig von der Art der Objekte, die Sie überprüfen, können Sie möglicherweise einige der Klassen in den Apache Commons verwenden, z. B .: Apache Commons Lang und Apache Commons

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; Es gibt einige gute Klassen in den Commons, die keine sichere Manipulation durchführen.

Hier folgt ein Beispiel, wie Sie in JAVA die Null-Vallidation verwenden können, wenn Sie die Apache-Bibliothek (commons-lang-2.4.jar) einschließen.

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

Und wenn Sie Spring verwenden, hat Spring auch die gleiche Funktionalität in seinem Paket, siehe Bibliothek (spring-2.4.6.jar).

Beispiel zur Verwendung dieser statischen Klasse aus Spring (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");



Ich bin ein Fan von "Fail-Fast" Code. Fragen Sie sich selbst - tun Sie etwas Nützliches, wenn der Parameter null ist? Wenn Sie keine klare Antwort darauf haben, was Ihr Code in diesem Fall tun soll ... Dh, er sollte anfangs niemals null sein, dann ignorieren Sie ihn und erlauben Sie das Auslösen einer NullPointerException. Der aufrufende Code macht eine NPE genauso verständlich wie eine IllegalArgumentException, es ist jedoch für den Entwickler einfacher zu debuggen und zu verstehen, was schiefgegangen ist, wenn eine NPE ausgelöst wird, anstatt dass Ihr Code versucht, eine andere unerwartete Kontingenz auszuführen Logik - was letztendlich dazu führt, dass die Anwendung trotzdem ausfällt.




Manchmal verfügen Sie über Methoden, die mit seinen Parametern arbeiten, die eine symmetrische Operation definieren:

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

Wenn Sie wissen, dass b niemals Null sein kann, können Sie es einfach austauschen. Es ist am nützlichsten für Gleiche: Statt foo.equals("bar"); besser machen "bar".equals(foo); .




Java 7 hat eine neue java.util.ObjectsDienstprogrammklasse, für die es eine requireNonNull()Methode gibt. Alles, was dies tut, ist ein werfen, NullPointerExceptionwenn sein Argument NULL ist, aber es bereinigt den Code etwas. Beispiel:

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

Die Methode ist am nützlichsten für die checking unmittelbar vor einer Zuweisung in einem Konstruktor, wobei bei jeder Verwendung drei Codezeilen gespeichert werden können:

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

wird

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



Letztendlich ist die einzige Möglichkeit, dieses Problem vollständig zu lösen, die Verwendung einer anderen Programmiersprache:

  • In Objective-C können Sie das Äquivalent eines Methodenaufrufs ausführen nil, und es wird absolut nichts passieren. Dies macht die meisten Nullprüfungen überflüssig, kann jedoch die Diagnose von Fehlern erheblich erschweren.
  • In Nice , einer von Java abgeleiteten Sprache, gibt es zwei Versionen aller Typen: eine potenziell Nullversion und eine Nichtnullversion. Sie können Methoden nur für Nicht-Null-Typen aufrufen. Potentiell-Null-Typen können durch explizite Überprüfung auf Null in Nicht-Null-Typen konvertiert werden. Dies macht es viel einfacher zu wissen, wo Nullprüfungen notwendig sind und wo sie nicht sind.



Wenn Sie diese Frage stellen, weisen Sie darauf hin, dass Sie möglicherweise an Strategien zur Fehlerbehandlung interessiert sind. Der Architekt Ihres Teams sollte entscheiden, wie Fehler verarbeitet werden sollen. Dafür gibt es mehrere Möglichkeiten:

  1. Lassen Sie die Exceptions durchlaufen - fangen Sie sie an der Hauptschleife oder in einer anderen Verwaltungsroutine.

    • Überprüfen Sie die Fehlerbedingungen und behandeln Sie sie entsprechend

Schauen Sie sich auch die aspektorientierte Programmierung an - sie haben ordentliche Möglichkeiten, sie if( o == null ) handleNull()in Ihren Bytecode einzufügen .




Verwenden Sie einfach niemals null. Lass es nicht zu

In meinen Klassen haben die meisten Felder und lokalen Variablen nicht-null-Standardwerte, und ich füge überall im Code Vertragsanweisungen (Always-on-Asserts) hinzu, um sicherzustellen, dass dies erzwungen wird (da dies prägnanter und ausdrucksvoller ist, als wenn man es zulässt.) als NPE auftauchen und dann die Zeilennummer auflösen müssen usw.).

Nachdem ich diese Praxis angenommen hatte, bemerkte ich, dass die Probleme sich scheinbar zu lösen schienen. Sie würden die Dinge viel früher im Entwicklungsprozess durch Zufall einfangen und feststellen, dass Sie eine Schwachstelle hatten ... und, was noch wichtiger ist, es hilft dabei, die Bedenken der verschiedenen Module auf den Punkt zu bringen, verschiedene Module können sich gegenseitig "vertrauen", und es gibt keine Abfälle mehr Code mit if = null elseKonstrukten!

Dies ist eine defensive Programmierung und führt auf lange Sicht zu deutlich saubererem Code. Sterilisieren Sie die Daten immer, z. B. hier, indem Sie strikte Standards durchsetzen, 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 laufen, auch in der Produktion, und wenn Dinge scheitern, wissen Sie, warum, anstatt einer zufälligen NPE, müssen Sie irgendwie herausfinden.




Dies ist ein sehr häufiges Problem für jeden Java-Entwickler. Daher gibt es in Java 8 offizielle Unterstützung, um diese Probleme ohne überladenen Code zu beheben.

Java 8 hat eingeführt java.util.Optional<T>. Es ist ein Container, der einen Wert ungleich Null enthalten kann oder nicht. Java 8 hat einen sichereren Weg für die Handhabung eines Objekts geschaffen, dessen Wert in einigen Fällen null sein kann. Es ist inspiriert von den Ideen von Haskell und Scala .

Kurz gesagt, die optionale Klasse enthält Methoden, um explizit mit den Fällen umzugehen, in denen ein Wert vorhanden ist oder nicht. Der Vorteil gegenüber Nullreferenzen besteht jedoch darin, dass Sie mit der optionalen Klasse <T> über den Fall nachdenken müssen, in dem der Wert nicht vorhanden ist. Folglich können Sie unbeabsichtigte Nullzeigerausnahmen verhindern.

In obigem Beispiel haben wir eine Heimservice-Fabrik, die einen Handle an mehrere in der Wohnung verfügbare Geräte zurückgibt. Diese Dienste sind jedoch möglicherweise nicht verfügbar / funktionsfähig. Dies bedeutet, dass es zu einer NullPointerException kommen kann. Anstatt ifvor der Verwendung eines Dienstes eine Nullbedingung hinzuzufügen, packen wir sie in Optional <Dienst> ein.

AUFRUFEN ZUR OPTION <T>

Betrachten wir eine Methode, um eine Referenz einer Dienstleistung von einer Fabrik zu erhalten. Geben Sie die Dienstreferenz nicht zurück, sondern umschließen Sie sie mit Optional. Der API-Benutzer wird darauf hingewiesen, dass der zurückgegebene Dienst möglicherweise defekt ist oder nicht verfügbar / funktionsfähig ist

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

Wie Sie sehen, Optional.ofNullable()bietet es eine einfache Möglichkeit, die Referenz umwickelt zu bekommen. Es gibt andere Möglichkeiten, die Referenz von Optional zu erhalten, entweder Optional.empty()& Optional.of(). Eine für die Rückgabe eines leeren Objekts, anstatt null erneut abzustimmen, und die andere, um ein nicht-nullbares Objekt einzuwickeln.

Wie genau hilft es, eine Nullprüfung zu vermeiden?

Nachdem Sie ein Referenzobjekt umbrochen haben, bietet Optional viele nützliche Methoden zum Aufrufen von Methoden für eine umschlossene Referenz ohne NPE.

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

Optional.ifPresent ruft den angegebenen Consumer mit einer Referenz auf, wenn es sich nicht um einen Nullwert handelt. Ansonsten tut es nichts.

@FunctionalInterface
public interface Consumer<T>

Stellt eine Operation dar, die ein einzelnes Eingabeargument akzeptiert und kein Ergebnis zurückgibt. Im Gegensatz zu den meisten anderen funktionalen Schnittstellen wird erwartet, dass Consumer über Nebenwirkungen arbeitet. Es ist so sauber und leicht verständlich. HomeService.switchOn(Service)Wird im obigen Codebeispiel aufgerufen, wenn die Referenz für die optionale Aufbewahrung nicht null ist.

Wir verwenden den ternären Operator sehr häufig zum Überprüfen der Nullbedingung und geben einen alternativen Wert oder einen Standardwert zurück. Optional bietet eine andere Möglichkeit, dieselbe Bedingung zu behandeln, ohne NULL zu prüfen. Optional.orElse (defaultObj) gibt defaultObj zurück, wenn das Optional einen Nullwert hat. Verwenden wir dies in unserem Beispielcode:

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

Jetzt macht HomeServices.get () dasselbe, aber auf eine bessere Art und Weise. Es wird geprüft, ob der Dienst bereits initialisiert ist oder nicht. Ist dies der Fall, geben Sie dasselbe zurück oder erstellen Sie einen neuen neuen Dienst. Die optionale <T> .orElse (T) hilft dabei, einen Standardwert zurückzugeben.

Zum Schluss noch unser NPE-Code sowie null-check-free-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 Post ist NPE sowie Null-Check-freier Code… Wirklich? .




Ich habe das ausprobiert NullObjectPatternaber für mich ist nicht immer der beste Weg zu gehen. Es gibt manchmal Situationen, in denen eine "keine Aktion" nicht angemessen ist.

NullPointerExceptionist eine Laufzeitausnahme , die besagt, dass der Entwickler fehlerhaft ist und mit genügend Erfahrung genau sagt, wo der Fehler liegt.

Nun zur Antwort:

Versuchen Sie, alle Ihre Attribute und ihre Zugriffselemente so privat wie möglich zu machen, oder vermeiden Sie es, sie den Clients überhaupt zugänglich zu machen. Sie können die Argumentwerte natürlich im Konstruktor haben, aber durch die Reduzierung des Gültigkeitsbereichs lassen Sie der Client-Klasse keinen ungültigen Wert übergeben. Wenn Sie die Werte ändern müssen, können Sie immer einen neuen erstellen object. Sie überprüfen die Werte im Konstruktor nur einmal und bei den übrigen Methoden können Sie fast sicher sein, dass die Werte nicht null sind.

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

Byte!




Darf ich es allgemeiner beantworten!

Wir in der Regel dieses Problem konfrontiert werden, wenn die Methoden , die Parameter in die Quere kommen wir nicht zu erwarten (schlechte Methodenaufruf ist Fehler des Programmierers). Zum Beispiel: Sie erwarten ein Objekt, stattdessen eine Null. Sie erwarten einen String mit mindestens einem Zeichen, stattdessen erhalten Sie einen leeren String ...

Es gibt also keinen Unterschied zwischen:

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

}

oder

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

Beide möchten sicherstellen, dass wir gültige Parameter erhalten haben, bevor wir andere Funktionen ausführen.

Wie in einigen anderen Antworten erwähnt, können Sie das Muster nach Vertrag verfolgen, um die oben genannten Probleme zu vermeiden . Siehe http://en.wikipedia.org/wiki/Design_by_contract .

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

Nur eine Probe:

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

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

Sie können einen Schritt weiter gehen und sicherstellen, dass in Ihrer Anwendung nur gültige Pojos erstellt werden können. (Probe von der Hibernate-Validierungsstelle)

public class Car {

   @NotNull
   private String manufacturer;

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

   @Min(2)
   private int seatCount;

   // ...
}



  1. Initialisieren Sie niemals Variablen auf Null.
  2. Wenn (1) nicht möglich ist, initialisieren Sie alle Sammlungen und Arrays mit leeren Sammlungen / Arrays.

Wenn Sie dies in Ihrem eigenen Code tun, können Sie! = Nullprüfungen vermeiden.

In den meisten Fällen scheinen Nullprüfungen Schleifen über Sammlungen oder Arrays zu schützen. Wenn Sie sie also leer initialisieren, benötigen Sie keine Nullprüfungen.

// 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 gibt einen winzigen Aufwand, aber es lohnt sich für saubereren Code und weniger NullPointerExceptions.




public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}





Related