Enveloppant la méthode de retour nul en Java avec Option dans Scala?

107

Supposons que j'ai une méthode session.get(str: String): Stringmais que vous ne savez pas si elle vous renverra une chaîne ou une valeur nulle, car elle provient de Java.

Existe-t-il un moyen plus simple de traiter cela dans Scala au lieu de session.get("foo") == null? Peut-être qu'un peu de magie s'applique comme ToOption(session.get("foo"))et ensuite je peux le traiter à la manière Scala comme

ToOption(session.get("foo")) match {
    case Some(_) =>;
    case None =>;
}
José Leal
la source
4
Pour plus d'astuces Option, voir blog.tmorris.net/scalaoption-cheat-sheet
Landei
4
Le lien ci-dessus doit être blog.tmorris.net/posts/scalaoption-cheat-sheet .
Jacek Laskowski

Réponses:

182

La méthode de Optionl'objet compagnon applysert de fonction de conversion à partir des références Nullable:

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

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

L' Optionobjet a une applyméthode qui fait exactement cela:

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

Notez que lorsque vous travaillez avec des objets Java, cela ne fonctionnera pas comme prévu:

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
la source
1
J'ai couru avec scala 2.11.8. La deuxième ligne a renvoyé NullPointerException. La sixième ligne a obtenu Some (null), pas None comme prévu.
John Lin
1. Utilisé Some au lieu d'Option dans optionString - Modifié dans la réponse d'origine. 2. Vérifié uniquement dans Scala 2.12.5
DekelM
-3

C'est un sujet très ancien mais intéressant!

Il est vrai que la conversion de tout résultat Non-exception de Try to Option entraînera un Some ...

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

... parce que Try ne concerne pas la vérification de la nullité, mais simplement un moyen de gérer fonctionnellement les exceptions.

Utiliser Try pour attraper une exception et la convertir en Option pour plus de commodité n'affichera None que si une exception se produit.

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

Vous souhaitez conserver les valeurs issues de Try. Cela peut être nul.

Mais il est également vrai que la lib standard est parfois assez déroutante ...

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

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

Ce comportement est un peu incohérent, mais il reflète en quelque sorte l'utilisation intentionnelle de Try et Option.

Vous utilisez essayer d'obtenir tout ce qui sort d'une expression qui peut lever des exceptions, et vous ne vous souciez pas de l'exception elle-même.

La valeur qui peut sortir peut très bien être une valeur nulle. Si toOption donnait None, vous ne pouviez pas faire la différence entre une exception et une null , et ce n'est pas joli!

Autonome, vous utilisez Option pour encapsuler l'existence ou non de quelque chose. Donc, dans ce cas, Some (null) vaut None, et cela a du sens, car null dans ce cas représente l'absence de quelque chose. Il n'y a pas d'ambiguïté ici.

Il est important de noter que dans tous les cas, la transparence référentielle n'est pas rompue car .toOption n'est pas la même chose que Option ()

Si vous avez vraiment besoin de faire respecter BOTH la sécurité d'exception et la sécurité nulle et votre code vraiment ne pas vraiment besoin de Différencier entre null et une exception , il vous suffit de combiner les deux paradigmes! Parce que bon, c'est ce que tu veux, non?

Vous pouvez le faire d'une manière ...

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)

... ou un autre ...

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)

... ou le plus ridiculement laid d'entre eux et d'autres ...

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
la source