Domanda

Dopo aver pubblicato questa domanda e la lettura di quella ho capito che è molto importante sapere se un metodo dovrebbe restituire null, o se questo è considerato una condizione di errore e dovrebbero essere lanciate delle eccezioni. C'è anche una bella discussione su return & # 8216; null & # 8217; o generare un'eccezione .

Sto scrivendo un metodo e so già se voglio restituire null o generare un'eccezione, qual è il modo migliore per esprimere la mia decisione, in altre parole, per documentare il mio contratto?

Alcuni modi in cui posso pensare:

  • Scrivilo nelle specifiche / nella documentazione (qualcuno lo leggerà?)
  • Renderlo parte del nome del metodo (come ho suggerito qui )
  • presuppone che ogni metodo che genera un'eccezione non restituirà null e che chiunque non "getta" potrebbe restituire null.

Parlo principalmente di Java, ma potrebbe applicarsi anche ad altre lingue: perché esiste un modo formale per esprimere se verranno generate eccezioni (le throws parole chiave) ma nessun modo formale per esprimere se null potrebbe essere restituito?

Perché non c'è qualcosa del genere:

public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

Riepilogo e conclusioni

Esistono molti modi per esprimere il contratto:

  • Se il tuo IDE lo supporta (come IntelliJ), è meglio usare un'annotazione come @NotNull perché è visibile al programmatore e può essere utilizzato per il controllo automatico del tempo di compilazione. C'è un plugin per Eclipse per aggiungere supporto per questi, ma non è stato così lavora per me.
  • Se non si tratta di un'opzione, utilizzare tipi personalizzati come Option<T> o NotNull<T>, che aggiungono chiarezza e almeno controllo del runtime.
  • In alcun modo, documentare il contratto in JavaDoc non fa mai male e talvolta aiuta persino.
  • L'uso dei nomi dei metodi per documentare il nullability del valore restituito non è stato proposto da nessuno tranne me, e sebbene possa essere molto dettagliato e non sempre utile, credo comunque che a volte abbia i suoi vantaggi, anche.
È stato utile?

Soluzione

Un'ottima domanda di follow-up. Considero null un valore veramente speciale e se un metodo può restituire @return some value ..., or null if ... deve chiaramente documentare in Javadoc quando lo fa (<=>). Quando codifico sono difensivo, e presumo che un metodo possa restituire <=> a meno che non sia convinto di no (ad es. Perché lo ha detto Javadoc.)

Le persone hanno capito che si trattava di un problema e una soluzione proposta è quella di utilizzare le annotazioni per dichiarare l'intenzione in modo da poterle verificare automaticamente. Vedi JSR 305: Annotazioni per il rilevamento dei difetti del software , JSR 308: Annotazioni su tipi Java e Nullable How-To di JetBrain .

Il tuo esempio potrebbe essere simile a questo e rifiutato dall'IDE, dal compilatore o da altri strumenti di analisi del codice.

@NotNull
public Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

Altri suggerimenti

Puoi utilizzare Option type, che è molto simile a un elenco con zero o un elemento. Un tipo restituito Option<Object> indica che il metodo può restituire un Object oppure può restituire un valore speciale di tipo None. Questo tipo sostituisce l'uso di null con migliori controlli del tipo.

Esempio:

public Option<Integer> parseInt(String s) {
   try {
      return Option.some(Integer.parseInt(s));
   }
   catch (Exception e) {
      return Option.none();
   }
}

Se lo usi in modo coerente, puoi attivare gli avvisi null IDE o semplicemente usare grep per null che non dovrebbe apparire nel tuo codice se usi Option.none() ovunque dovresti normalmente usare un Maybe letterale.

Iterable viene fornito di serie con Scala e si chiama Option<String> in Haskell. Il link sopra è a una libreria chiamata Java funzionale che lo include. Quella versione implementa l'interfaccia <=> e ha metodi monadici che ti permettono di comporre le cose in modo piacevole. Ad esempio, per fornire un valore predefinito di 0 in caso di <=>:

int x = optionalInt.orSome(0);

E puoi sostituirlo ...

if (myString != null && !"".equals(myString))

... con questo, se hai un <=> ...

for (String s : myOptionString)

In effetti: nel nostro framework abbiamo un tipo di puntatore "non nullo", che può essere restituito per indicare che il metodo restituirà sempre un valore.

Vedo tre opzioni:

  1. attendi che il supporto linguistico lo esprima (ad es. C #?! cosa)
  2. usa Aspect Orientation per creare le tue estensioni linguistiche per esprimerlo
  3. usa un tipo personalizzato per esprimerlo
  4. (ma si basa sulla cooperazione tra sviluppatori) utilizza uno schema di denominazione per indicarlo

Per Java, è possibile utilizzare la descrizione Javadoc di un metodo per documentare il significato del valore restituito, incluso se può essere nullo. Come è stato menzionato, anche le annotazioni possono fornire assistenza qui.

D'altra parte, ammetto di non vedere nulla come qualcosa da temere. Ci sono situazioni in cui & Quot; nessuno è a casa & Quot; è una condizione significativa (anche se qui la tecnica Null Object ha un valore reale).

È certamente vero che il tentativo di invocare un metodo su un valore null provocherà un'eccezione. Ma così tenterà di dividere per zero. Ciò non significa che dobbiamo eliminare una campagna per eliminare gli zeri! Significa solo che dobbiamo capire il contratto su un metodo e fare la cosa giusta con i valori che restituisce.

Hai dato un'occhiata a Spec # ?

Potresti scrivere la tua annotazione (Java) o attributo (C #) per indicare che il valore di ritorno potrebbe essere nullo. Nulla lo controllerà automaticamente (sebbene .NET 4.0 disponga di contratti di codice per questo genere di cose) ma almeno fungerebbe da documentazione.

È supportato un @Nullable e @NotNull annotazione in IntelliJ IDEA . Si parla anche dell'aggiunta di quelle annotazioni (o di una funzione simile) a Java 7. Sfortunatamente non so fino a che punto è arrivato o se è ancora sulla buona strada.

Forse potresti definire una classe generica chiamata " NotNull " ;, in modo che il tuo metodo sia simile a:

public NotNull<Object> methodWhichCannotReturnNull(int i) throws Exception
{
   // the following would lead to a run-time error thown by the
   // NotNull constructor, if it's constructed with a null value
   return new NotNull<Object>(null);
}

Questo è ancora un controllo di runtime (non un tempo di compilazione), ma:

  • Viene lanciato nell'implementazione del metodo (non è un errore nel codice chiamante)
  • È auto-documentante (il chiamante sa che sta ricevendo NotNull<T> come tipo di ritorno)

A tutti i costi, evitare di fare affidamento su JavaDocs. Le persone le leggono solo se la firma non appare banale e si spiega da sé (il che è male per cominciare), e coloro che si preoccupano effettivamente di leggerle hanno meno probabilità di fare un errore con i null poiché sono attualmente più attenti .

Se si utilizza Java 5+, è possibile utilizzare un'annotazione personalizzata, ad es. @MayReturnNull

Aggiorna

Tutta la filosofia di codifica a parte (restituendo null, usando eccezioni, asserzioni, yada yada), spero che quanto sopra risponda alla tua domanda. A parte le primitive con valori predefiniti, i tipi complessi possono essere o meno nulli e il tuo codice deve gestirlo.

In generale, suppongo che un valore di ritorno nullo sia predefinito rispetto al contratto dell'API. È quasi sempre possibile progettare il codice in modo tale che un valore null non venga mai restituito dalle API durante & Quot; normale & Quot; flusso di esecuzione. (Ad esempio, controlla foo.contains (obj) anziché chiamare foo.get (obj) e avere un ramo separato per null. Oppure usa Modello di oggetto nullo .

Se non riesci a progettare la tua API in questo modo, documenterei chiaramente quando e perché un null potrebbe essere lanciato - almeno almeno in Javadoc, e possibilmente anche usando una @annotazione personalizzata come come molte altre risposte hanno suggerito.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top