Membungkus metode pengembalian nol di Jawa dengan Opsi di Scala?

107

Misalkan saya memiliki metode session.get(str: String): Stringtetapi Anda tidak tahu apakah itu akan mengembalikan Anda string atau null, karena berasal dari Java.

Apakah ada cara yang lebih mudah untuk menangani ini di Scala daripada session.get("foo") == null? Mungkin beberapa sihir berlaku seperti ToOption(session.get("foo"))dan kemudian saya bisa memperlakukannya seperti Scala

ToOption(session.get("foo")) match {
    case Some(_) =>;
    case None =>;
}
José Leal
sumber
4
Untuk trik Opsi lainnya, lihat blog.tmorris.net/scalaoption-cheat-sheet
Landei
4
Tautan di atas haruslah blog.tmorris.net/posts/scalaoption-cheat-sheet .
Jacek Laskowski

Jawaban:

182

Metode Optionobjek pendamping applyberfungsi sebagai fungsi konversi dari referensi nullable:

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

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

The Optionobjek memiliki applymetode yang tidak tepat:

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

Perhatikan bahwa saat bekerja dengan objek Java itu tidak akan berfungsi seperti yang diharapkan:

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
sumber
1
Saya menjalankan dengan scala 2.11.8. Baris kedua menampilkan NullPointerException. Baris keenam mendapatkan Some (null), bukan None seperti yang Anda harapkan.
John Lin
1. Digunakan Beberapa daripada Option di optionString - Berubah dalam jawaban asli. 2. Diverifikasi hanya di Scala 2.12.5
DekelM
-3

Ini adalah topik yang sangat lama tapi bagus!

Memang benar bahwa mengubah hasil Non-pengecualian dari Try to Option akan menghasilkan Beberapa ...

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

... karena Try bukan tentang pemeriksaan nullability tetapi hanya cara untuk menangani pengecualian secara fungsional.

Menggunakan Coba untuk menangkap pengecualian dan mengubahnya menjadi Opsi untuk kenyamanan hanya akan menampilkan Tidak Ada jika terjadi pengecualian.

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

Anda ingin melestarikan nilai-nilai yang keluar dari Try. Itu mungkin nol.

Tetapi juga benar bahwa lib standar terkadang cukup membingungkan ...

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

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

Perilaku ini agak tidak konsisten tetapi ini mencerminkan penggunaan yang diinginkan dari Try dan Option.

Anda menggunakan mencoba untuk mendapatkan apa pun yang keluar dari ekspresi yang mungkin memunculkan pengecualian, dan Anda tidak peduli dengan pengecualian itu sendiri.

Nilai yang mungkin keluar mungkin saja nol. Jika toOption memberikan Tidak ada, Anda tidak dapat membedakan antara pengecualian dan nol , dan itu tidak cantik!

Mandiri, Anda menggunakan Option untuk merangkum ada atau tidaknya sesuatu. Jadi dalam kasus itu Some (null) is None, dan itu masuk akal, karena null dalam kasus itu mewakili tidak adanya sesuatu. Tidak ada ambiguitas di sini.

Penting untuk diperhatikan bahwa dalam hal apapun transparansi referensial tidak rusak karena .toOption tidak sama dengan Option ()

Jika Anda benar-benar perlu menegakkan KEDUA keamanan pengecualian DAN keamanan nol, dan kode Anda benar-benar tidak perlu membedakan antara nol dan pengecualian , Anda hanya perlu menggabungkan kedua paradigma! Karena yah, itu yang kamu inginkan, bukan?

Anda dapat melakukannya dengan satu cara ...

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)

... atau lainnya ...

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)

... atau yang paling jelek dari mereka yang lain ...

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
sumber