코틀린에는 두 가지 비교 연산자가 있습니다:
== — 구조적 비교 (자바의 .equals()와 동일). 내용물을 확인합니다: a == b는 a?.equals(b) ?: (b == null)을 호출합니다.=== — 참조 비교. 두 변수가 동일한 객체를 가리키는지 확인합니다: a === b는 자바의 객체에 대해 a == b와 같습니다.기본 타입의 경우 (예: Int): ==와 ===는 자동 박싱 덕분에 동일하게 동작할 수 있지만, 일반적으로는 ==를 사용하는 것이 좋습니다.
val a = "Kotlin" val b = "Kotlin" val c = a println(a == b) // true (내용 비교) println(a === b) // false (다른 참조 — 문자열은 컴파일러에 따라 내장됨) println(a === c) // true (동일한 객체)
코틀린에서 a.equals(b)와 a == b의 차이는 무엇인가요?
일부는 차이가 없다고 주장하지만, 만약 a가 nullable이라면 a.equals(b)를 호출하면 NullPointerException이 발생하고, a == b는 안전하게 두 값이 모두 null일 때 true를 반환하거나, 단지 하나만 null일 때 false를 반환합니다.
예시:
val a: String? = null val b: String? = null println(a == b) // true println(a?.equals(b)) // null (true가 아니지만 에러는 아님) println(a.equals(b)) // NullPointerException
사례
대규모 프로젝트에서 nullable 문자열을 a.equals(b)로 비교했지만, a == null일 경우 애플리케이션이 다운되는 것을 모르고 있었습니다. 이 버그는 매우 드물게 발생했지만, 프로덕션에서 치명적인 충돌을 일으켰고 — 이를 a == b로 변경하여 수정했습니다.
사례
객체를 ===를 사용해 비교할 때 내용 비교가 이루어질 것이라고 기대했지만, ===는 객체의 동일성을 검사합니다 — 동일한 내용을 가진 두 개의 서로 다른 문자열이 ===로 비교하면 같지 않다는 결과가 나와 데이터 캐싱 로직을 깨뜨리는 문제가 발생했습니다.
사례
boxed Int 값을 (예: 컬렉션에서) 작업하면서 개발자들은 ===로 비교하여 예기치 않은 결과를 얻었습니다. 이는 서로 다른 숫자의 객체 인스턴스가 반드시 기본적으로 내장되지 않기 때문입니다. 이는 객체 컬렉션 작업 시 올바르지 않은 동작으로 이어졌습니다.