Opakowanie metody zwracającej wartość null w Javie z opcją w Scali?

107

Załóżmy, że mam metodę, session.get(str: String): Stringale nie wiesz, czy zwróci ci ona ciąg znaków, czy wartość null, ponieważ pochodzi z Javy.

Czy jest łatwiejszy sposób na rozwiązanie tego problemu w Scali zamiast session.get("foo") == null? Może jakaś magia się zastosuje, ToOption(session.get("foo"))a potem będę mógł to traktować w sposób Scala

ToOption(session.get("foo")) match {
    case Some(_) =>;
    case None =>;
}
José Leal
źródło
4
Więcej sztuczek z opcjami można
Landei,
4
Powyższy link powinien mieć postać blog.tmorris.net/posts/scalaoption-cheat-sheet .
Jacek Laskowski

Odpowiedzi:

182

Metoda Optionobiektu towarzyszącego applysłuży jako funkcja konwersji z odwołań dopuszczających wartość null:

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

scala> Option(3)   
res5: Option[Int] = Some(3)
Tom Crockett
źródło
19

OptionObiekt ma applymetody, która robi dokładnie to:

var myOptionalString = Option(session.get("foo"));
RoToRa
źródło
5

Zauważ, że podczas pracy z obiektami Java nie będzie działać zgodnie z oczekiwaniami:

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
źródło
1
Biegałem ze Scalą 2.11.8. Druga linia zgłosiła wyjątek NullPointerException. Szósta linia otrzymała Some (null), a nie None, zgodnie z oczekiwaniami.
John Lin
1. Użyto Some zamiast Option w optionString - Zmieniono w oryginalnej odpowiedzi. 2. Zweryfikowano tylko w Scali 2.12.5
DekelM
-3

To bardzo stary temat, ale fajny!

Prawdą jest, że przekształcenie dowolnego wyniku trybu Non-wyjątek w Try na Option spowoduje, że ...

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

... ponieważ w Try nie chodzi o sprawdzanie wartości null, ale tylko o sposób na funkcjonalną obsługę wyjątków.

Użycie opcji Spróbuj przechwycić wyjątek i przekonwertowanie go na opcję dla wygody spowoduje wyświetlenie Brak tylko w przypadku wystąpienia wyjątku.

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

Chcesz zachować wartości wynikające z Try. To może być nieważne.

Ale prawdą jest również, że standardowa biblioteka czasami jest dość myląca ...

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

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

To zachowanie jest nieco niespójne, ale w pewnym sensie odzwierciedla zamierzone użycie zarówno Try, jak i Option.

Używasz try, aby uzyskać wszystko, co pochodzi z wyrażenia, które może rzucać wyjątki, i nie przejmujesz się samym wyjątkiem.

Wartość, która może się pojawić, może być zerowa. Jeśli toOption dało None, nie możesz odróżnić wyjątku od wartości null , a to nie jest ładne!

Samodzielnie, używasz Option, aby hermetyzować istnienie czegoś lub nie. Więc w tym przypadku Some (null) to None, i to ma sens, ponieważ null w tym przypadku oznacza brak czegoś. Nie ma tu dwuznaczności.

Należy zauważyć, że w żadnym przypadku przezroczystość referencyjna nie jest zepsuta, ponieważ .toOption to nie to samo, co Option ()

Jeśli naprawdę potrzebujesz wymusić ZARÓWNO bezpieczeństwo wyjątków ORAZ bezpieczeństwo zerowe, a Twój kod naprawdę nie musi rozróżniać między wartością zerową a wyjątkiem , wystarczy połączyć oba paradygmaty! Ponieważ cóż, tego właśnie chcesz, prawda?

Możesz to zrobić w jeden sposób ...

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)

... lub inny ...

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)

... lub śmiesznie brzydkie z nich inne ...

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
źródło