ภาพรวม
!! เรียกว่า Not-null Assertion Operator หรือ Double-bang Operator ใช้บังคับให้ Compiler ถือว่าค่าตัวแปรนั้น ไม่เป็น null แน่นอน หากเป็น null จริงๆ จะโยน NullPointerException (NPE) ทันที
Syntax
val nullable: String? = "Hello"
val nonNull: String = nullable!! // บังคับว่าไม่ null
ตัวอย่างการทำงาน
กรณีที่ 1: ค่าไม่เป็น null → ทำงานปกติ
fun main() {
var name: String? = "Kotlin"
val length = name!!.length // ✅ OK
println("Length: $length") // 6
}
กรณีที่ 2: ค่าเป็น null → โยน NPE
fun main() {
var name: String? = null
val length = name!!.length // ❌ NullPointerException
}
Exception in thread "main" java.lang.NullPointerException
at MainKt.main(main.kt:3)
เมื่อไหร่ควร (และไม่ควร) ใช้ !!
✅ เหมาะสม
- Logic รับประกันว่าค่าไม่เป็น null แล้ว (เช่น หลัง Check)
- Interop กับ Java Library ที่ไม่มี Nullability Annotation
- Test Code ที่รู้ว่าไม่เป็น null
❌ ควรหลีกเลี่ยง
- ใช้แบบสุ่มๆ เพื่อ "ขจัด" Compiler Error
- Production Code ที่ไม่แน่ใจ 100% ว่าไม่ null
- Loop/Logic ที่ซับซ้อน - ควรใช้ Safe Call (
?.) หรือif (x != null)
ทางเลือกที่ปลอดภัยกว่า
1. Safe Call Operator (?.)
val length = name?.length // คืนค่า Int? (null ถ้า name เป็น null)
2. Elvis Operator (?:)
val length = name?.length ?: 0 // คืนค่า 0 ถ้า name เป็น null
3. Explicit Null Check
if (name != null) {
val length = name.length // Smart Cast: name เป็น String ใน Block นี้
}
4. let Scope Function
name?.let { nonNullName ->
println(nonNullName.length)
}
5. requireNotNull / checkNotNull (Contract)
val length = requireNotNull(name) { "Name must not be null" }.length
// หรือ
val nonNullName = checkNotNull(name) { "Name must not be null" }
Best Practice
- ใช้
?.และ?:เป็นหลัก - ใช้
!!เฉพาะเมื่อ แน่ใจ 100% และมี Comment อธิบายว่าทำไม - พิจารณา Refactor Logic ให้ไม่ต้องใช้ !! (เช่น Early Return, Guard Clause)
- Enable Compiler Warning:
-Werrorหรือ IDE Inspection สำหรับ!!
สรุป
!! = "ฉันรับประกันว่าค่านี้ไม่ null ถ้าเป็น null ให้ Crash ทันที" - ใช้ด้วยความระมัดระวัง!