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.