Il motivo è Optional
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;
Il mio punto è che Opzionale è stato scritto per supportare la programmazione funzionale , che è stata aggiunta a Java contemporaneamente. (L'esempio viene fornito da un blog di Brian Goetz . Un esempio migliore potrebbe usare il orElse()
metodo, poiché questo codice genererà comunque un'eccezione, ma ottieni l'immagine.)
Ma ora, le persone usano Opzionale per un motivo molto diverso. Lo stanno usando per correggere un difetto nel design del linguaggio. Il difetto è questo: non c'è modo di specificare quali dei parametri di un'API e i valori restituiti possono essere nulli. Può essere menzionato nei javadocs, ma la maggior parte degli sviluppatori non scrive nemmeno javadocs per il loro codice e non molti controlleranno i javadocs mentre scrivono. Quindi questo porta a un sacco di codice che controlla sempre i valori null prima di usarli, anche se spesso non possono essere nulli perché sono già stati validati ripetutamente nove o dieci volte nello stack di chiamate.
Penso che ci sia stata una vera sete per risolvere questo difetto, perché così tante persone che hanno visto la nuova classe Optional hanno assunto il suo scopo era quello di aggiungere chiarezza alle API. È per questo che le persone fanno domande del tipo "se i vincitori dovrebbero restituire gli Optionals?" No, probabilmente non dovrebbero, a meno che non ti aspetti che il getter venga utilizzato nella programmazione funzionale, il che è molto improbabile. In effetti, se si guarda dove viene utilizzato Opzionale nell'API Java, è principalmente nelle classi Stream, che sono il nucleo della programmazione funzionale. (Non ho controllato molto attentamente, ma le classi Stream potrebbero essere l' unico posto in cui vengono utilizzate.)
Se si prevede di utilizzare un getter in un po 'di codice funzionale, potrebbe essere una buona idea avere un getter standard e un secondo che restituisca Opzionale.
Oh, e se hai bisogno che la tua classe sia serializzabile, non dovresti assolutamente usare Opzionale.
Gli optionals sono una pessima soluzione al difetto dell'API perché a) sono molto dettagliati eb) Non sono mai stati pensati per risolvere quel problema in primo luogo.
Una soluzione molto migliore al difetto dell'API è il Controllo nullità . Questo è un processore di annotazione che ti consente di specificare quali parametri e valori di ritorno possono essere nulli annotandoli con @Nullable. In questo modo, il compilatore può eseguire la scansione del codice e capire se un valore che può essere effettivamente null viene passato a un valore in cui null non è consentito. Per impostazione predefinita, presuppone che nulla sia autorizzato a essere null a meno che non sia annotato in tal modo. In questo modo, non devi preoccuparti di valori null. Passare un valore null a un parametro comporterà un errore del compilatore. Testare un oggetto per null che non può essere null produce un avviso del compilatore. L'effetto di questo è di cambiare NullPointerException da un errore di runtime a un errore di compilazione.
Questo cambia tutto.
Per quanto riguarda i tuoi getter, non usare Opzionale. E prova a progettare le tue classi in modo che nessuno dei membri possa essere nullo. E forse prova ad aggiungere Nullness Checker al tuo progetto e a dichiarare i tuoi getter e parametri setter @Nullable se ne hanno bisogno. L'ho fatto solo con nuovi progetti. Probabilmente produce molti avvertimenti nei progetti esistenti scritti con molti test superflui per null, quindi potrebbe essere difficile aggiornarlo. Ma catturerà anche molti bug. Lo adoro. Il mio codice è molto più pulito e più affidabile per questo.
(C'è anche un nuovo linguaggio che si rivolge a questo. Kotlin, che si compila in codice byte Java, ti permette di specificare se un oggetto può essere nullo quando lo dichiari. È un approccio più pulito.)
Addendum al messaggio originale (versione 2)
Dopo averci riflettuto molto, sono giunto con riluttanza alla conclusione che è accettabile restituire Opzionale a una condizione: che il valore recuperato potrebbe effettivamente essere nullo. Ho visto un sacco di codice in cui le persone restituiscono routinariamente Facoltativamente da getter che non possono restituire null. Vedo questo come una brutta pratica di codifica che aggiunge complessità al codice, il che rende più probabili i bug. Ma quando il valore restituito potrebbe effettivamente essere nullo, andare avanti e racchiuderlo in un Opzionale.
Tieni presente che i metodi progettati per la programmazione funzionale e che richiedono un riferimento di funzione, saranno (e dovrebbero) essere scritti in due forme, una delle quali utilizza Opzionale. Ad esempio, Optional.map()
ed Optional.flatMap()
entrambi accettano riferimenti a funzioni. Il primo prende un riferimento a un normale getter e il secondo ne prende uno che ritorna Opzionale. Quindi non stai facendo un favore a nessuno restituendo un Opzionale in cui il valore non può essere nullo.
Detto questo, vedo ancora che l'approccio utilizzato da Nullness Checker è il modo migliore per gestire i valori null, poiché trasformano NullPointerExceptions da bug di runtime in errori di compilazione.