1 คะแนน โดย GN⁺ 2024-08-04 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

Null-Restricted and Nullable Types (Preview)

สรุป

ฟีเจอร์ภาษารุ่นพรีวิวที่รองรับตัวทำเครื่องหมาย nullness ซึ่งใช้ระบุว่าประเภทใน Java ยอมรับหรือปฏิเสธ null ได้

เป้าหมาย

  • ปรับปรุงประเภทอ้างอิงของ Java เพื่อให้โปรแกรมเมอร์สามารถแสดงได้ว่าคาดหวังการอ้างอิง null หรือไม่
  • รองรับการแปลงระหว่างประเภทที่มีคุณสมบัติ nullness ต่างกัน และให้คำเตือนสำหรับค่า null ที่จัดการไม่ถูกต้อง
  • เข้ากันได้กับโค้ด Java เดิม และรองรับการนำฟีเจอร์ใหม่มาใช้แบบค่อยเป็นค่อยไป
  • รับประกันว่าตัวแปรของประเภทที่ปฏิเสธ null จะถูกกำหนดค่าเริ่มต้นก่อนถูกอ่านครั้งแรก
  • บังคับใช้ประเภทที่ปฏิเสธ null ในรันไทม์ แม้กับคลาสที่คอมไพล์แยกต่างหาก
  • ให้เมทาดาทาและการรับประกันความถูกต้องที่จำเป็นต่อการปรับแต่งประสิทธิภาพในรันไทม์

สิ่งที่ไม่ใช่เป้าหมาย

  • ไม่ตีความโค้ดเดิมใหม่โดยอัตโนมัติ
  • ไม่บังคับให้ต้องจัดการค่า null ทุกกรณีอย่างชัดเจน
  • ไม่รวมการเปลี่ยนแปลงสำหรับ primitive type
  • ไม่นำการปรับปรุงทางภาษาไปใช้กับไลบรารีมาตรฐาน

แรงจูงใจ

  • ในโปรแกรม Java ตัวแปรชนิด String สามารถมีได้ทั้งการอ้างอิงถึงอ็อบเจ็กต์ String หรือค่า null
  • ไม่มีวิธีแสดงอย่างชัดเจนว่าตัวแปรยอมรับ null หรือไม่ จึงก่อให้เกิดความสับสนและบั๊ก
  • จึงจำเป็นต้องมีเครื่องมือที่ช่วยให้นักพัฒนาระบุได้ว่าไทป์นั้นรองรับหรือคาดหวังค่า null เป็นส่วนหนึ่งของประเภท

คำอธิบาย

คุณสมบัติ nullness และตัวทำเครื่องหมาย

  • ประเภทอ้างอิงสามารถแสดง nullness ได้แบบเลือกใช้
  • Foo! คือประเภท null-restricted ที่ไม่รวม null
  • Foo? คือประเภท nullable ที่รวม null
  • โดยค่าเริ่มต้น Foo จะไม่ได้ระบุ nullness

การกำหนดค่าเริ่มต้นของฟิลด์และอาร์เรย์

  • ฟิลด์หรืออาร์เรย์แบบ null-restricted ต้องถูกกำหนดค่าเริ่มต้นก่อนใช้งานเสมอ
  • หากพยายามอ่านฟิลด์ null-restricted ที่ยังไม่ได้กำหนดค่าเริ่มต้น จะเกิดข้อยกเว้น

nullness ของนิพจน์และการแปลง

  • คอมไพเลอร์ Java จะกำหนด nullness ให้กับทุกนิพจน์
  • สามารถใช้การแปลง nullness เพื่อจัดการนิพจน์ที่มี nullness ต่างกันได้
  • การแปลง nullness แบบ narrowing อาจทำให้เกิด NullPointerException ในรันไทม์

การตรวจสอบ null ในรันไทม์

  • เมื่อเกิดการแปลง nullness แบบ narrowing จะเกิด NullPointerException

nullness ของตัวแปรประเภท

  • ตัวแปรประเภทก็สามารถแสดง nullness ได้
  • ตัวแปรประเภทแบบ null-restricted และ nullable ใช้ยืนยัน nullness เฉพาะภายในโค้ด generic

type argument และขอบเขต

  • type argument สามารถแสดง nullness ได้ และสิ่งนี้มีผลต่อ nullness ของ API
  • type argument ที่มี nullness ไม่ตรงกันอาจทำให้เกิดคำเตือน

การ override เมธอดและการอนุมาน type argument

  • nullness จะถูกละเลยเมื่อใช้ตัดสินว่าเมธอดมีซิกเนเจอร์เหมือนกันหรือไม่
  • ประเภทคืนค่าของเมธอดที่ override สามารถแปลงได้ผ่านการแปลง nullness

คำเตือนจากคอมไพเลอร์

  • การสร้างประเภท null-restricted อาจทำให้เกิดข้อผิดพลาดใหม่ในช่วงคอมไพล์
  • การแปลง nullness แบบ narrowing หรือการใช้ประเภท ? กับการดำเนินการที่ไม่เป็นมิตรกับ null อาจทำให้เกิดคำเตือน

การคอมไพล์และการแทนค่าในคลาสไฟล์

  • ตัวทำเครื่องหมาย null ส่วนใหญ่จะถูกลบออกจากคลาสไฟล์
  • แอททริบิวต์ NullRestricted ใหม่ใช้ระบุว่าฟิลด์ไม่ยอมรับค่า null

Core Reflection

  • ไม่มีลิเทอรัล Foo!.class หรือ Foo?.class
  • API ใหม่ RuntimeType ใช้อธิบายรูปแบบ null-restricted ในรันไทม์

การเปลี่ยนแปลงเพิ่มเติม

  • การซีเรียลไลซ์แบบดั้งเดิมไม่เข้ากันกับฟิลด์และอาร์เรย์แบบ null-restricted
  • javadoc จะรวมตัวทำเครื่องหมาย nullness
  • API ของ java.lang.reflect.Type และ javax.lang.model จะเข้ารหัส nullness

ทางเลือก

  • เครื่องมือพัฒนาต่าง ๆ ในระบบนิเวศของ Java ต่างก็มีการติดตาม null ในแบบของตนเอง
  • ภาษาโปรแกรมอื่น ๆ ติดตาม nullness ในระบบประเภท
  • การบังคับใช้ nullness ในรันไทม์สามารถทำได้ด้วยการตรวจสอบแบบชัดเจนหรือการเรียก Objects.requireNonNull

การพึ่งพา

  • ต้องใช้ Flexible Constructor Bodies (Second Preview)
  • รวมถึงงานในอนาคตอย่าง Null-Restricted Value Class Types (Preview) และ JEP 402: Enhanced Primitive Boxing (Preview)

สรุปของ GN⁺

  • JEP นี้มอบเครื่องมือสำหรับจัดการค่า null ใน Java ได้อย่างชัดเจน ช่วยเพิ่มเสถียรภาพและความอ่านง่ายของโค้ด
  • การเพิ่มประเภท null-restricted และ nullable ช่วยลดบั๊กที่เกิดจากการอ้างอิง null
  • เข้ากันได้กับโค้ดเดิมและนำมาใช้แบบค่อยเป็นค่อยไปได้ ทำให้นักพัฒนามีความยืดหยุ่น
  • เมื่อเทียบกับภาษาอื่น ก็ช่วยเสริมความสามารถของ Java ในการจัดการ null
  • เครื่องมือที่มีความสามารถคล้ายกันคือฟีเจอร์ null-safety ของ Kotlin

1 ความคิดเห็น

 
GN⁺ 2024-08-04
ความคิดเห็นบน Hacker News
  • การเปรียบเทียบวิธีจัดการ null ของ C# และ Kotlin

    • C# เมื่อเปิดใช้ nullability ในโปรเจกต์ ตัวแปรทั้งหมดจะถูกประกาศเป็น non-null โดยค่าเริ่มต้น
    • Kotlin ก็คล้ายกัน แต่ไม่จำเป็นต้องคำนึงถึง backwards compatibility
    • Kotlin มีความสามารถให้กำหนดค่าตัวแปร non-nullable ที่ยังไม่ถูกกำหนดค่าเริ่มต้นภายหลังได้ผ่านการประกาศ lateinit var
  • ความเห็นต่อข้อเสนอใหม่

    • ตัวแปรเดิมถูกแบ่งเป็น nullable, explicitly nullable และ explicitly non-nullable
    • แนวทางของ C# ดูดีกว่า โดยเฉพาะเพราะไม่จำเป็นต้องแก้ปัญหา nullability ในโค้ดเบสแบบ legacy
    • อย่างไรก็ตาม แนวทางของ C# จะเน้นให้เห็นปัญหา nullability ในโค้ดเบสได้ทันที
  • ความกังวลเกี่ยวกับการแปลง nullness-narrowing อัตโนมัติ

    • การแปลงอัตโนมัติให้ความรู้สึกว่าไม่ถูกต้อง
    • มีบางกรณีที่ควรทำให้เกิด compiler error
    • การแปลงแบบ explicit ปลอดภัยกว่า
  • ความจำเป็นของวิธีทำให้ตัวแปรทั้งหมดเป็น non-null โดยค่าเริ่มต้น

    • จำเป็นต้องมีวิธีกำหนดในระดับแพ็กเกจหรือไฟล์ให้ตัวแปรทั้งหมดเป็น non-null
    • ไม่เช่นนั้นจะต้องใช้ไวยากรณ์ T! กับตัวแปรเกือบทั้งหมด ทำให้โค้ดซับซ้อน
  • ความจำเป็นของฟีเจอร์ optionality แบบ explicit ในระดับภาษาใน Java

    • จากประสบการณ์กับ Kotlin และ Typescript การรองรับในระดับภาษาดีกว่า
    • เครื่องมืออย่าง NullAway ใน Java ใช้งานค่อนข้างยุ่งยาก
  • คำวิจารณ์ต่อการตัดสินใจที่ไม่ใช้การปรับปรุงภาษาเหล่านี้กับ standard library

    • จากประสบการณ์ใช้ PHP การทำงานร่วมกับ standard library ค่อนข้างยุ่งยาก
    • จำเป็นต้องเพิ่มความสามารถในการแสดงออกนี้ให้กับ standard library
  • ความจำเป็นของวิธีง่าย ๆ ในการยกระดับคำเตือนตอน compile time ให้เป็นข้อผิดพลาด

    • Java เป็นภาษาที่ใช้ static type เป็นหลัก จึงไม่เหมาะที่จะนำพฤติกรรมแบบ dynamic เข้ามา
  • ความจำเป็นที่ค่าเริ่มต้นควรเป็น non-nullable, immutable และมีขอบเขตแคบ

    • การตัดสินใจออกแบบใหม่มักละทิ้งเส้นทางที่ปลอดภัยเพื่อแลกกับความสะดวกทันที
    • ปัญหานี้ก่อให้เกิดข้อผิดพลาดจำนวนมากในหลายภาษาและเทคโนโลยี
  • ประสบการณ์การจัดการ null ในภาษา Hack

    • nullness เป็นส่วนสำคัญในระบบชนิดข้อมูลของ Hack
    • มีคำถามเกี่ยวกับอาร์เรย์แบบ nullable
    • ใน Java เป็นปัญหาเพราะโค้ด legacy ทั้งหมดตั้งสมมติฐานเรื่อง nullability อยู่แล้ว
  • คำถามว่าสามารถนำฟีเจอร์นี้ไปใช้กับ Java SDK ได้หรือไม่

    • มีข้อสงสัยว่าจะนำไปใช้กับโค้ด legacy ได้อย่างไร
  • ลิงก์ที่เกี่ยวข้อง