Domanda

Io sono nel mezzo di lettura eccellente La Pulizia Del Codice

Una discussione è per quanto riguarda il passaggio di valori null in un metodo.

public class MetricsCalculator {
    public double xProjection(Point p1, Point p2) {
        return (p2.x - p1.x) * 1.5;
    }
}
...
calculator.xProjection(null, new Point(12,13));

Esso rappresenta modi diversi di gestire questa:

public double xProjection(Point p1, Point p2) {
    if (p1 == null || p2 == null) {
        throw new IllegalArgumentException("Invalid argument for xProjection");
    }
    return (p2.x - p1.x) * 1.5;
}

public double xProjection(Point p1, Point p2) {
    assert p1 != null : "p1 should not be null";
    assert p2 != null : "p2 should not be null";
    return (p2.x - p1.x) * 1.5;
}

Io preferisco il affermazioni approccio, ma non mi piace il fatto che affermazioni sono disattivati per impostazione predefinita.

Il libro, infine, afferma:

Nella maggior parte dei linguaggi di programmazione non c'è un buon modo per trattare con un valore null, che è passata da un chiamante accidentalmente.Perché questo è il caso, l'approccio razionale è quello di vietare di passare null di default.

Davvero non andare in come si dovrebbe applicare questa restrizione?

Qualcuno di voi ha opinioni forti in entrambi i modi.

È stato utile?

Soluzione

Sia l'uso di affermazioni e di lancio di eccezioni sono validi approcci qui.Sia il meccanismo può essere utilizzato per indicare un errore di programmazione, non un errore di runtime, come è il caso qui.

  • Affermazioni hanno il vantaggio di prestazioni sono in genere disabili sui sistemi di produzione.
  • Le eccezioni hanno il vantaggio di sicurezza, come il controllo viene sempre eseguita.

La scelta dipende molto dal pratiche di sviluppo del progetto.Il progetto nel suo insieme ha bisogno di decidere su una affermazione politica:se la scelta è quella di consentire affermazioni durante tutto lo sviluppo, quindi io direi di usare le asserzioni per controllare questo tipo di parametro non valido in un sistema di produzione, un NullPointerException espulsi a causa di un errore di programmazione è improbabile che possa essere intercettato e gestito in modo significativo, comunque, e che, quindi, agiscono solo come un'asserzione.

Praticamente, però, conosco un sacco di sviluppatori che non si fidano che affermazioni verrà attivato quando appropriato e quindi optare per la sicurezza di lanciare una NullPointerException.

Naturalmente, se non è possibile applicare un criterio per il codice (se si sta creando una biblioteca, per esempio, e quindi dipendono da come gli altri sviluppatori l'esecuzione del codice), si dovrebbe optare per il metodo sicuro di lancio NullPointerException per i metodi che sono la parte della libreria di API.

Altri suggerimenti

Regola generale è che se il tuo metodo non si aspetta null argomenti poi si deve buttare Sistema.ArgumentNullException.Lancio corretto Exception ti protegge non solo dalle risorse corruzione e altre cose cattive, ma serve come una guida per gli utenti del vostro codice di risparmio di tempo, trascorso il debug del codice.

Anche leggere un articolo su Defensive programming

Inoltre, non è di immediato utilizzo, ma correlati a parlare di Spec#...C'è una proposta di aggiungere "null-cassaforte tipi" di una futura versione di Java: "Migliorata la gestione dei valori null - Null-safe"tipi di.

In base alla proposta, il metodo sarebbe diventato

public class MetricsCalculator {
    public double xProjection(#Point p1, #Point p2) {
        return (p2.x - p1.x) * 1.5;
    }
}

dove #Point è il tipo di non-null i riferimenti a oggetti di tipo Point.

Davvero non andare in come si dovrebbe applicare questa restrizione?

Si faccia rispettare da lancio di un ArgumentExcexception se passano nel null.

if (p1 == null || p2 == null) {
    throw new IllegalArgumentException("Invalid argument for xProjection");
}

Io preferisco l'uso di asserzioni.

Ho una regola che io uso solo affermazioni in pubblico e metodi protetti.Questo è perché credo che il metodo chiamante deve assicurare che sia il passaggio di argomenti validi per i metodi privati.

Spec# sembra molto interessante!

Quando qualcosa di simile non è disponibile, io in genere di test non-metodi privati con un run-time null-check, e le affermazioni di metodi interni.Piuttosto che il codice di controllo null esplicitamente in ogni metodo, mi delegare di una utilità di classe con un controllo nullo metodo:

/**
 * Checks to see if an object is null, and if so 
 * generates an IllegalArgumentException with a fitting message.
 * 
 * @param o The object to check against null.
 * @param name The name of the object, used to format the exception message
 *
 * @throws IllegalArgumentException if o is null.
 */
public static void checkNull(Object o, String name) 
    throws IllegalArgumentException {
   if (null == o)
      throw new IllegalArgumentException(name + " must not be null");
}

public static void checkNull(Object o) throws IllegalArgumentException {
   checkNull(o, "object");
} 

// untested:
public static void checkNull(Object... os) throws IllegalArgumentException {
   for(Object o in os) checkNull(o);  
}

Quindi il controllo si trasforma in:

public void someFun(String val1, String val2) throws IllegalArgumentException {
   ExceptionUtilities.checkNull(val1, "val1");
   ExceptionUtilities.checkNull(val2, "val2");

   /** alternatively:
   ExceptionUtilities.checkNull(val1, val2);
   **/

   /** ... **/
} 

Che può essere aggiunto con un editor di macro o un codice di script di elaborazione.Edit: Dettagliato di controllo potrebbe essere aggiunto in questo modo, ma credo sia molto più semplice per automatizzare l'aggiunta di una singola linea.

Nella maggior parte dei linguaggi di programmazione non c'è un buon modo per trattare con un valore null, che è passata da un chiamante accidentalmente.Perché questo è il caso, l'approccio razionale è quello di vietare di passare null di default.

Ho trovato JetBrains' @Nullable e @NotNull annotazioni approccio per affrontare questa la più geniale, finora.È IDE specifico, purtroppo, ma davvero pulito e potente, IMO.

http://www.jetbrains.com/idea/documentation/howto.html

Avendo questo (o qualcosa di simile) come standard java sarebbe davvero bello.

Sebbene non sia strettamente correlati, si potrebbe desiderare di dare un occhiata a Spec#.

Penso che è ancora in fase di sviluppo (da Microsoft) ma alcuni CTP sono disponibili e sembra promettente.Fondamentalmente permette di fare questo:

  public static int Divide(int x, int y)
    requires y != 0 otherwise ArgumentException; 
  {
  }

o

  public static int Subtract(int x, int y)
    requires x > y;
    ensures result > y;
  {
    return x - y;
  } 

Esso fornisce anche un'altra funzionalità come Notnull tipi.Si basano su .NET Framework 2.0 ed è pienamente compatibile.Il syntaxt, come si può vedere, è C#.

@Chris Karcher direi assolutamente corretto.L'unica cosa che mi sento di dire è di controllare i parametri separatamente e sono l'eccezione relazione il parametro che è stato nullo anche come si fa la registrazione in cui il null è venuta da molto più semplice.

@wvdschel wow!Se la scrittura del codice è troppo sforzo per voi, si dovrebbe guardare in qualcosa di simile PostSharp (o Java equivalente se disponibile) che post-processo vostre assemblee e inserire param controlli per voi.

In quanto off-topic sembra diventato l'argomento, Scala richiede un approccio interessante per questo.Tutti i tipi sono considerati nulli, a meno che non è esplicitamente avvolgerla in un Option per indicare che essa potrebbe essere null.Così:

//  allocate null
var name : Option[String]
name = None

//  allocate a value
name = Any["Hello"]

//  print the value if we can
name match {
  Any[x] => print x
  _ => print "Nothing at all"
}

Generalmente preferisco non fare, in quanto è solo rallentato le cose.NullPointerExceptions sono lanciati in seguito, comunque, che sarà presto portare l'utente a scoprire che sta passando null per il metodo.Ho usato per controllare, ma il 40% del mio codice ha finito per essere un codice di verifica, al punto che ho deciso che era solo che non vale la bella affermazione di messaggi.

Sono d'accordo o in disaccordo con wvdschel post, dipende cosa ha specificamente dicendo.

In questo caso, certo, questo metodo andrà in crash su null in modo che il controllo esplicito qui probabilmente non è necessario.

Tuttavia, se il metodo memorizza i dati passati, e c'è qualche altro metodo che si chiama successivi che fare con esso, alla scoperta di un input non valido il più presto possibile è la chiave per risolvere i bug più veloce.A quel punto successivo, ci potrebbe essere una miriade di modi che bad dati è capitato di essere dato alla tua classe.E ' una specie di cercare di capire come i ratti sono entrato nella tua casa dopo il fatto, cercando di trovare un buco da qualche parte.

Leggermente off-topic, ma con una caratteristica di findbugs che trovo molto utile è quello di essere in grado di annotare i parametri di metodi per descrivere i parametri che non deve essere superato un valore null.

Utilizzando l'analisi statica del codice, findbugs può quindi indicare le posizioni in cui il metodo viene chiamato con un potenziale valore null.

Questo ha due vantaggi:

  1. L'annotazione viene descritto il tuo intento per di come il metodo deve essere chiamato, favorendo la documentazione
  2. FindBugs può indicare un potenziale problema chiamanti di metodo, che consente di rintracciare potenziali bug.

Utile solo quando si ha accesso al codice che chiamate i vostri metodi, ma che è solitamente il caso.

Thwrowing C# ArgumentException, o Java IllegalArgumentException proprio all'inizio del metodo, che mi sembra la più chiara delle soluzioni.

Si dovrebbe sempre essere attenti con le Eccezioni Runtime - eccezioni che non sono dichiarate nella firma del metodo.Dal momento che il compilatore non valere per la cattura di questi è molto facile dimenticarsi di loro.Assicurarsi di che avere un qualche tipo di "catch all" eccezione di movimentazione per evitare che il software per fermare bruscamente.Che è la parte più importante della vostra esperienza utente.

Il modo migliore per gestire questo in realtà sarebbe l'uso di eccezioni.In definitiva, le asserzioni sta andando a finire per dare un simile l'esperienza per l'utente finale, ma non forniscono alcun modo per gli sviluppatori di chiamare il codice per gestire la situazione prima di mostrare un'eccezione per l'utente finale.Ultimatley, si vuole garantire che si prova per l'input non validi al più presto possibile (soprattutto in pubblico), del codice) e di fornire le opportune eccezioni che il codice chiamante può prendere.

In Java modo, supponendo che il null deriva da un errore di programmazione (ie.non deve mai andare al di fuori della fase di test), per poi lasciare il sistema buttare, o se ci sono effetti collaterali di raggiungere quel punto, controllare per nulla all'inizio e gettare uno IllegalArgumentException o NullPointerException.

Se il null potrebbe venire da un effettivo eccezioneal caso, ma non si desidera utilizzare una eccezione controllata per questo, quindi è sicuramente desidera andare IllegalArgumentException percorso all'inizio del metodo.

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