Avvolgere il metodo di restituzione null in Java con Option in Scala?


107

Supponi di avere un metodo session.get(str: String): Stringma non sai se ti restituirà una stringa o un null, perché proviene da Java.

C'è un modo più semplice per trattare questo in Scala invece che session.get("foo") == null? Forse si applica un po 'di magia ToOption(session.get("foo"))e poi posso trattarlo in modo Scala come

ToOption(session.get("foo")) match {
    case Some(_) =>;
    case None =>;
}

4
Per altri trucchi per le opzioni, vedere blog.tmorris.net/scalaoption-cheat-sheet
— Landei

4
Il collegamento sopra dovrebbe essere blog.tmorris.net/posts/scalaoption-cheat-sheet .
— Jacek Laskowski

Risposte:


182

Il metodo Optiondell'oggetto associato applyfunge da funzione di conversione da riferimenti nullable:

scala> Option(null)
res4: Option[Null] = None

scala> Option(3)   
res5: Option[Int] = Some(3)

19

L' Optionoggetto ha un applymetodo che fa esattamente questo:

var myOptionalString = Option(session.get("foo"));

5

Si noti che quando si lavora con oggetti Java non funzionerà come previsto:

val nullValueInteger : java.lang.Integer = null
val option: Option[Int] = Option(nullValueInteger)
println(option)  // Doesn't work - zero value on conversion

val nullStringValue : String = null
val optionString: Option[String] = Option(nullStringValue)
println(optionString) // Works - None value

1
Ho corso con scala 2.11.8. La seconda riga ha generato NullPointerException. La sesta riga ha ottenuto Some (null), not None come ti aspettavi.
— John Lin

1. Utilizzato Some invece di Option in optionString - Modificato nella risposta originale. 2. Verificato solo in Scala 2.12.5
— DekelM

-3

Questo è un argomento molto vecchio ma carino!

È vero che la conversione di qualsiasi risultato non eccezionale di Try to Option si tradurrà in un Some ...

scala> Try(null).toOption
res10: Option[Null] = Some(null)

... perché Try non riguarda il controllo del nullability ma solo un modo per gestire funzionalmente le eccezioni.

L'utilizzo di Try per catturare un'eccezione e la conversione di questa in un'opzione per comodità mostrerà Nessuno solo nel caso in cui si verifichi un'eccezione.

scala> Try(1/0).toOption
res11: Option[Int] = None

Vuoi preservare i valori che provengono da Try. Potrebbe essere nullo.

Ma è anche vero che la libreria standard a volte è abbastanza confusa ...

scala> Try(null).toOption
res12: Option[Null] = Some(null)

scala> Option(null)
res13: Option[Null] = None

Questo comportamento è un po 'incoerente ma in qualche modo riflette l'uso intenzionale di Try e Option.

Usi try per ottenere tutto ciò che esce da un'espressione che può generare eccezioni e non ti interessa l'eccezione stessa.

Il valore che potrebbe risultare potrebbe essere nullo. Se toOption ha dato None, non potresti distinguere tra un'eccezione e un null , e questo non è carino!

Standalone, usi Option per incapsulare l'esistenza o meno di qualcosa. Quindi in quel caso Some (null) è None, e questo ha senso, perché null in quel caso rappresenta l'assenza di qualcosa. Non c'è ambiguità qui.

È importante notare che in ogni caso la trasparenza referenziale non viene interrotta poiché .toOption non è la stessa cosa di Option ()

Se si ha realmente bisogno di far rispettare SIA sicurezza rispetto alle eccezioni E nulla la sicurezza, e il codice davvero non ha bisogno di distinzione fra nullo e un'eccezione , è sufficiente combinare entrambi i paradigmi! Perché beh, è ​​quello che vuoi, giusto?

Puoi farlo in un modo ...

scala> Try(Option(null)).getOrElse(None)
res23: Option[Null] = None

scala> Try(Option(3/0)).getOrElse(None)
res24: Option[Int] = None

scala> Try(Option(3)).getOrElse(None)
res25: Option[Int] = Some(3)

... oppure un'altra ...

scala> Try(Option(null)).toOption.flatten
res26: Option[Null] = None

scala> Try(Option(3/0)).toOption.flatten
res27: Option[Int] = None

scala> Try(Option(3)).toOption.flatten
res28: Option[Int] = Some(3)

... o il ridicolmente più brutto di loro altri ...

scala> Option(Try(null).getOrElse(null))
res29: Option[Null] = None

scala> Option(Try(3/0).getOrElse(null))
res30: Option[Any] = None

scala> Option(Try(3).getOrElse(null))
res31: Option[Any] = Some(3)
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.