Elvis Operator: nó là gì, cú pháp và xử lý giá trị null

Tác giả: IT Sectr Đã đăng: 2026-05-27 Thời gian đọc: 8 phút

Elvis Operator là một toán tử nhị phân trả về toán hạng trái nếu nó không phải null, và toán hạng phải trong trường hợp ngược lại. Nó được viết dưới dạng ?: trong Kotlin, Groovy và một số ngôn ngữ khác. Theo Tài liệu ngôn ngữ Kotlin, 2024, toán tử này là một phần của hệ thống an toàn null của ngôn ngữ và cho phép rút ngắn cấu trúc điều kiện thành một dòng mà không mất tính dễ đọc. Không giống như biểu thức if-else đầy đủ, Elvis Operator chỉ tính toán vế phải khi vế trái là null, mang lại lợi thế về hiệu suất khi sử dụng các biểu thức mặc định tốn kém.

Các điểm chính

  • Elvis Operator — toán tử ?:, trả về toán hạng không null đầu tiên trong hai
  • Null safety — lĩnh vực ứng dụng chính của Elvis Operator trong Kotlin và các ngôn ngữ khác
  • Cú pháp cực kỳ ngắn gọn: val result = a ?: b, tương đương với if (a != null) a else b
  • Groovy sử dụng cùng cú pháp ?:, Swift sử dụng toán tử ??, Dart sử dụng ??
  • Ghi log qua Elvis Operator là một mẫu phổ biến: val name = input ?: “default”

Elvis Operator là gì

Elvis Operator là một toán tử nhị phân được đặt tên theo kiểu tóc của Elvis Presley. Ký hiệu ?: trông giống như khuôn mặt của ca sĩ nhìn nghiêng: dấu hỏi là mắt và tóc mai, dấu hai chấm là miệng. Toán tử nhận hai toán hạng: nếu toán hạng thứ nhất không phải null — nó được trả về, nếu không thì toán hạng thứ hai được trả về. Điều này cho phép thay thế một cấu trúc if-else đầy đủ bằng một biểu thức ngắn gọn duy nhất.

Nguồn gốc tên gọi

Tên “Elvis Operator” đã được thiết lập trong cộng đồng KotlinGroovy, sau đó lan sang Xtend và các ngôn ngữ JVM khác. Trong Swift và Dart, cấu trúc tương tự được gọi là nil-coalescing operator, nhưng chức năng tương đồng. Sự liên tưởng trực quan với Elvis Presley đã giúp toán tử trở thành một trong những ký hiệu dễ nhận biết nhất trong cú pháp của các ngôn ngữ lập trình hiện đại.

Vai trò trong xử lý null

Elvis Operator là một phần của hệ thống null safety ngăn chặn NullPointerException (NPE). Theo một nghiên cứu của JetBrains năm 2023, NPE chiếm 28% tất cả các ngoại lệ trong mã JVM sản xuất. Sử dụng Elvis Operator loại bỏ hoàn toàn NPE tại điểm gán, đảm bảo một giá trị mặc định. Kết hợp với toán tử gọi an toàn ?., một chuỗi đáng tin cậy được tạo ra mà không có một khối if nào.

Cú pháp Elvis Operator trong Kotlin

Trong Kotlin, Elvis Operator được viết dưới dạng ?: giữa hai biểu thức. Nếu biểu thức bên trái không phải null — kết quả bằng biểu thức bên trái, nếu không thì biểu thức bên phải được tính toán. Biểu thức bên phải được tính toán một cách lười biếng — chỉ khi toán hạng bên trái là null, điều này quan trọng cho hiệu suất khi sử dụng các tính toán tốn kém hoặc lời gọi API.

kotlin
val name: String? = getUserName()
val displayName = name ?: "Guest"

fun getLength(str: String?): Int {
    return str?.length ?: 0
}

val config: Config? = loadConfig()
val timeout = config?.timeout ?: 30
println("Timeout: $timeout")

// Elvis with throw cho tham số bắt buộc
val requiredId = nullableId ?: throw IllegalArgumentException("ID is required")

// Elvis with return cho thoát sớm
fun process(data: String?): Result {
    val safe = data ?: return Result.failure("No data")
    return processInternal(safe)
}

Kết hợp với let là một mẫu phổ biến trong Kotlin, nơi Elvis Operator cung cấp một giá trị mặc định và let thực hiện một hành động trên kết quả không null. Cách tiếp cận này thay thế toàn bộ khối if-else bằng một chuỗi gọi duy nhất mà không mất tính dễ đọc. Elvis Operator cũng có thể được sử dụng với throw để buộc dừng khi thiếu tham số bắt buộc — đây là một cách thông dụng để xác thực dữ liệu đầu vào.

Elvis với trả về sớm từ hàm

Một mẫu phổ biến trong Kotlin là Elvis + return. Nếu giá trị là null, hàm sẽ ngay lập tức trả về kết quả hoặc ném một ngoại lệ. Thành ngữ Elvis với return thường được sử dụng trong các hàm chuyển đổi dữ liệu: val processed = rawData ?: return defaultValue. Điều này nhỏ gọn hơn guard let trong Swift và không làm tăng độ lồng ghép của mã.

Elvis Operator vs if-else: So sánh

Elvis Operator ngắn hơn if-else và không yêu cầu lặp lại biến. So sánh: val x = a ?: b với val x = if (a != null) a else b. Với các biểu thức phức tạp, mức giảm mã lên tới 60%, trong khi ngữ nghĩa hoàn toàn giống nhau — trình biên dịch có thể tạo ra cùng một bytecode cho cả hai biến thể.

Tiêu chíElvis Operatorif-else
Độ dài1 dòng, 5–10 ký tự3 dòng, 15–30 ký tự
Lặp lại biểu thứcKhôngCó (a != null) ? a : b
Vế phải lười biếngCó (elvis ngắn hơn)
Tác dụng phụChỉ ở vế phảiỐ cả hai nhánh
Tính dễ đọcCao cho trường hợp đơn giảnTốt hơn cho logic phức tạp

Khi nào sử dụng Elvis Operator

Elvis Operator tối ưu cho việc gán giá trị mặc định, chuỗi các lời gọi hàm với truy cập an toàn và ghi log các giá trị bị thiếu. Các mẫu thông dụng Kotlin khuyến nghị nó như một sự thay thế cho if-else đối với các kiểm tra null đơn giản trong biểu thức. Kết hợp với ?., nó tạo ra các chuỗi nhỏ gọn mà không có biến tạm thời.

Khi nào if-else được ưu tiên hơn

if-else vẫn được ưu tiên cho nhiều điều kiện, khi cần thực hiện các tác dụng phụ, hoặc khi cả hai toán hạng là các khối mã phức tạp với nhiều thao tác. Elvis Operator không hỗ trợ các khối lồng nhau — chỉ các biểu thức đơn cho mỗi toán hạng. Nếu vế phải gọi một hàm có tác dụng phụ, tính dễ đọc của if-else sẽ cao hơn.

Elvis Operator trong các ngôn ngữ lập trình khác

Groovy sử dụng chính xác cùng cú pháp ?: như Kotlin, vì cả hai ngôn ngữ đều chạy trên JVM và chia sẻ triết lý null-safety. Toán tử này xuất hiện sớm hơn trong Groovy — nó có mặt trong ngôn ngữ từ phiên bản 1.8, phát hành năm 2011. Groovy cũng hỗ trợ phép gán Elvis: x ?= value (chỉ gán nếu x là null).

groovy
def name = getUserName()
def display = name ?: "Guest"

def map = ["key": "value"]
def result = map?.get("missing") ?: "default"
println(result)

// Phép gán Elvis trong Groovy
def config = null
config ?= "defaultConfig"
assert config == "defaultConfig"

Trong Swift, phiên bản tương đương được gọi là nil-coalescing operator và được viết dưới dạng ??. Trong Dart, cùng cú pháp ?? được sử dụng. Sự khác biệt là Swift và Dart yêu cầu các kiểu toán hạng phải khớp nhau, trong khi Kotlin cho phép các kiểu khác nhau với chuyển đổi tự động sang kiểu siêu phổ biến. Trong TypeScript, toán tử ?? (nullish coalescing) xuất hiện ở phiên bản 3.7 và chỉ hoạt động với null và undefined, không giống như || vốn lọc tất cả các giá trị falsy. Trong PHP, toán tử ?? xuất hiện ở phiên bản 7.0, trong C# — ?? từ phiên bản 6.0.

Lỗi thường gặp với Elvis Operator

Lỗi phổ biến nhất là nhầm lẫn Elvis Operator ?: với toán tử gọi an toàn ?. Trong Kotlin, ?. gọi một phương thức hoặc thuộc tính chỉ khi đối tượng không phải null, trong khi ?: trả về giá trị mặc định khi null. Chúng được kết hợp tuần tự, nhưng mỗi cái thực hiện chức năng riêng của nó. Sự nhầm lẫn xảy ra ở những người mới bắt đầu cố gắng sử dụng ?: mà không có ?. phía trước.

Tác dụng phụ trong toán hạng bên phải

Vế phải của Elvis được tính toán một cách lười biếng, nhưng nếu nó chứa một lời gọi hàm có tác dụng phụ, điều này có thể dẫn đến hành vi không mong đợi. Các nhà phát triển đôi khi đặt các tính toán tốn kém hoặc ghi log ở vế phải, việc này không được thực hiện khi giá trị không phải null. Điều quan trọng cần nhớ là vế phải là một biểu thức chỉ được tính toán khi cần thiết.

Chuỗi Elvis không có nhóm

Nhiều Elvis liên tiếp có thể làm khó đọc mã. Ví dụ, a ?: b ?: c ?: d được tính từ trái sang phải, trả về giá trị không null đầu tiên. Nhóm bằng dấu ngoặc đơn hoặc tách logic ra một hàm riêng cải thiện khả năng đọc và dễ dàng gỡ lỗi. Nếu chuỗi dài hơn 3 phần tử, nên sử dụng biểu thức when hoặc một hàm phụ trợ.

Elvis thay vì if-else với các điều kiện boolean

Những nhà phát triển mới bắt đầu đôi khi cố gắng sử dụng Elvis Operator để kiểm tra giá trị boolean: val x = flag ?: false. Điều này chỉ hoạt động nếu flag có thể là null. Đối với các điều kiện boolean không có null, cần if-else thông thường hoặc toán tử ba ngôi — Kotlin không có toán tử ba ngôi, nhưng nó được thay thế bằng biểu thức if-else: val x = if (flag) a else b.

Câu hỏi thường gặp

Elvis Operator khác gì so với toán tử ba ngôi?

Elvis Operator chỉ kiểm tra null, trong khi toán tử ba ngôi chấp nhận bất kỳ điều kiện boolean nào. Kotlin không có toán tử ba ngôi — nó được thay thế bằng biểu thức if-else. Elvis giải quyết một nhiệm vụ cụ thể: giá trị mặc định khi null, trong khi toán tử ba ngôi bao phủ tất cả các biểu thức điều kiện.

Có thể sử dụng Elvis Operator với hàm không?

Có, vế phải có thể là một lời gọi hàm: val x = a ?: calculateDefault(). Hàm chỉ được tính toán khi a là null nhờ vào tính toán lười biếng. Điều này cho phép sử dụng các tính toán tốn kém, lời gọi API hoặc truy vấn cơ sở dữ liệu mà không mất hiệu suất khi có giá trị.

Elvis Operator có tồn tại trong Java không?

Java không có Elvis Operator trực tiếp. Từ Java 8, có thể sử dụng Optional.ofNullable(value).orElse(default). Java 14+ đã giới thiệu biểu thức switch, nhưng ?: hoàn chỉnh không có. Kotlin và Groovy cung cấp nó như một cấu trúc cú pháp tích hợp của ngôn ngữ.

Elvis Operator hoạt động như thế nào với chuỗi gọi?

Mẫu điển hình là gọi an toàn ?. theo sau là Elvis. Ví dụ: user?.address?.city ?: “Unknown”. Nếu bất kỳ phần tử nào trong chuỗi là null — giá trị mặc định được trả về. Đây là một sự thay thế nhỏ gọn cho các kiểm tra if lồng nhau, giảm mã đi 3–5 lần so với cách tiếp cận truyền thống.

Sự khác biệt giữa Elvis Operator và orElse trong Optional là gì?

Elvis Operator là một cấu trúc cú pháp ở cấp độ ngôn ngữ, trong khi orElse là một phương thức của Optional trong Java. Elvis lười biếng (vế phải chỉ được tính khi null), trong khi orElse luôn tính toán đối số của nó. Đối với biến thể lười biếng trong Java, có orElseGet chấp nhận một Supplier. Elvis ngắn hơn và không yêu cầu tạo Optional.

Tổng kết

  • Elvis Operator — toán tử ?: để cung cấp giá trị mặc định khi toán hạng là null
  • Cú pháp trong Kotlin và Groovy: val result = a ?: b, trong đó b chỉ được tính khi a == null
  • Null safety — lĩnh vực ứng dụng chính, ngăn chặn NullPointerException
  • Nil-coalescing — phiên bản tương đương trong Swift (??) và Dart (??) với ngữ nghĩa tương tự, trong TypeScript — ?? từ phiên bản 3.7
  • Kết hợp với gọi an toàn ?. tạo ra chuỗi xử lý null nhỏ gọn không lồng ghép
  • Tính toán lười biếng của toán hạng phải — một sự khác biệt chính so với toán tử ba ngôi
  • Thực hành tốt nhất — sử dụng cho các kiểm tra null đơn giản, tránh trong các khối phức tạp có tác dụng phụ

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm