Kotlin Academy · บทเรียน

ตัวดำเนินการ !!: เมื่อใดและเหตุใดควรหลีกเลี่ยง

ทำความเข้าใจตัวดำเนินการยืนยันว่าไม่เป็น null ความเสี่ยง และทางเลือกที่ดีกว่า

บทเรียน 4 จาก 413 ขั้นตอน

ตัวดำเนินการ !!: เมื่อใดและเหตุใดควรหลีกเลี่ยง เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน

!! คืออะไร

ตัวดำเนินการ ยืนยันว่าไม่เป็นค่าว่าง !! จะแปลงชนิดที่รับค่าว่างได้ให้เป็นชนิดที่ไม่เป็นค่าว่าง หากค่าดังกล่าวเป็นค่าว่างขณะรันโปรแกรม จะโยน NullPointerException

การใช้ !! เบื้องต้น

x!! จะคืนค่า x หากไม่เป็นค่าว่าง มิฉะนั้นจะโยน NPE

fun main() {
    val name: String? = "Kotlin"
    val len: Int = name!!.length // 6
    println(len)
}

!! จะโยนข้อผิดพลาดเมื่อเป็นค่าว่าง

หากค่าดังกล่าวเป็นค่าว่างจริง คุณจะได้รับข้อผิดพลาดเดียวกับที่ Kotlin พยายามป้องกัน

fun main() {
    val name: String? = null
    try {
        println(name!!.length)
    } catch (e: NullPointerException) {
        println("NPE caught!")
    }
}

ทางเลือกที่ดีกว่า: การเรียกแบบปลอดภัย

แทนที่จะใช้ !! ควรเลือกใช้ ?. เพื่อจัดการกรณีต่าง ๆ อย่างเหมาะสมโดยไม่ทำให้โปรแกรมขัดข้อง

fun main() {
    val name: String? = null
    val len = name?.length
    println(len) // null — no crash
}

ทางเลือกที่ดีกว่า: ตัวดำเนินการ Elvis

จับคู่ ?. กับ ?: เพื่อกำหนดค่าทดแทนที่เหมาะสม

fun main() {
    val name: String? = null
    val len = name?.length ?: 0
    println(len) // 0
}

ทางเลือกที่ดีกว่า: การแปลงชนิดอัจฉริยะ

การตรวจสอบด้วย if (x != null) จะเปิดใช้การแปลงชนิดอัจฉริยะ จึงไม่จำเป็นต้องใช้ !!

fun main() {
    val name: String? = "Alice"
    if (name != null) {
        println(name.length) // smart-cast to String
    }
}

ทางเลือกที่ดีกว่า: requireNotNull

หากค่าดังกล่าวต้องมีอยู่ requireNotNull(x) { "..." } จะโยน IllegalArgumentException ที่สื่อความหมายได้ชัดเจน

fun process(name: String?) {
    val safe = requireNotNull(name) { "name is required" }
    println("processing $safe")
}
fun main() {
    process("Ada")
    // process(null) // throws IllegalArgumentException: name is required
}

ทางเลือกที่ดีกว่า: checkNotNull

checkNotNull(x) ทำงานในลักษณะเดียวกัน แต่จะโยน IllegalStateException ให้ใช้สำหรับตรวจสอบเงื่อนไขคงที่

class Service {
    private var data: String? = null
    fun load() { data = "loaded" }
    fun read(): String = checkNotNull(data) { "load() must be called first" }
}
fun main() {
    val s = Service()
    s.load()
    println(s.read())
}

กรณีที่เหมาะสมสำหรับการใช้ !!

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

fun main() {
    val list = listOf(1, 2, 3)
    val firstEven: Int = list.find { it % 2 == 0 }!! // safe: we know list has an even
    println(firstEven)
}

การใช้ !! ต่อกัน — รูปแบบที่ควรหลีกเลี่ยงอย่างยิ่ง

การใช้ !! หลายรายการต่อกันเป็นสัญญาณว่าควรปรับปรุงโค้ดใหม่ ให้ปรับโครงสร้างโดยใช้การเรียกแบบปลอดภัยและประโยคตรวจสอบเบื้องต้น

class A(val b: B?)
class B(val c: C?)
class C(val name: String?)
fun main() {
    val a: A? = A(B(C("ok")))
    // BAD: val n = a!!.b!!.c!!.name!!
    val n = a?.b?.c?.name ?: "unknown"
    println(n)
}

การปรับโครงสร้างเพื่อนำ !! ออก

แทนที่ !! ด้วยส่วนติดต่อที่ตรงไปตรงมามากกว่า เช่น ค่าที่ฟังก์ชันคืนซึ่งรับค่าว่างได้ การใช้ requireNotNull ตั้งแต่จุดเริ่มต้น หรือการคืนค่าออกจากฟังก์ชันแต่เนิ่น ๆ

fun firstUpper(s: String?): String? = s?.firstOrNull()?.uppercase()
fun main() {
    println(firstUpper("alice")) // A
    println(firstUpper(""))      // null
    println(firstUpper(null))    // null
}

ตรวจสอบความเข้าใจ

จะเกิดอะไรขึ้นหากคุณใช้ !! กับค่าที่เป็นค่าว่างจริงขณะรันโปรแกรม

สรุปทบทวน

!! เป็นช่องทางหลีกเลี่ยงข้อจำกัดที่ทำลายความปลอดภัยจากค่าว่างของ Kotlin ควรเลือกใช้ ?. ?: การแปลงชนิดอัจฉริยะ requireNotNull หรือ checkNotNull และสงวน !! ไว้สำหรับเงื่อนไขคงที่ที่มีคำอธิบายกำกับและคอมไพเลอร์ไม่สามารถพิสูจน์ได้

เริ่มต้นได้ฟรี

เรียนรู้ Kotlin ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
51
บทเรียน
203

คำถามที่พบบ่อย

บทเรียน “ตัวดำเนินการ !!: เมื่อใดและเหตุใดควรหลีกเลี่ยง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ตัวดำเนินการ !!: เมื่อใดและเหตุใดควรหลีกเลี่ยง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ตัวดำเนินการ !!: เมื่อใดและเหตุใดควรหลีกเลี่ยง”

ทำความเข้าใจตัวดำเนินการยืนยันว่าไม่เป็น null ความเสี่ยง และทางเลือกที่ดีกว่า คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “ตัวดำเนินการ !!: เมื่อใดและเหตุใดควรหลีกเลี่ยง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม

ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ชนิด Nullable และตัวปรับแต่ง ?
  2. Safe Call ?. และ Elvis ?: ในโค้ดจริง
  3. let, also และ run กับตัวรับ Nullable
  4. ตัวดำเนินการ !!: เมื่อใดและเหตุใดควรหลีกเลี่ยง
← กลับไปที่ Kotlin Academy