Perché Java 8's Optional non dovrebbe essere usato negli argomenti


392

Ho letto su molti siti Web. Opzionale dovrebbe essere usato solo come tipo restituito e non usato negli argomenti del metodo. Sto lottando per trovare una ragione logica per cui. Ad esempio ho un pezzo di logica che ha 2 parametri opzionali. Quindi penso che avrebbe senso scrivere la mia firma del metodo in questo modo (soluzione 1):

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
    // my logic
}

Molte pagine Web specificano Opzionale non devono essere utilizzate come argomenti del metodo. Con questo in mente, potrei usare la seguente firma del metodo e aggiungere un commento Javadoc chiaro per specificare che gli argomenti possono essere nulli, sperando che i futuri manutentori leggano il Javadoc e quindi eseguano sempre controlli nulli prima di utilizzare gli argomenti (soluzione 2) :

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

In alternativa, potrei sostituire il mio metodo con quattro metodi pubblici per fornire un'interfaccia più gradevole e rendere più ovvio p1 e p2 opzionali (soluzione 3):

public int calculateSomething() {
    calculateSomething(null, null);
}

public int calculateSomething(String p1) {
    calculateSomething(p1, null);
}

public int calculateSomething(BigDecimal p2) {
    calculateSomething(null, p2);
}

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

Ora provo a scrivere il codice della classe che invoca questo pezzo di logica per ogni approccio. Richiamo prima i due parametri di input da un altro oggetto che restituisce se Optionalpoi invococalculateSomething . Pertanto, se viene utilizzata la soluzione 1, il codice chiamante sarà simile al seguente:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1, p2);

se viene utilizzata la soluzione 2, il codice chiamante sarà simile al seguente:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

se viene applicata la soluzione 3, potrei usare il codice sopra o potrei usare il seguente (ma è significativamente più codice):

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p1, p2);
    } else {
        result = myObject.calculateSomething(p1);
    }
} else {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p2);
    } else {
        result = myObject.calculateSomething();
    }
}

Quindi la mia domanda è: perché è considerata una cattiva pratica usare Optionals come argomenti del metodo (vedi soluzione 1)? Mi sembra la soluzione più leggibile e rende più evidente che i parametri potrebbero essere vuoti / nulli per i futuri manutentori. (Sono consapevole che i progettisti Optionalintendevano utilizzarlo solo come tipo restituito, ma non riesco a trovare alcun motivo logico per non utilizzarlo in questo scenario).


16
Se hai usato gli optionals, non dovresti verificare che l'opzione passata come parametro non lo sia null?
biziclop,

17
Sì, ma sarebbe ovvio per qualcun altro mantenere il codice in futuro che il parametro può essere vuoto / null, quindi potenzialmente evitare un'eccezione puntatore null in futuro
Neil Stevens

1
Wow. Argomenti null passati a un metodo? È così Visual Basic. Quale principio sta violando? SRP (forse). Inoltre, viola un altro principio il cui nome mi lascia privo di sensi va nella direzione di passare SOLO le informazioni necessarie affinché un metodo o una funzione faccia il suo lavoro.
Luminoso

20
Tutto teoricamente possibilmente essere null è come ogni metodo in una libreria che probabilmente chiama System.exit (0). Non è possibile verificare contro questo e non si dovrebbe verificare contro questo. Tutto ciò che dovresti fare tutto il tempo che in realtà non dovresti (quasi) mai fare. Come rendere definitivi tutti i parametri. Lascia che i tuoi strumenti ti aiutino a prevenire la modifica dei valori dei parametri o dimenticare di inizializzare i campi invece di rendere il tuo codice illeggibile per migliaia di finali e altrettanti controlli nulli.
yeoman,

6
In realtà basta usare le annotazioni NonNull / Nullable, ecco cosa stai cercando in questa situazione, non facoltativo.
Bill K,

Risposte:


202

Oh, quegli stili di codifica devono essere presi con un po 'di sale.

  1. (+) Passare un risultato Opzionale a un altro metodo, senza alcuna analisi semantica; lasciandolo al metodo, va bene.
  2. (-) L'uso di parametri opzionali che causano la logica condizionale all'interno dei metodi è letteralmente controproducente.
  3. (-) La necessità di comprimere un argomento in un facoltativo, non è ottimale per il compilatore ed esegue un wrapping non necessario.
  4. (-) Rispetto ai parametri nullable Opzionale è più costoso.

In generale: Opzionale unifica due stati, che devono essere svelati. Quindi più adatto per il risultato che per l'input, per la complessità del flusso di dati.


38
In realtà, avente un Optionalparametro rappresenta uno dei tre stati: un nullfacoltativo, un non nullo Optionalcon isPresent() == falsee non nullo Optionalavvolgendo un valore effettivo.
biziclop,

16
@biziclop sì, un punto inevitabile già criticato. Ma l' intenzione è di avere solo espressioni non nulle. Che non ci sia voluto molto, ascoltare i consigli per evitare Opzionale anche in alcuni casi, è abbastanza ironico. A @NotNull Optional.
Joop Eggen,

80
@biziclop Nota che se lo stai usando Optional, lo stato 1 ( nullOpzionale) indica di solito un errore di programmazione, quindi potresti non gestirlo (lascialo semplicemente lanciare a NullPointerException)
user253751

50
"subottimale per il compilatore", "Rispetto ai parametri nullable Opzionale è più costoso" - questi argomenti potrebbero essere validi per il linguaggio C e non per il linguaggio Java. I programmatori Java dovrebbero concentrarsi su codice pulito, portabilità, testabilità, buona architettura, modularità, ecc. E non su "Opzionale è più costoso di riferimento null". E se scopri che devi concentrarti sulle micro-ottimizzazioni, allora faresti meglio a saltare Oggetti, Elenchi, Generici e passare a matrici e primitive (non voglio essere offensivo qui, sto solo condividendo la mia opinione) .
Kacper86

15
"subottimale per il compilatore": l'ottimizzazione prematura è la radice di tutti i mali ... se non stai scrivendo un codice critico per le prestazioni (che spesso accade quando provi a specificare un'interfaccia pulita), questo non dovrebbe essere un problema.
Mohan,

165

Il miglior post che ho visto sull'argomento è stato scritto da Daniel Olszewski :

Sebbene possa essere allettante considerare Opzionale per i parametri del metodo non obbligatori, una soluzione del genere impallidisce rispetto ad altre possibili alternative. Per illustrare il problema, esaminare la seguente dichiarazione del costruttore:

public SystemMessage(String title, String content, Optional<Attachment> attachment) {
    // assigning field values
}

A prima vista può sembrare una giusta decisione di progettazione. Dopotutto, abbiamo esplicitamente contrassegnato il parametro allegato come facoltativo. Tuttavia, per quanto riguarda la chiamata al costruttore, il codice client può diventare un po 'goffo.

SystemMessage withoutAttachment = new SystemMessage("title", "content", Optional.empty());
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", Optional.ofNullable(attachment));

Invece di fornire chiarezza, i metodi di fabbrica della classe Optional distraggono solo il lettore. Nota che c'è solo un parametro opzionale, ma immagina di averne due o tre. Lo zio Bob non sarebbe sicuramente orgoglioso di tale codice 😉

Quando un metodo può accettare parametri opzionali, è preferibile adottare l'approccio ben collaudato e progettare tale caso utilizzando il metodo di sovraccarico. Nell'esempio della classe SystemMessage, la dichiarazione di due costruttori separati è superiore all'utilizzo di Opzionale.

public SystemMessage(String title, String content) {
    this(title, content, null);
}

public SystemMessage(String title, String content, Attachment attachment) {
    // assigning field values
}

Questa modifica rende il codice client molto più semplice e facile da leggere.

SystemMessage withoutAttachment = new SystemMessage("title", "content");
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);

10
È molto copia + incolla quando sono rilevanti solo uno o due paragrafi.
Garret Wilson,

47
Sfortunatamente questa spiegazione non risolve il problema di quando il chiamante, ad esempio, analizzando alcune informazioni può essere facoltativo. Con il metodo di sovraccarico (come raccomandato sopra), il codice chiamante deve dire "È presente X? In tal caso, chiamerò il metodo sovraccarico A. È presente Y? Dovrò chiamare il metodo sovraccarico B. Se X e Y sono presenti, dovrò chiamare il metodo sovraccarico C. " E così via. Potrebbe esserci una buona risposta a questo, ma questa spiegazione del "perché" non lo copre.
Garret Wilson,

9
Inoltre, quando si tratta di raccolte, esiste una netta differenza tra una raccolta vuota e nessuna raccolta. Ad esempio, una cache. È stata una mancanza di cache? vuoto facoltativo / null. C'è stato un hit della cache che sembra essere una raccolta vuota? full optional / collezione.
Ajax

1
@Ajax Penso che tu abbia frainteso l'articolo. Stanno citando un punto sostenuto dall'efficace libro Java , in cui si dice che quando un tipo restituito da un metodo è una raccolta (non un oggetto arbitrario come verrebbe restituito da una cache), si dovrebbe favorire la restituzione di una raccolta vuota anziché nullo Optional.
Gili,

4
Certo, dovresti favorirlo , ma non hai sempre il controllo su un po 'di codice e, in un senso molto reale, potresti voler distinguere tra "c'è un valore ed è una raccolta vuota" contro "non c'è valore definito (ancora) ". Dato che "magic null" è anche una pratica scoraggiata, spetta a te, lo sviluppatore, scegliere l'opzione meno negativa. Preferisco l'opzione facoltativa vuota per rappresentare un errore nella cache anziché una raccolta vuota, poiché il valore effettivo memorizzato nella cache potrebbe essere una raccolta vuota.
Ajax,

86

Non ci sono quasi buoni motivi per non utilizzare Optionalcome parametri. Gli argomenti contro questo si basano su argomenti dell'autorità (vedi Brian Goetz - il suo argomento è che non possiamo far valere opzioni non nulle) o che gli Optionalargomenti possono essere nulli (essenzialmente lo stesso argomento). Naturalmente, qualsiasi riferimento in Java può essere nullo, dobbiamo incoraggiare le regole imposte dal compilatore, non la memoria dei programmatori (il che è problematico e non scalabile).

I linguaggi di programmazione funzionale incoraggiano i Optionalparametri. Uno dei modi migliori per utilizzarlo è disporre di più parametri opzionali e utilizzare liftM2per utilizzare una funzione presupponendo che i parametri non siano vuoti e restituire un facoltativo (vedere http://www.functionaljava.org/javadoc/4.4/functionaljava/fj/ data / Option.html # liftM2-fj.F- ). Java 8 ha purtroppo implementato una libreria molto limitata con supporto opzionale.

Come programmatori Java dovremmo usare null solo per interagire con le librerie legacy.


3
Che ne dici di usare @Nonnulle @Nullableda javax.annotation invece? Li uso ampiamente in una libreria che sviluppo e il supporto fornito dall'IDE (IntelliJ) è molto buono.
Rogério,

1
Va bene, ma devi usare questa annotazione ovunque e hai bisogno di una libreria per supportare metodi come mappa, flatMap / bind, liftM2, sequenza, ecc.
Mark Perry,

14
I linguaggi di programmazione funzionale incoraggiano i parametri opzionali. Citazione necessaria. La maggior parte delle funzioni non dovrebbe assumere un optional; invece, l'onere di trattare (usando appropriate funzioni di ordine superiore) con la presenza o l'assenza di un valore è sul chiamante della funzione in questione.
jub0bs,

5
Questo. In effetti, nessuna delle risposte è abbastanza convincente, e nessuna di esse risponde a questa domanda specifica "perché usare gli opzionali come parametri di metodo è considerato una cattiva pratica mentre annotare i parametri di metodo @NonNullè del tutto corretto se servono allo stesso scopo in modi diversi?" Per me, c'è solo un argomento che ha almeno un po 'di senso: "Opzionale dovrebbe essere usato per fornire API migliori che hanno un chiaro tipo di ritorno. Comunque per argomenti di metodo, possono essere usate funzioni sovraccaricate". - Tuttavia, non credo che questo sia un argomento abbastanza forte.
Utku Özdemir,

1
Certo, preferibile a null, ma ciò che è ancora più preferibile è non aver bisogno di molti valori opzionali in primo luogo perché un buon design: D
yeoman

12

Questo consiglio è una variante della regola empirica "essere il più aspecifico possibile riguardo agli input e il più specifico possibile riguardo agli output".

Di solito se si dispone di un metodo che accetta un valore semplice non nullo, è possibile mapparlo su Optional, quindi la versione normale è strettamente più non specifica per quanto riguarda gli input. Tuttavia, ci sono una serie di possibili ragioni per cui si vorrebbe richiedere un Optionalargomento:

  • vuoi che la tua funzione sia usata insieme ad un'altra API che restituisce un Optional
  • La tua funzione dovrebbe restituire qualcosa di diverso da uno vuoto Optionalse il valore dato è vuoto
  • Pensi che Optionalsia così fantastico che a chiunque usi la tua API dovrebbe essere richiesto di conoscerlo ;-)

10

Il modello con Optionalè per evitare di tornare null . È ancora perfettamente possibile passare nulla un metodo.

Anche se questi non sono ancora ufficiali, puoi usare le annotazioni in stile JSR-308 per indicare se accetti o meno i nullvalori nella funzione. Tieni presente che dovresti avere gli strumenti giusti per identificarlo effettivamente e fornirebbe più di un controllo statico rispetto a una politica di runtime applicabile, ma sarebbe di aiuto.

public int calculateSomething(@NotNull final String p1, @NotNull final String p2) {}

Il problema qui è piuttosto che @NotNull non è il caso predefinito e deve essere annotato in modo esplicito - quindi piastra di cottura e cose che le persone semplicemente non faranno a causa della pigrizia.
dwegener,

1
@dwegener Sì, ma Optionalnon risolve nemmeno il problema, quindi il mio suggerimento per le annotazioni.
Makoto,

2
È molto più difficile ignorare Opzionale piuttosto che ignorare un'annotazione che noterai solo se leggi i documenti / la fonte o se i tuoi strumenti possono prenderli (l'analisi statica non può sempre determinare nulla annulla correttamente).
Ajax

Nota che @Nullable potrebbe non significare che "accetti" null come valore valido, ovvero non generare alcuna eccezione. Può significare solo che ti guardi da questo caso, ma genererà comunque un'eccezione (questa è la semantica di Findbugs). Quindi puoi introdurre ambiguità con tali annotazioni anziché chiarezza.
tkruse,

Non sono sicuro di quale ambiguità ci sia @ user2986984. "Non gestire null" potrebbe solo realisticamente significare che viene generata un'eccezione.
Makoto,

7

Questo mi sembra un po 'sciocco, ma l'unica ragione a cui riesco a pensare è che gli argomenti degli oggetti nei parametri del metodo sono già opzionali in un certo senso: possono essere nulli. Pertanto forzare qualcuno a prendere un oggetto esistente e avvolgerlo in un optional è inutile.

Detto questo, concatenare insieme metodi che prendono / restituiscono opzioni è una cosa ragionevole da fare, ad es. Forse monade.


7
Anche i valori e i campi di restituzione non possono essere nulli? Quindi Optionalè del tutto inutile?
Samuel Edwin Ward,


4

La mia opinione è che Opzionale dovrebbe essere una Monade e questi non sono concepibili in Java.

Nella programmazione funzionale hai a che fare con funzioni di ordine puro e superiore che accettano e compongono i loro argomenti solo in base al loro "tipo di dominio aziendale". La composizione di funzioni che si nutrono o il cui calcolo deve essere riferito al mondo reale (i cosiddetti effetti collaterali) richiede l'applicazione di funzioni che si occupano di decomprimere automaticamente i valori dalle monadi che rappresentano il mondo esterno (Stato, Configurazione, Futures, forse, entrambi, scrittore, ecc ...); questo si chiama sollevamento. Puoi pensarlo come una sorta di separazione delle preoccupazioni.

Mischiare questi due livelli di astrazione non facilita la leggibilità, quindi è meglio evitarlo.


3

Un altro motivo per essere cauti quando si passa un Optionalparametro as è che un metodo dovrebbe fare una cosa ... Se si passa un Optionalparametro si potrebbe preferire fare più di una cosa, potrebbe essere simile passare un parametro booleano.

public void method(Optional<MyClass> param) {
     if(param.isPresent()) {
         //do something
     } else {
         //do some other
     }
 }

Penso che non sia una buona ragione. La stessa logica potrebbe essere applicata per verificare se param è nullo quando non viene utilizzato facoltativo. In realtà, if(param.isPresent())non è l'approccio migliore per usare Opzionale, invece puoi usare:param.forEach(() -> {...})
hdkrus

Non mi piace nemmeno l'idea di passare parametri nullable. Comunque, ho detto che potresti favorire, ovviamente ci sono delle eccezioni che potresti usare, dipende da te, basta usarlo con attenzione, tutto qui. Non esiste alcuna regola applicabile per tutti gli scenari.
Pau,

2

L'accettazione di Opzionale come parametri provoca un avvolgimento non necessario a livello del chiamante.

Ad esempio nel caso di:

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {}

Supponiamo di avere due stringhe non nulle (cioè restituite da un altro metodo):

String p1 = "p1"; 
String p2 = "p2";

Sei costretto a avvolgerli in Opzionale anche se sai che non sono vuoti.

Questo peggiora anche quando devi comporre con altre strutture "mappabili", ad es. Eithers :

Either<Error, String> value = compute().right().map((s) -> calculateSomething(
< here you have to wrap the parameter in a Optional even if you know it's a 
  string >));

ref:

i metodi non dovrebbero aspettarsi Opzione come parametri, questo è quasi sempre un odore di codice che indicava una perdita del flusso di controllo dal chiamante alla chiamata, dovrebbe essere responsabilità del chiamante controllare il contenuto di un'Opzione

rif. https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749


1

Penso che sia perché di solito scrivi le tue funzioni per manipolare i dati, e poi elevali Optionalall'utilizzo mape funzioni simili. Ciò aggiunge il Optionalcomportamento predefinito ad esso. Certo, potrebbero esserci casi in cui è necessario scrivere la propria funzione ausiliaria su cui funziona Optional.


1

Credo che la risposta dell'essere sia che devi prima verificare se Opzionale è nullo stesso e quindi provare a valutare il valore che avvolge. Troppe convalide non necessarie.


2
Passare un riferimento facoltativo nullo può essere considerato un errore di programmazione (poiché Opzionale fornisce un modo esplicito di passare un valore "vuoto"), quindi non vale la pena controllarlo, a meno che non si desideri evitare di generare eccezioni in tutti i casi.
pvgoran,

1

Gli optionals non sono progettati per questo scopo, come spiegato bene da Brian Goetz .

Puoi sempre usare @Nullable per indicare che un argomento del metodo può essere nullo. L'uso di un facoltativo non ti consente davvero di scrivere in modo più accurato la logica del tuo metodo.


5
Mi dispiace, ma non posso essere d'accordo con l'argomento "non è stato progettato" o "qualcuno lo raccomanda". Un ingegnere dovremmo essere specifici. Usare @Nullable è molto peggio che usare Opzionale, perché gli Optionals sono molto più dettagliati dal punto di vista dell'API. Non vedo buone ragioni per non usare Optionals come argomenti (a condizione che tu non voglia usare il metodo di overloading)
Kacper86

0

Un altro approccio, quello che puoi fare è

// get your optionals first
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();

// bind values to a function
Supplier<Integer> calculatedValueSupplier = () -> { // your logic here using both optional as state}

Una volta che hai creato una funzione (fornitore in questo caso) sarai in grado di passarla come qualsiasi altra variabile e sarai in grado di chiamarla usando

calculatedValueSupplier.apply();

L'idea qui è se hai un valore facoltativo o meno sarà il dettaglio interno della tua funzione e non sarà nel parametro. Pensare funzioni quando si pensa all'opzionale come parametro è in realtà una tecnica molto utile che ho trovato.

Per quanto riguarda la tua domanda se dovresti effettivamente farlo o meno si basa sulle tue preferenze, ma come altri hanno detto che rende la tua API brutta a dir poco.


0

All'inizio, ho anche preferito passare gli Optionals come parametro, ma se passi da una prospettiva API-Designer a una prospettiva API-User, vedi gli svantaggi.

Per il tuo esempio, dove ogni parametro è facoltativo, suggerirei di cambiare il metodo di calcolo in una propria classe come segue:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();

MyCalculator mc = new MyCalculator();
p1.map(mc::setP1);
p2.map(mc::setP2);
int result = mc.calculate();

0

So che questa domanda riguarda più l'opinione che i fatti concreti. Ma di recente sono passato dall'essere uno sviluppatore .net a uno java, quindi di recente mi sono unito alla festa opzionale. Inoltre, preferirei dichiararlo come commento, ma poiché il mio livello di punti non mi consente di commentare, sono costretto a inserire questo come risposta.

Quello che ho fatto, che mi ha servito bene come regola empirica. Utilizzare Optionals per i tipi di restituzione e utilizzare Optionals solo come parametri, se richiedo sia il valore dell'Opzionale, sia il tempo o meno l'Opzionale aveva un valore all'interno del metodo.

Se mi interessa solo il valore, controllo isPresent prima di chiamare il metodo, se ho un tipo di registrazione o logica diversa all'interno del metodo che dipende dall'esistenza del valore, allora passerò felicemente nell'Opzionale.


0

Questo perché abbiamo requisiti diversi per un utente API e uno sviluppatore API.

Uno sviluppatore è responsabile di fornire una specifica precisa e un'implementazione corretta. Pertanto, se lo sviluppatore è già a conoscenza del fatto che un argomento è facoltativo, l'implementazione deve gestirlo correttamente, sia esso nullo o facoltativo. L'API dovrebbe essere il più semplice possibile per l'utente e null è il più semplice.

D'altra parte, il risultato viene passato dallo sviluppatore API all'utente. Tuttavia, la specifica è completa e dettagliata, c'è ancora la possibilità che l'utente non ne sia consapevole o sia solo pigro a gestirla. In questo caso, il risultato facoltativo impone all'utente di scrivere del codice aggiuntivo per gestire un possibile risultato vuoto.


0

Prima di tutto, se stai usando il metodo 3, puoi sostituire quelle ultime 14 righe di codice con questo:

int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

Le quattro varianti che hai scritto sono metodi convenienti . Dovresti usarli solo quando sono più convenienti. Questo è anche l'approccio migliore. In questo modo, l'API è molto chiara su quali membri sono necessari e quali no. Se non si desidera scrivere quattro metodi, è possibile chiarire le cose in base al nome dei parametri:

public int calculateSomething(String p1OrNull, BigDecimal p2OrNull)

In questo modo, è chiaro che sono ammessi valori null.

Il tuo uso di p1.orElse(null)illustra quanto è dettagliato il nostro codice quando si utilizza Opzionale, il che è parte del motivo per cui lo evito. Opzionale è stato scritto per la programmazione funzionale. I flussi ne hanno bisogno. I tuoi metodi probabilmente non dovrebbero mai restituire Opzionale a meno che non sia necessario usarli nella programmazione funzionale. Esistono metodi, come il Optional.flatMap()metodo, che richiedono un riferimento a una funzione che restituisce Facoltativo. Ecco la sua firma:

public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)

Quindi questa è di solito l'unica buona ragione per scrivere un metodo che ritorna Opzionale. Ma anche lì, può essere evitato. Puoi passare un getter che non restituisce Opzionale a un metodo come flatMap (), avvolgendolo in un altro metodo che converte la funzione nel tipo giusto. Il metodo wrapper è simile al seguente:

public static <T, U> Function<? super T, Optional<U>> optFun(Function<T, U> function) {
    return t -> Optional.ofNullable(function.apply(t));
}

Supponiamo quindi di avere un getter come questo: String getName()

Non puoi passarlo a flatMap in questo modo:

opt.flatMap(Widget::getName) // Won't work!

Ma puoi passarlo così:

opt.flatMap(optFun(Widget::getName)) // Works great!

Al di fuori della programmazione funzionale, gli Optionals dovrebbero essere evitati.

Brian Goetz l'ha detto meglio quando ha detto questo:

Il motivo per cui Opzionale è stato aggiunto a Java è perché questo:

return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .findFirst()
    .getOrThrow(() -> new InternalError(...));

è più pulito di così:

Method matching =
    Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .getFirst();
if (matching == null)
  throw new InternalError("Enclosing method not found");
return matching;

1
Bene, questo è uno dei motivi per cui è stato aggiunto a Java. Ce ne sono molti altri. La sostituzione di lunghe catene di istruzioni "if" nidificate che attraversano una struttura di dati con una singola sequenza di chiamate concatenate a Optional.map è il mio preferito personale. Il mondo della programmazione di Linguaggi funzionali ha molti usi interessanti per Opzionale oltre a sostituire semplicemente i controlli null come questo.
Qualcuno il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.