Recupero di un valore senza dover eseguire il controllo null in Java

12

Molte volte mi trovo a verificare nulla durante il recupero di un valore da una gerarchia di dati per evitare NullPointerExceptions, che trovo incline agli errori e richiede un sacco di caratteri standard.

Ho scritto una routine molto semplice che mi permette di saltare il controllo nullo durante il recupero di un oggetto ...

public final class NoNPE {

    public static <T> T get(NoNPEInterface<T> in) {
        try {
            return in.get();
        } catch (NullPointerException e) {
            return null;
        }
    }

    public interface NoNPEInterface<T> {
        T get();
    }
}

Lo uso un po 'come questo ...

Room room = NoNPE.get(() -> country.getTown().getHouses().get(0).getLivingRoom());

Quanto sopra mi ha portato a ottenere un oggetto Room o un null, senza dover controllare tutti i livelli genitore.

Cosa ne pensi di quanto sopra? Sto creando un modello problematico? C'è un modo migliore per farlo secondo te?

    
posta Eurig Jones 15.01.2017 - 02:24
fonte

4 risposte

12

La tua soluzione è molto intelligente. Il problema che vedo è il fatto che non sai perché hai ottenuto un null ? Era perché la casa non aveva stanze? È stato perché la città non aveva case? Era perché il paese non aveva città? È stato perché c'era un null nella posizione 0 della raccolta a causa di un errore anche quando ci sono case nelle posizioni 1 e superiori?

Se fai uso di extensibe della classe NonPE , avrai seri problemi di debug. Penso che sia meglio sapere dove si trova esattamente la catena rotta piuttosto che ottenere silenziosamente un null che potrebbe nascondere un errore più profondo.

Anche questo viola la Legge di Demeter : country.getTown().getHouses().get(0).getLivingRoom() . Nella maggior parte dei casi, violare alcuni principi validi ti porta ad applicare soluzioni non ortodosse per risolvere il problema causato dalla violazione di tale principio.

La mia raccomandazione è che tu la usi con cautela e prova a risolvere il difetto di progettazione che ti fa incorrere nel antipattern del relitto ferroviario (quindi non devi usare NonPE ovunque). Altrimenti potresti avere bug che saranno difficili da rilevare.

    
risposta data 15.01.2017 - 02:48
fonte
10

L'idea è buona, davvero buona. Poiché Java 8 presenta i tipi Optional , è possibile trovare una spiegazione dettagliata al tipo facoltativo Java . Un esempio di ciò che hai pubblicato è

Optional.ofNullable(country)
    .map(Country::getTown)
    .map(Town::Houses);

E più avanti.

    
risposta data 15.01.2017 - 05:38
fonte
0

Il tuo metodo funziona abbastanza bene per lo scopo previsto, sebbene restituire null s quando ottieni un NullPointerException sembra un cattivo design.

Prova a evitare null s quando puoi e passali solo quando rappresentano qualcosa o hanno un significato speciale e restituiscili solo quando rappresentano / significano qualcosa, altrimenti devi lanciare un NullPointerException . Questo evita bug e confusione. Se Object non deve essere null , deve essere generata una NullPointer . Se un oggetto può essere null allora niente andrà storto quando uno viene passato. Altrimenti il tuo metodo sopra funzionerà.

    
risposta data 15.01.2017 - 17:36
fonte
0

Posso sentire il tuo dolore, ma la soluzione proposta è una cattiva idea.

  • Se uno dei getter lancia un NPE per qualche altro motivo, lo ignorerai.
  • C'è il rischio che quel lambda interiore cresca in un codice orribile. Ad esempio, se c'è un nuovo requisito per restituire una costante speciale quando non ci sono case nella città, un programmatore pigro può estendere la lamda, lasciando tutto avvolto in NoNPE.get .
  • Come già accennato, Optional.map è ciò che stai cercando.
  • La penalità per la creazione di una nuova istanza di NullPointerException è spesso significativa. Sono molti microsecondi, specialmente quando lo stack delle chiamate aumenta. È difficile prevedere dove verrà utilizzata l'utilità.

Come nota a margine, NoNPEInterface è un duplicato di java.util.function.Supplier .

In alcuni casi potresti prendere in considerazione l'utilizzo di utilità di valutazione delle espressioni che sono presenti in molti framework (ad esempio: EL, SpEL):

evaluateProperty(country, "town.houses[0].livingRoom")
    
risposta data 15.01.2017 - 22:09
fonte

Leggi altre domande sui tag