Java >> Programma Java >  >> Tag >> class

Sostituisci i metodi di classe con espressioni lambda, è una cattiva pratica?

Ho avuto alcune domande a cui non riesco a trovare la risposta, almeno in Java.

Ho visto una definizione di classe in un tutorial in cui i lambda venivano usati in modo simile ai metodi. Quindi sono curioso di sapere se ci sia qualche vantaggio oltre al codice conciso e alle preferenze di stile.

Esempio:

public class Blocks {
    private Deque<Block> entries;

    public Blocks() {
        this.entries = new ArrayDeque<>();
    }

    public Deque<Block> getEntries() {
        return entries;
    }

    public void setEntries(Deque<Block> entries) {
        this.entries = new ArrayDeque<>(entries);
    }

    public Predicate<Block> push = entries::offerLast;

    public Supplier<Optional<Block>> peek = () -> Optional.ofNullable(entries.peekLast());

    public BooleanSupplier isEmpty = entries::isEmpty;

    public Supplier<String> lastHash = () -> peek.get().map(Block::hash).orElse("0");

    public LongSupplier size = entries::size;
}

È una definizione di classe valida? È una cattiva pratica? Se sì, perché?

Una cosa che ho notato è che nel push del predicato ricevo il seguente avviso:

Dereference of 'entries' will produce 'NullPointerException'

Perché ricevo questo avviso se le voci devono essere istanziate? L'avviso sembra influenzare qualsiasi funzione con un riferimento al metodo. Se invece:

public Predicate<Block> push = block -> entries.offerLast(block);

quindi l'avviso scompare.

Risposta

Gli inizializzatori di campo di una classe vengono eseguiti in ordine testuale, prima del costruttore. Pertanto, i campi push , isEmpty ecc verranno inizializzati prima di entries viene inizializzato nel costruttore.

Quando un metodo fa riferimento a un'espressione come entries::offerLast viene valutato, entries viene prima valutato per determinare su quale oggetto deve essere chiamato il metodo. Tuttavia, dal momento che entries non è inizializzato nel momento in cui viene valutata l'espressione di riferimento del metodo, entries restituisce null. Questo provoca un NullPointerException essere lanciato. JLS 15.13.3

Innanzitutto, se l'espressione di riferimento del metodo inizia con un ExpressionName o un Primary, questa sottoespressione viene valutata. Se la sottoespressione restituisce null, viene generata un'eccezione NullPointerException e l'espressione di riferimento del metodo viene completata all'improvviso.

Per risolvere questo problema, puoi spostare l'inizializzazione di entires campo fuori dal costruttore e in linea con la sua dichiarazione:

private Deque<Block> entries = new ArrayDeque<>();

Oppure puoi usare un'espressione lambda invece di un riferimento al metodo:

public Predicate<Block> push = e -> entries.offerLast(e);

Etichetta Java