java string empty - Evitare! = Istruzioni nulle





15 Answers

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

Fondamentalmente, hai @Nullable e @NotNull .

Puoi usare in metodo 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'altra parte di codice:

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

Ora il compilatore IDEA IntelliJ ti dirà che il controllo è inutile, dal momento che la funzione helloWorld() non restituirà null , mai.

Utilizzando il parametro

void someMethod(@NotNull someParameter) { }

se scrivi qualcosa come:

someMethod(null);

Questo non verrà compilato.

Ultimo esempio con @Nullable

@Nullable iWantToDestroyEverything() { return null; }

Facendo questo

iWantToDestroyEverything().something();

E puoi star certo che questo non accadrà. :)

È un buon modo per consentire al compilatore di controllare qualcosa di più di quello che fa di solito e per rafforzare i tuoi contratti. Sfortunatamente, non è supportato da tutti i compilatori.

In IntelliJ IDEA 10.5 e su, hanno aggiunto il supporto per qualsiasi altra implementazione @Nullable @NotNull .

Vedi post sul blog Altre annotazioni flessibili e configurabili @ Nullable / @ NotNull .

check test not

Io uso object != null molto per evitare NullPointerException .

C'è una buona alternativa a questo?

Per esempio:

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

Questo evita una NullPointerException , quando è sconosciuto se l'oggetto è null o meno.

Si noti che la risposta accettata potrebbe non essere aggiornata, consultare https://.com/a/2386013/12943 per un approccio più recente.




Wow, odio quasi aggiungere un'altra risposta quando abbiamo 57 modi diversi per raccomandare il NullObject pattern , ma penso che alcune persone interessate a questa domanda possano piacere sapere che c'è una proposta sulla tabella per Java 7 da aggiungere "null -gestione sicura " -una sintassi semplificata per la logica if-not-equal-null.

L'esempio dato da Alex Miller assomiglia a questo:

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

Il ?. significa solo de-referenziare l'identificatore sinistro se non è nullo, altrimenti valuta il resto dell'espressione come null . Alcune persone, come Dick Wall, membro di Java Posse, e gli elettori di Devoxx amano davvero questa proposta, ma c'è anche un'opposizione, sulla base del fatto che in realtà incoraggerà maggiormente l'uso del null come valore sentinella.

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

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




Solo per questa situazione -

Non verificare se una variabile è nullo prima di richiamare un metodo equals (una stringa confronta l'esempio seguente):

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

genererà NullPointerException se foo non esiste.

Puoi evitarlo se confronti le tue String questo modo:

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



A seconda del tipo di oggetti che stai controllando, potresti essere in grado di utilizzare alcune delle classi dei comuni apache come: apache commons lang e apache commons collections

Esempio:

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

oppure (a seconda di cosa è 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 fanno manipolazioni nulle.

Segue un esempio di come è possibile utilizzare null vallidation 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 usi Spring, Spring ha anche la stessa funzionalità nel suo pacchetto, vedi library (spring-2.4.6.jar)

Esempio su come usare questo statf classf da spring (org.springframework.util.Assert)

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



Sono un fan del codice "fail fast". Chiediti: stai facendo qualcosa di utile nel caso in cui il parametro sia nullo? Se non si dispone di una risposta chiara per ciò che il codice dovrebbe fare in quel caso ... Cioè non dovrebbe mai essere nullo in primo luogo, quindi ignorarlo e consentire che venga lanciata una NullPointerException. Il codice chiamante avrà lo stesso senso di un NPE come sarebbe un IllegalArgumentException, ma sarà più facile per lo sviluppatore eseguire il debug e capire cosa è andato storto se viene lanciato un NPE piuttosto che il codice che tenta di eseguire qualche altro imprevisto logica - che alla fine si traduce nell'errore dell'applicazione in ogni caso.




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 cambiarlo. È molto utile per gli uguali: invece di foo.equals("bar"); meglio fare "bar".equals(foo); .




Java 7 ha una nuova classe di utilità java.util.Objects su cui esiste un metodo requireNonNull() . Tutto ciò che viene fatto è lanciare una NullPointerException se il suo argomento è nullo, ma ripulisce un po 'il codice. Esempio:

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

Il metodo è molto utile per checking poco prima di un compito in un costruttore, in cui 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");
}



In definitiva, l'unico modo per risolvere completamente questo problema è utilizzare un linguaggio di programmazione diverso:

  • In Objective-C, puoi fare l'equivalente di invocare un metodo nil, e assolutamente non succederà nulla. Questo rende superflua la maggior parte dei controlli nulli, ma può rendere gli errori molto più difficili da diagnosticare.
  • In Nice , un linguaggio derivato da Java, ci sono due versioni di tutti i tipi: una versione potenzialmente nulla e una versione non nulla. Puoi solo invocare metodi su tipi non nulli. I tipi potenzialmente null possono essere convertiti in tipi non nulli tramite il controllo esplicito di null. Ciò rende molto più facile sapere dove sono necessari i controlli nulli e dove non lo sono.



Ponendo la domanda in questione, potresti essere interessato alle strategie di gestione degli errori. L'architetto del tuo team dovrebbe decidere come lavorare gli errori. Ci sono diversi modi per farlo:

  1. consentire alle eccezioni di ripple - catturarli nel 'ciclo principale' o in qualche altra routine di gestione.

    • controlla le condizioni di errore e gestiscile in modo appropriato

Certo, guarda anche Aspect Oriented Programming: hanno dei modi perfetti per inserirli if( o == null ) handleNull()nel tuo bytecode.




Basta non usare mai null. Non permetterlo.

Nelle mie classi, la maggior parte dei campi e delle variabili locali hanno valori di default non nulli e aggiungo dichiarazioni di contratto (sempre-on assert) ovunque nel codice per assicurarmi che questo sia applicato (poiché è più succinto e più espressivo che lasciarlo apparire come un NPE e quindi dover risolvere il numero di linea, ecc.).

Una volta adottata questa pratica, ho notato che i problemi sembravano risolversi da soli. Vedrai le cose molto prima nel processo di sviluppo per caso e ti rendi conto di avere un punto debole .. e soprattutto ... aiuta a incapsulare le preoccupazioni dei diversi moduli, i diversi moduli possono "fidarsi" l'un l'altro, e non più sporcare il codice con if = null elsecostrutti!

Questa è una programmazione difensiva e produce un codice molto più pulito a lungo termine. Disinteggiare sempre i dati, ad es. Applicando norme rigide, e i problemi scompaiono.

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

I contratti sono come test di mini-unità che sono sempre in esecuzione, anche in produzione, e quando le cose falliscono, sai perché, piuttosto che un NPE casuale che devi in ​​qualche modo capire.




Questo è un problema molto comune per ogni sviluppatore Java. Quindi c'è un supporto ufficiale in Java 8 per risolvere questi problemi senza codice ingombrante.

Java 8 ha introdotto java.util.Optional<T>. È un contenitore che può o non può contenere un valore non nullo. Java 8 ha fornito un modo più sicuro per gestire un oggetto il cui valore potrebbe essere nullo in alcuni casi. È ispirato alle idee di Haskell e Scala .

In poche parole, la classe facoltativa include metodi per trattare esplicitamente i casi in cui un valore è presente o assente. Tuttavia, il vantaggio rispetto ai riferimenti null è che la classe <T> facoltativa ti costringe a pensare al caso in cui il valore non è presente. Di conseguenza, è possibile evitare eccezioni di puntatore nullo non intenzionale.

Nell'esempio sopra abbiamo una fabbrica di servizi a domicilio che restituisce un handle a più appliance disponibili in casa. Ma questi servizi possono o non possono essere disponibili / funzionali; significa che potrebbe risultare in una NullPointerException. Anziché aggiungere una ifcondizione nulla prima di utilizzare qualsiasi servizio, includilo in <Servizio> facoltativo.

CONFEZIONAMENTO OPZIONALE <T>

Consideriamo un metodo per ottenere un riferimento di un servizio da una fabbrica. Invece di restituire il riferimento del servizio, avvolgilo con Facoltativo. Permette all'utilizzatore dell'API di sapere che il servizio restituito può o meno essere disponibile / funzionale, utilizzare in modo difensivo

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

Come vedi Optional.ofNullable()fornisce un modo semplice per ottenere il riferimento avvolto. Ci sono altri modi per ottenere il riferimento di Opzionale, sia Optional.empty()& Optional.of(). Uno per restituire un oggetto vuoto invece di risintonizzare null e l'altro per avvolgere un oggetto non annullabile, rispettivamente.

COSÌ COME ESATTAMENTE AIUTA PER EVITARE UN CONTROLLO NULL?

Dopo aver avvolto un oggetto di riferimento, Opzionale fornisce molti metodi utili per richiamare i metodi su un riferimento fascicolato senza NPE.

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

Optional.ifPresent richiama il Consumatore dato con un riferimento se è un valore non nullo. Altrimenti, non fa nulla.

@FunctionalInterface
public interface Consumer<T>

Rappresenta un'operazione che accetta un singolo argomento di input e non restituisce alcun risultato. A differenza della maggior parte delle altre interfacce funzionali, si prevede che il Consumer operi attraverso effetti collaterali. È così pulito e facile da capire. Nell'esempio di codice sopra riportato, HomeService.switchOn(Service)viene richiamato se il riferimento facoltativo di mantenimento è non nullo.

Usiamo molto spesso l'operatore ternario per verificare la condizione nulla e restituire un valore alternativo o un valore predefinito. Facoltativo fornisce un altro modo per gestire la stessa condizione senza controllare null. Optional.orElse (defaultObj) restituisce defaultObj se Opzionale ha un valore nullo. Usiamo questo nel nostro codice di esempio:

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

Ora HomeServices.get () fa la stessa cosa, ma in un modo migliore. Controlla se il servizio è già stato inizializzato di no. Se lo è, restituire lo stesso o creare un nuovo nuovo servizio. Facoltativo <T> .orElse (T) consente di restituire un valore predefinito.

Infine, ecco il nostro NPE e il codice null check-free:

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){
         //...
    }
}

Il post completo è NPE e il codice Null check-free ... Davvero? .




Ho provato il NullObjectPatternma per me non è sempre il modo migliore per andare. Ci sono volte quando una "nessuna azione" non è appropriata.

NullPointerExceptionè un'eccezione Runtime che significa che è colpa degli sviluppatori e con sufficiente esperienza ti dice esattamente dove si trova l'errore.

Ora alla risposta:

Cerca di rendere tutti i tuoi attributi e i relativi accessor il più privati ​​possibile o di non esporli affatto ai clienti. È possibile avere i valori dell'argomento nel costruttore, ovviamente, ma riducendo l'ambito non si consente alla classe client di passare un valore non valido. Se è necessario modificare i valori, è sempre possibile crearne uno nuovo object. Si controllano i valori nel costruttore solo una volta e nel resto dei metodi si può essere quasi certi che i valori non siano nulli.

Naturalmente, l'esperienza è il modo migliore per comprendere e applicare questo suggerimento.

Byte!




Posso rispondere più in generale!

Di solito ci troviamo di fronte a questo problema quando i metodi ottengono i parametri come non ci aspettavamo (la chiamata al metodo errato è colpa del programmatore). Ad esempio: ci si aspetta di ottenere un oggetto, invece si ottiene un valore nullo. Ti aspetti di ottenere una stringa con almeno un carattere, invece ottieni una stringa vuota ...

Quindi non c'è differenza tra:

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

}

o

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

Entrambi vogliono assicurarsi che abbiamo ricevuto parametri validi, prima di fare qualsiasi altra funzione.

Come accennato in alcune altre risposte, per evitare problemi sopra puoi seguire il modello Design by contract . Si prega di consultare http://en.wikipedia.org/wiki/Design_by_contract .

Per implementare questo modello in java, puoi utilizzare le annotazioni java core come javax.annotation.NotNull o utilizzare librerie più sofisticate come Hibernate Validator .

Solo un esempio:

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

Ora puoi tranquillamente sviluppare la funzione principale del tuo metodo senza dover controllare i parametri di input, proteggendo i tuoi metodi da parametri imprevisti.

Puoi fare un ulteriore passo avanti e assicurarti che nella tua applicazione possano essere creati solo pojos validi. (esempio dal sito di validazione di Hibernate)

public class Car {

   @NotNull
   private String manufacturer;

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

   @Min(2)
   private int seatCount;

   // ...
}



  1. Mai inizializzare le variabili su null.
  2. Se (1) non è possibile, inizializza tutte le raccolte e gli array per svuotare raccolte / array.

Fallo nel tuo codice personale e puoi evitare! = Assegni nulli.

La maggior parte delle volte i controlli nulli sembrano proteggere i loop su raccolte o array, quindi basta inizializzarli, non è necessario alcun controllo nullo.

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

C'è un piccolo sovraccarico in questo, ma ne vale la pena per un codice più pulito e meno NullPointerExceptions.




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



Related