การตัดวิธีการคืนค่า null ใน Java ด้วย Option ใน Scala?


107

สมมติว่าฉันมีวิธีการsession.get(str: String): Stringแต่คุณไม่รู้ว่ามันจะส่งคืนสตริงหรือค่าว่างให้คุณเพราะมันมาจาก Java

มีวิธีที่ง่ายกว่าในการรักษาสิ่งนี้ใน Scala แทนsession.get("foo") == nullหรือไม่? บางทีเวทย์มนตร์บางอย่างใช้ToOption(session.get("foo"))แล้วฉันสามารถรักษาด้วยวิธี Scala เช่น

ToOption(session.get("foo")) match {
    case Some(_) =>;
    case None =>;
}

4
สำหรับเคล็ดลับตัวเลือกเพิ่มเติมโปรดดูblog.tmorris.net/scalaoption-cheat-sheet
Landei

4
ที่ลิงค์ข้างต้นควรจะblog.tmorris.net/posts/scalaoption-cheat-sheet
Jacek Laskowski

คำตอบ:


182

Optionสหายของวัตถุapplyวิธีการทำหน้าที่เป็นฟังก์ชั่นการแปลงจากการอ้างอิง nullable:

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

scala> Option(3)   
res5: Option[Int] = Some(3)

19

Optionวัตถุมีapplyวิธีการที่ไม่ตรงกับที่:

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

5

สังเกตว่าเมื่อทำงานกับวัตถุ Java จะไม่ทำงานตามที่คาดไว้:

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
ฉันวิ่งด้วยสกาล่า 2.11.8 บรรทัดที่สองโยน NullPointerException บรรทัดที่หกมี Some (null) ไม่ใช่ None ตามที่คุณคาดไว้
John Lin

1. ใช้ Some แทน Option ใน optionString - เปลี่ยนคำตอบเดิม 2. ยืนยันเฉพาะใน Scala 2.12.5
DekelM

-3

นี่เป็นหัวข้อที่เก่ามาก แต่เป็นหัวข้อที่ดี!

เป็นความจริงที่การแปลงผลลัพธ์ที่ไม่ใช่ข้อยกเว้นของ Try to Option จะทำให้เกิด Some ...

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

... เพราะ Try ไม่เกี่ยวกับการตรวจสอบความว่างเปล่า แต่เป็นเพียงวิธีจัดการข้อยกเว้นตามหน้าที่เท่านั้น

การใช้ลองจับข้อยกเว้นและการแปลงเป็นตัวเลือกเพื่อความสะดวกจะแสดงเฉพาะไม่มีในกรณีที่มีข้อยกเว้นเกิดขึ้น

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

คุณต้องการรักษาค่าที่มาจาก Try นั่นอาจเป็นโมฆะ

แต่ก็เป็นความจริงเช่นกันที่ lib มาตรฐานค่อนข้างสับสนในบางครั้ง ...

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

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

ลักษณะการทำงานนี้ไม่สอดคล้องกันเล็กน้อย แต่สะท้อนถึงการใช้งานทั้ง Try และ Option ที่ตั้งใจไว้

คุณใช้พยายามดึงสิ่งที่ออกมาจากนิพจน์ที่อาจทำให้เกิดข้อยกเว้นและคุณไม่สนใจข้อยกเว้นนั้นเอง

ค่าที่ออกมาอาจเป็นค่าว่างก็ได้ หาก toOption ให้ None คุณจะไม่สามารถแยกความแตกต่างระหว่างข้อยกเว้นและค่าว่างได้และนั่นก็ไม่สวย!

แบบสแตนด์อโลนคุณใช้ตัวเลือกเพื่อห่อหุ้มการมีอยู่หรือไม่มีของบางสิ่ง ดังนั้นในกรณีนี้ Some (null) คือ None และนั่นก็สมเหตุสมผลเพราะ null ในกรณีนั้นแสดงถึงการไม่มีบางสิ่ง ที่นี่ไม่มีความคลุมเครือ

สิ่งสำคัญคือต้องสังเกตว่าไม่ว่าในกรณีใด ๆ ความโปร่งใสในการอ้างอิงจะไม่ถูกทำลายเนื่องจาก. toOption ไม่เหมือนกับ Option ()

ถ้าคุณต้องการจริงๆที่จะบังคับใช้ทั้งยกเว้นความปลอดภัยและ null ปลอดภัยและรหัสของคุณจริงๆไม่จำเป็นต้อง differenciate ระหว่างโมฆะและข้อยกเว้นคุณเพียงแค่ต้องรวมทั้งกรอบความคิด! เพราะนั่นคือสิ่งที่คุณต้องการใช่ไหม?

คุณสามารถทำได้ด้วยวิธีเดียว ...

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)

... หรืออีกอย่าง ...

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)

... หรือคนอื่นที่น่าเกลียดที่สุด ...

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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.