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 =>;
}

4
Untuk trik Opsi lainnya, lihat blog.tmorris.net/scalaoption-cheat-sheet
Landei

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)

19

The Optionobjek memiliki applymetode yang tidak tepat:

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

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

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)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.