Domanda

Io uso object != null molto da evitare NullPointerException.

Esiste una buona alternativa a questa?

Per esempio:

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

Ciò evita a NullPointerException, quando non si sa se l'oggetto lo è null o no.

Tieni presente che la risposta accettata potrebbe non essere aggiornata, vedi https://stackoverflow.com/a/2386013/12943 per un approccio più recente.

È stato utile?

Soluzione

Questo per me suona come un problema ragionevolmente comune che gli sviluppatori da junior a intermedi tendono ad affrontare ad un certo punto: o non sanno o non si fidano dei contratti a cui partecipano e superano difensivamente i null. Inoltre, quando scrivono il proprio codice, tendono a fare affidamento sulla restituzione di null per indicare qualcosa che richiede quindi al chiamante di verificare la presenza di null.

In altre parole, ci sono due casi in cui viene visualizzato il controllo null:

  1. Dove null è una risposta valida in termini di contratto; e

  2. Dove non è una risposta valida.

(2) è facile. Utilizzare assert istruzioni (asserzioni) o consentire errori (ad esempio, NullPointerException ). Le asserzioni sono una funzionalità Java molto sottoutilizzata che è stata aggiunta in 1.4. La sintassi è:

assert <condition>

o

assert <condition> : <object>

dove <condition> è un'espressione booleana e <object> è un oggetto il cui toString() output del metodo verrà incluso nell'errore.

Un'istruzione Error genera un AssertionError (-ea) se la condizione non è vera. Per impostazione predefinita, Java ignora le asserzioni. È possibile abilitare le asserzioni passando l'opzione <=> alla JVM. È possibile abilitare e disabilitare le asserzioni per singole classi e pacchetti. Ciò significa che è possibile convalidare il codice con le asserzioni durante lo sviluppo e il test e disabilitarle in un ambiente di produzione, anche se i miei test non hanno mostrato alcun impatto sulle prestazioni dalle asserzioni.

Non usare asserzioni in questo caso è OK perché il codice fallirà, che è ciò che accadrà se si usano asserzioni. L'unica differenza è che con le asserzioni potrebbe accadere prima, in modo più significativo e possibilmente con informazioni aggiuntive, il che potrebbe aiutarti a capire perché è successo se non te lo aspettavi.

(1) è un po 'più difficile. Se non hai alcun controllo sul codice che stai chiamando, sei bloccato. Se null è una risposta valida, devi verificarla.

Se è il codice che controlli, tuttavia (e questo è spesso il caso), allora è una storia diversa. Evitare di utilizzare null come risposta. Con i metodi che restituiscono raccolte, è facile: restituire raccolte vuote (o matrici) invece di null praticamente sempre.

Con le non raccolte potrebbe essere più difficile. Considera questo come esempio: se hai queste interfacce:

public interface Action {
  void doSomething();
}

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

dove Parser prende l'input dell'utente grezzo e trova qualcosa da fare, forse se stai implementando un'interfaccia a riga di comando per qualcosa. Ora è possibile rendere nullo il contratto se non viene eseguita alcuna azione appropriata. Questo porta al controllo null di cui stai parlando.

Una soluzione alternativa è di non restituire mai null e utilizzare invece Pattern di oggetti null :

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;
    }
  }
}

Confronto:

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();
}

a

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

che è un design molto migliore perché porta a un codice più conciso.

Detto questo, forse è del tutto appropriato per il metodo findAction () generare un'eccezione con un messaggio di errore significativo, specialmente in questo caso in cui si fa affidamento sull'input dell'utente. Sarebbe molto meglio per il metodo findAction generare un'eccezione piuttosto che per il metodo chiamante esplodere con una semplice NullPointerException senza spiegazioni.

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

O se ritieni che il meccanismo try / catch sia troppo brutto, piuttosto che Non fare nulla, l'azione predefinita dovrebbe fornire un feedback all'utente.

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);
        }
    }
}

Altri suggerimenti

Se si utilizza (o si prevede di utilizzare) un IDE Java come IDEA JetBrains IntelliJ , Eclipse o Netbeans o uno strumento come findbugs, puoi utilizzare le annotazioni per risolvere questo problema.

Fondamentalmente, hai @Nullable e @NotNull.

Puoi usare metodi e parametri, come questo:

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

o

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

Il secondo esempio non verrà compilato (in IntelliJ IDEA).

Quando si utilizza la prima funzione helloWorld() in un altro codice:

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

Ora il compilatore IDEA di IntelliJ ti dirà che il controllo è inutile, dal momento che la funzione null non restituirà <=>, mai.

Utilizzo del parametro

void someMethod(@NotNull someParameter) { }

se scrivi qualcosa del tipo:

someMethod(null);

Questo non verrà compilato.

Ultimo esempio usando <=>

@Nullable iWantToDestroyEverything() { return null; }

In questo modo

iWantToDestroyEverything().something();

E puoi essere sicuro che ciò non accadrà. :)

È un buon modo per consentire al compilatore di controllare qualcosa di più di quanto non faccia normalmente e per rafforzare i contratti. Sfortunatamente, non è supportato da tutti i compilatori.

In IntelliJ IDEA 10.5 e versioni successive, hanno aggiunto il supporto per qualsiasi altra <=> <=> implementazione.

Vedi post sul blog Altro flessibile e configurabile @ annotazioni Nullable / @ NotNull .

Se non sono ammessi valori null

Se il tuo metodo viene chiamato esternamente, inizia con qualcosa del genere:

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

Quindi, nel resto di quel metodo, saprai che object non è null.

Se si tratta di un metodo interno (non parte di un'API), basta documentare che non può essere nullo e il gioco è fatto.

Esempio:

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

Tuttavia, se il tuo metodo passa semplicemente il valore e il metodo successivo lo passa ecc., potrebbe diventare problematico. In tal caso, potresti voler controllare l'argomento come sopra.

Se è consentito null

Questo dipende davvero. Se scopri che spesso faccio qualcosa del genere:

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

Quindi mi dirigo e faccio due cose completamente diverse. Non esiste uno snippet di codice brutto, perché ho davvero bisogno di fare due cose diverse a seconda dei dati. Ad esempio, dovrei lavorare sull'input o dovrei calcolare un buon valore predefinito?


In realtà è raro per me usare il linguaggio " if (object != null && ... " ;.

Potrebbe essere più semplice fornirti degli esempi, se mostri esempi di dove in genere usi il linguaggio.

Caspita, quasi odio aggiungere un'altra risposta quando abbiamo 57 modi diversi per raccomandare NullObject pattern, ma penso che alcune persone interessate a questa domanda possano sapere che esiste una proposta sul tavolo per Java 7 aggiungere " gestione null-safe " & # 8212; una sintassi semplificata per la logica if-not-equal-null.

L'esempio fornito da Alex Miller è simile al seguente:

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

?. significa de-referenziare l'identificatore sinistro solo se non è nullo, altrimenti valuta il resto dell'espressione come null. Alcune persone, come Dick Wall, membro di Java Posse e il gli elettori di Devoxx adorano davvero questa proposta, ma c'è anche opposizione, in quanto incoraggerà effettivamente un maggiore uso di <=> come valore sentinella.


Aggiornamento: Un la proposta ufficiale per un operatore null-safe in Java 7 è stata presentata in Project Coin. La sintassi è leggermente diversa dall'esempio sopra, ma è la stessa nozione.


Aggiornamento: La proposta dell'operatore null-safe non è diventata Project Coin. Quindi, non vedrai questa sintassi in Java 7.

Se valori non definiti non sono consentiti:

Potresti configurare il tuo IDE per avvisarti del potenziale dereferenziamento nullo. Per esempio. in Eclipse, vedi Preferenze > Java & Gt; Compilatore & Gt; Errori / Avvertenze / Analisi nulla .

Se sono consentiti valori non definiti:

Se si desidera definire una nuova API in cui valgono valori indefiniti , utilizzare Pattern opzione (può essere familiare dai linguaggi funzionali). Presenta i seguenti vantaggi:

  • Nell'API è esplicitamente indicato se esiste o meno un input o un output.
  • Il compilatore ti costringe a gestire " undefined " caso.
  • L'opzione è una monade , quindi non è necessario un controllo null dettagliato, basta usare map / foreach / getOrElse o un combinatore simile per usare in sicurezza il valore (esempio) .

Java 8 ha un Optional incorporato classe (consigliata); per le versioni precedenti, ci sono alternative alla libreria, ad esempio Guava 's < a href = "https://google.github.io/guava/releases/19.0/api/docs/com/google/common/base/Optional.html" rel = "noreferrer"> Option o FunctionalJava ' ?: . Ma come molti modelli di stile funzionale, l'utilizzo di Option in Java (anche 8) porta a un po 'di plateplate, che puoi ridurre usando un linguaggio JVM meno dettagliato, ad es. Scala o Xtend.

Se hai a che fare con un'API che potrebbe restituire valori null , non puoi fare molto in Java. Xtend e Groovy hanno operatore Elvis ?. e operatore di dereference null-safe <=>, ma tieni presente che restituisce null in caso di riferimento null, quindi solo " defers " la corretta gestione di null.

Solo per questa situazione -

Non verifica se una variabile è nulla prima di invocare un metodo uguale (di seguito un esempio di confronto di stringhe):

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

genererà un NullPointerException se foo non esiste.

Puoi evitarlo confrontando i tuoi String in questo modo:

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

Con Java 8 arriva la nuova classe java.util.Optional che probabilmente risolve parte del problema. Si può almeno dire che migliora la leggibilità del codice e nel caso delle API pubbliche rendono più chiaro il contratto dell'API allo sviluppatore del client.

Funzionano così:

Un oggetto opzionale per un determinato tipo (Fruit) viene creato come tipo di ritorno di un metodo. Può essere vuoto o contenere un fruits oggetto:

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();
}

Ora guarda questo codice dove cerchiamo un elenco di map() (orElse()) per una determinata istanza di Fruit:

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

È possibile utilizzare l'operatore Optional per eseguire un calcolo su - o estrarre un valore da - un oggetto opzionale. null ti consente di fornire un fallback per i valori mancanti.

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

Ovviamente, il controllo del valore null / vuoto è ancora necessario, ma almeno lo sviluppatore è consapevole che il valore potrebbe essere vuoto e il rischio di dimenticare di controllare è limitato.

In un'API creata da zero usando orElse ogni volta che un valore di ritorno potrebbe essere vuoto e restituendo un oggetto semplice solo quando non può essere ifPresent (convenzione), il codice client potrebbe abbandonare i controlli null sui valori di ritorno di oggetti semplici ...

Naturalmente NullPointerException potrebbe anche essere usato come argomento del metodo, forse un modo migliore per indicare argomenti opzionali rispetto a 5 o 10 metodi di sovraccarico in alcuni casi.

<=> offre altri metodi convenienti, come <=> che consentono l'uso di un valore predefinito e <=> che funziona con espressioni lambda .

Ti invito a leggere questo articolo (la mia fonte principale per scrivere questa risposta) in cui la soluzione problematica <=> (e in generale il puntatore null) e la (parziale) proposta da <=> sono ben spiegate: Oggetti opzionali Java .

A seconda del tipo di oggetti che stai controllando potresti essere in grado di usare alcune delle classi nei comuni di apache come: apache commons lang e collezioni apache commons

Esempio:

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

o (a seconda di ciò che è necessario controllare):

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

La classe StringUtils è solo una delle tante; ci sono alcune buone classi nei beni comuni che manipolano in modo sicuro.

Ecco un esempio di come è possibile utilizzare la null null in JAVA quando si include la libreria apache (commons-lang-2.4.jar)

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

E se stai usando Spring, Spring ha anche la stessa funzionalità nel suo pacchetto, vedi library (spring-2.4.6.jar)

Esempio su come utilizzare questa classe statica dalla primavera (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
  • Se consideri che un oggetto non dovrebbe essere nullo (o è un bug) usa un'asserzione.
  • Se il tuo metodo non accetta parametri nulli, dillo nel javadoc e usa un'asserzione.

Devi controllare l'oggetto! = null solo se vuoi gestire il caso in cui l'oggetto potrebbe essere null ...

Esiste una proposta per aggiungere nuove annotazioni in Java7 per aiutare con parametri null / notnull: http://tech.puredanger.com/java7/#jsr308

Sono un fan di " fail fast " codice. Chiediti: stai facendo qualcosa di utile nel caso in cui il parametro sia nullo? Se non hai una risposta chiara su cosa dovrebbe fare il tuo codice in quel caso ... non dovrebbe mai essere nullo in primo luogo, quindi ignorarlo e consentire a NullPointerException di essere lanciato. Il codice chiamante avrà lo stesso senso di un NPE come se fosse un IllegalArgumentException, ma sarà più facile per lo sviluppatore eseguire il debug e capire cosa è andato storto se viene lanciato un NPE anziché il codice che tenta di eseguire qualche altra imprevista imprevista logica - che alla fine porta comunque al fallimento dell'applicazione.

Il framework delle raccolte di Google offre un modo valido ed elegante per ottenere il controllo null.

Esiste un metodo in una classe di libreria come questo:

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

E l'utilizzo è (con import static):

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

O nel tuo esempio:

checkNotNull(someobject).doCalc();

A volte, hai metodi che operano sui suoi parametri che definiscono un'operazione simmetrica:

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

Se sai che b non può mai essere nullo, puoi semplicemente scambiarlo. È più utile per uguali: Invece di foo.equals("bar"); meglio fare "bar".equals(foo);.

Piuttosto che Null Object Pattern - che ha i suoi usi - potresti considerare situazioni in cui l'oggetto null è un bug.

Quando viene generata l'eccezione, esaminare la traccia dello stack e risolvere il problema.

Java 7 ha una novità java.util.Objects classe di utilità su cui è presente a requireNonNull() metodo.Tutto ciò che fa è lanciare a NullPointerException se il suo argomento è null, ma pulisce un po' il codice.Esempio:

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

Il metodo è molto utile per controllo appena prima di un'assegnazione in un costruttore, dove ogni suo utilizzo può salvare tre righe di codice:

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

diventa

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

Null is not a 'problem'. It is an integral part of a complete modeling tool set. Software aims to model the complexity of the world and null bears its burden. Null indicates 'No data' or 'Unknown' in Java and the like. So it is appropriate to use nulls for these purposes. I don't prefer the 'Null object' pattern; I think it rise the 'who will guard the guardians' problem.
If you ask me what is the name of my girlfriend I'll tell you that I have no girlfriend. In the Java language I'll return null. An alternative would be to throw meaningful exception to indicate some problem that can't be (or don't want to be) solved right there and delegate it somewhere higher in the stack to retry or report data access error to the user.

  1. For an 'unknown question' give 'unknown answer'. (Be null-safe where this is correct from business point of view) Checking arguments for null once inside a method before usage relieves multiple callers from checking them before a call.

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

    Previous leads to normal logic flow to get no photo of a non-existent girlfriend from my photo library.

    getPhotoOfThePerson(me.getGirlfriend())
    

    And it fits with new coming Java API (looking forward)

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

    While it is rather 'normal business flow' not to find photo stored into the DB for some person, I used to use pairs like below for some other cases

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

    And don't loathe to type <alt> + <shift> + <j> (generate javadoc in Eclipse) and write three additional words for you public API. This will be more than enough for all but those who don't read documentation.

    /**
     * @return photo or null
     */
    

    or

    /**
     * @return photo, never null
     */
    
  2. This is rather theoretical case and in most cases you should prefer java null safe API (in case it will be released in another 10 years), but NullPointerException is subclass of an Exception. Thus it is a form of Throwable that indicates conditions that a reasonable application might want to catch (javadoc)! To use the first most advantage of exceptions and separate error-handling code from 'regular' code (according to creators of Java) it is appropriate, as for me, to catch NullPointerException.

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

    Questions could arise:

    Q. What if getPhotoDataSource() returns null?
    A. It is up to business logic. If I fail to find a photo album I'll show you no photos. What if appContext is not initialized? This method's business logic puts up with this. If the same logic should be more strict then throwing an exception it is part of the business logic and explicit check for null should be used (case 3). The new Java Null-safe API fits better here to specify selectively what implies and what does not imply to be initialized to be fail-fast in case of programmer errors.

    Q. Redundant code could be executed and unnecessary resources could be grabbed.
    A. It could take place if getPhotoByName() would try to open a database connection, create PreparedStatement and use the person name as an SQL parameter at last. The approach for an unknown question gives an unknown answer (case 1) works here. Before grabbing resources the method should check parameters and return 'unknown' result if needed.

    Q. This approach has a performance penalty due to the try closure opening.
    A. Software should be easy to understand and modify firstly. Only after this, one could think about performance, and only if needed! and where needed! (source), and many others).

    PS. This approach will be as reasonable to use as the separate error-handling code from "regular" code principle is reasonable to use in some place. Consider the next example:

    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. For those fast to downvote (and not so fast to read documentation) I would like to say that I've never caught a null-pointer exception (NPE) in my life. But this possibility was intentionally designed by the Java creators because NPE is a subclass of Exception. We have a precedent in Java history when ThreadDeath is an Error not because it is actually an application error, but solely because it was not intended to be caught! How much NPE fits to be an Error than ThreadDeath! But it is not.

  3. Check for 'No data' only if business logic implies it.

    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);
        }
    }
    

    and

    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);
    }
    

    If appContext or dataSource is not initialized unhandled runtime NullPointerException will kill current thread and will be processed by Thread.defaultUncaughtExceptionHandler (for you to define and use your favorite logger or other notification mechanizm). If not set, ThreadGroup#uncaughtException will print stacktrace to system err. One should monitor application error log and open Jira issue for each unhandled exception which in fact is application error. Programmer should fix bug somewhere in initialization stuff.

Ultimately, the only way to completely solve this problem is by using a different programming language:

  • In Objective-C, you can do the equivalent of invoking a method on nil, and absolutely nothing will happen. This makes most null checks unnecessary, but it can make errors much harder to diagnose.
  • In Nice, a Java-derived language, there are two versions of all types: a potentially-null version and a not-null version. You can only invoke methods on not-null types. Potentially-null types can be converted to not-null types through explicit checking for null. This makes it much easier to know where null checks are necessary and where they aren't.

Common "problem" in Java indeed.

First, my thoughts on this:

I consider that it is bad to "eat" something when NULL was passed where NULL isn't a valid value. If you're not exiting the method with some sort of error then it means nothing went wrong in your method which is not true. Then you probably return null in this case, and in the receiving method you again check for null, and it never ends, and you end up with "if != null", etc..

So, IMHO, null must be a critical error which prevents further execution (that is, where null is not a valid value).

The way I solve this problem is this:

First, I follow this convention:

  1. All public methods / API always check its arguments for null
  2. All private methods do not check for null since they are controlled methods (just let die with nullpointer exception in case it wasn't handled above)
  3. The only other methods which do not check for null are utility methods. They are public, but if you call them for some reason, you know what parameters you pass. This is like trying to boil water in the kettle without providing water...

And finally, in the code, the first line of the public method goes like this:

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

Note that addParam() returns self, so that you can add more parameters to check.

Method validate() will throw checked ValidationException if any of the parameters is null (checked or unchecked is more a design/taste issue, but my ValidationException is checked).

void validate() throws ValidationException;

The message will contain the following text if, for example, "plans" is null:

"Illegal argument value null is encountered for parameter [plans]"

As you can see, the second value in the addParam() method (string) is needed for the user message, because you cannot easily detect passed-in variable name, even with reflection (not subject of this post anyway...).

And yes, we know that beyond this line we will no longer encounter a null value so we just safely invoke methods on those objects.

This way, the code is clean, easy maintainable and readable.

Asking that question points out that you may be interested in error handling strategies. Your team's architect should decide how to work errors. There are several ways to do this:

  1. allow the Exceptions to ripple through - catch them at the 'main loop' or in some other managing routine.

    • check for error conditions and handle them appropriately

Sure do have a look at Aspect Oriented Programming, too - they have neat ways to insert if( o == null ) handleNull() into your bytecode.

In addition to using assert you can use the following:

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

This is slightly better than:

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



    .....
}

Just don't ever use null. Don't allow it.

In my classes, most fields and local variables have non-null default values, and I add contract statements (always-on asserts) everywhere in the code to make sure this is being enforced (since it's more succinct, and more expressive than letting it come up as an NPE and then having to resolve the line number, etc.).

Once I adopted this practice, I noticed that the problems seemed to fix themselves. You'd catch things much earlier in the development process just by accident and realize you had a weak spot.. and more importantly.. it helps encapsulate different modules' concerns, different modules can 'trust' each other, and no more littering the code with if = null else constructs!

This is defensive programming and results in much cleaner code in the long run. Always sanitize the data, e.g. here by enforcing rigid standards, and the problems go away.

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; }
}

The contracts are like mini-unit tests which are always running, even in production, and when things fail, you know why, rather than a random NPE you have to somehow figure out.

Guava, a very useful core library by Google, has a nice and useful API to avoid nulls. I find UsingAndAvoidingNullExplained very helpful.

As explained in the wiki:

Optional<T> is a way of replacing a nullable T reference with a non-null value. An Optional may either contain a non-null T reference (in which case we say the reference is "present"), or it may contain nothing (in which case we say the reference is "absent"). It is never said to "contain null."

Usage:

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

This is a very common problem for every Java developer. So there is official support in Java 8 to address these issues without cluttered code.

Java 8 has introduced java.util.Optional<T>. It is a container that may or may not hold a non-null value. Java 8 has given a safer way to handle an object whose value may be null in some of the cases. It is inspired from the ideas of Haskell and Scala.

In a nutshell, the Optional class includes methods to explicitly deal with the cases where a value is present or absent. However, the advantage compared to null references is that the Optional<T> class forces you to think about the case when the value is not present. As a consequence, you can prevent unintended null pointer exceptions.

In above example we have a home service factory that returns a handle to multiple appliances available in the home. But these services may or may not be available/functional; it means it may result in a NullPointerException. Instead of adding a null if condition before using any service, let's wrap it in to Optional<Service>.

WRAPPING TO OPTION<T>

Let's consider a method to get a reference of a service from a factory. Instead of returning the service reference, wrap it with Optional. It lets the API user know that the returned service may or may not available/functional, use defensively

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

As you see Optional.ofNullable() provides an easy way to get the reference wrapped. There are another ways to get the reference of Optional, either Optional.empty() & Optional.of(). One for returning an empty object instead of retuning null and the other to wrap a non-nullable object, respectively.

SO HOW EXACTLY IT HELPS TO AVOID A NULL CHECK?

Once you have wrapped a reference object, Optional provides many useful methods to invoke methods on a wrapped reference without NPE.

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

Optional.ifPresent invokes the given Consumer with a reference if it is a non-null value. Otherwise, it does nothing.

@FunctionalInterface
public interface Consumer<T>

Represents an operation that accepts a single input argument and returns no result. Unlike most other functional interfaces, Consumer is expected to operate via side-effects. It is so clean and easy to understand. In the above code example, HomeService.switchOn(Service) gets invoked if the Optional holding reference is non-null.

We use the ternary operator very often for checking null condition and return an alternative value or default value. Optional provides another way to handle the same condition without checking null. Optional.orElse(defaultObj) returns defaultObj if the Optional has a null value. Let's use this in our sample code:

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

Now HomeServices.get() does same thing, but in a better way. It checks whether the service is already initialized of not. If it is then return the same or create a new New service. Optional<T>.orElse(T) helps to return a default value.

Finally, here is our NPE as well as 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){
         //...
    }
}

The complete post is NPE as well as Null check-free code … Really?.

I like articles from Nat Pryce. Here are the links:

In the articles there is also a link to a Git repository for a Java Maybe Type which I find interesting, but I don't think it alone could decrease the checking code bloat. After doing some research on the Internet, I think != null code bloat could be decreased mainly by careful design.

I've tried the NullObjectPattern but for me is not always the best way to go. There are sometimes when a "no action" is not appropiate.

NullPointerException is a Runtime exception that means it's developers fault and with enough experience it tells you exactly where is the error.

Now to the answer:

Try to make all your attributes and its accessors as private as possible or avoid to expose them to the clients at all. You can have the argument values in the constructor of course, but by reducing the scope you don't let the client class pass an invalid value. If you need to modify the values, you can always create a new object. You check the values in the constructor only once and in the rest of the methods you can be almost sure that the values are not null.

Of course, experience is the better way to understand and apply this suggestion.

Byte!

Probably the best alternative for Java 8 or newer is to use the Optional class.

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

This is especially handy for long chains of possible null values. Example:

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

Example on how to throw exception on null:

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

Java 7 introduced the Objects.requireNonNull method which can be handy when something should be checked for non-nullness. Example:

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

May I answer it more generally!

We usually face this issue when the methods get the parameters in the way we not expected (bad method call is programmer's fault). For example: you expect to get an object, instead you get a null. You expect to get an String with at least one character, instead you get an empty String ...

So there is no difference between:

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

}

or

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

They both want to make sure that we received valid parameters, before we do any other functions.

As mentioned in some other answers, to avoid above problems you can follow the Design by contract pattern. Please see http://en.wikipedia.org/wiki/Design_by_contract.

To implement this pattern in java, you can use core java annotations like javax.annotation.NotNull or use more sophisticated libraries like Hibernate Validator.

Just a sample:

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

Now you can safely develop the core function of your method without needing to check input parameters, they guard your methods from unexpected parameters.

You can go a step further and make sure that only valid pojos could be created in your application. (sample from hibernate validator site)

public class Car {

   @NotNull
   private String manufacturer;

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

   @Min(2)
   private int seatCount;

   // ...
}

I highly disregard answers that suggest using the null objects in every situation. This pattern may break the contract and bury problems deeper and deeper instead of solving them, not mentioning that used inappropriately will create another pile of boilerplate code that will require future maintenance.

In reality if something returned from a method can be null and the calling code has to make decision upon that, there should an earlier call that ensures the state.

Also keep in mind, that null object pattern will be memory hungry if used without care. For this - the instance of a NullObject should be shared between owners, and not be an unigue instance for each of these.

Also I would not recommend using this pattern where the type is meant to be a primitive type representation - like mathematical entities, that are not scalars: vectors, matrices, complex numbers and POD(Plain Old Data) objects, which are meant to hold state in form of Java built-in types. In the latter case you would end up calling getter methods with arbitrary results. For example what should a NullPerson.getName() method return?

It's worth considering such cases in order to avoid absurd results.

  1. Never initialise variables to null.
  2. If (1) is not possible, initialise all collections and arrays to empty collections/arrays.

Doing this in your own code and you can avoid != null checks.

Most of the time null checks seem to guard loops over collections or arrays, so just initialise them empty, you won't need any null checks.

// 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
    }
}

There is a tiny overhead in this, but it's worth it for cleaner code and less NullPointerExceptions.

This is the most common error occurred for most of the developers.

We have number of ways to handle this.

Approach 1:

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

notNull(Object object, String message)

Approach 2:

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

Approach 3:

@isNull @Nullable  // using annotation based validation

Approach 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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top