¿Envolviendo el método de devolución de nulos en Java con Option en Scala?

107

Suponga que tengo un método session.get(str: String): Stringpero no sabe si le devolverá una cadena o un nulo, porque proviene de Java.

¿Hay una forma más fácil de tratar esto en Scala en lugar de session.get("foo") == null? Tal vez se aplique algo de magia ToOption(session.get("foo"))y luego pueda tratarlo en Scala como

ToOption(session.get("foo")) match {
    case Some(_) =>;
    case None =>;
}
José Leal
fuente
4
Para obtener más trucos de opciones, consulte blog.tmorris.net/scalaoption-cheat-sheet
Landei
4
El enlace anterior debería ser blog.tmorris.net/posts/scalaoption-cheat-sheet .
Jacek Laskowski

Respuestas:

182

El método Optiondel objeto complementario applysirve como función de conversión de referencias que aceptan valores NULL:

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

scala> Option(3)   
res5: Option[Int] = Some(3)
Tom Crockett
fuente
19

El Optionobjeto tiene un applymétodo que hace exactamente eso:

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

Tenga en cuenta que al trabajar con objetos Java, no funcionará como se esperaba:

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
DekelM
fuente
1
Corrí con scala 2.11.8. La segunda línea arrojó NullPointerException. La sexta línea obtuvo Algunos (nulo), no Ninguno como esperaba.
John Lin
1. Usó Some en lugar de Option en optionString - Cambiado en la respuesta original. 2. Verificado solo en Scala 2.12.5
DekelM
-3

¡Este es un tema muy antiguo pero agradable!

Es cierto que convertir cualquier resultado que no sea de excepción de Try to Option dará como resultado un Some ...

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

... porque Try no se trata de verificar la nulabilidad, sino solo de una forma de manejar funcionalmente las excepciones.

El uso de Intentar detectar una excepción y convertirla en una Opción por conveniencia solo mostrará Ninguno en caso de que ocurra una excepción.

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

Desea conservar los valores que surgen de Try. Eso puede ser nulo.

Pero también es cierto que la librería estándar a veces es bastante confusa ...

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

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

Este comportamiento es un poco inconsistente, pero refleja el uso intencionado de Try y Option.

Usas try para obtener lo que sea que surja de una expresión que pueda generar excepciones, y no te importa la excepción en sí.

El valor que puede aparecer puede muy bien ser nulo. Si toOption dio None, no podría diferenciar entre una excepción y un nulo , ¡y eso no es bonito!

Independiente, usa Option para encapsular la existencia o no de algo. Entonces, en ese caso, Some (null) es None, y eso tiene sentido, porque null en ese caso representa la ausencia de algo. Aquí no hay ambigüedad.

Es importante remarcar que en cualquier caso la transparencia referencial no se rompe ya que .toOption no es lo mismo que Option ()

Si realmente necesita para hacer cumplir AMBOS seguridad de excepción y la seguridad nula, y su código realmente no necesita estudio diferencial entre nulo y una excepción , sólo tiene que combinar ambos paradigmas! Porque bueno, eso es lo que quieres, ¿verdad?

Puedes hacerlo de una manera ...

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)

... u otro ...

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 el ridículamente más feo de ellos otros ...

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)
David Royo
fuente