W Kotlinie istnieją dwa operatory do porównywania:
== — porównanie strukturalne (odpowiada .equals()). Sprawdza zawartość: a == b wywołuje a?.equals(b) ?: (b == null).=== — porównanie referencyjne. Sprawdza, czy obie zmienne wskazują na ten sam obiekt: a === b jest równoważne Java a == b dla obiektów.Dla typów prymitywnych (np. Int): == i === mogą się zachowywać identycznie z powodu autoboxingu, ale w ogólnym przypadku należy używać ==.
val a = "Kotlin" val b = "Kotlin" val c = a println(a == b) // true (porównanie zawartości) println(a === b) // false (różne referencje — łańcuchy są internowane, w zależności od kompilatora) println(a === c) // true (to sam obiekt)
Jaka jest różnica między a.equals(b) a a == b w Kotlinie?
Niektórzy twierdzą, że nie ma różnicy, jednak jeśli a jest nullable, to wywołanie a.equals(b) spowoduje NullPointerException, podczas gdy a == b jest bezpieczne i zwróci true, jeśli oba są null, lub false, jeśli tylko jeden z nich jest null.
Przykład:
val a: String? = null val b: String? = null println(a == b) // true println(a?.equals(b)) // null (a nie true, ale nie ma awarii) println(a.equals(b)) // NullPointerException
Historia
W dużym projekcie aktywnie porównywano nullable łańcuchy za pomocą a.equals(b), nie zdając sobie sprawy, że przy a == null aplikacja się zawiesza. Błąd powtarzał się dosyć rzadko, ale prowadził do fatalnych awarii w produkcji — naprawiono go zastępując a == b.
Historia
Podczas porównywania obiektów przez === oczekiwano porównania zawartości, ale === sprawdza identyczność obiektów — okazało się, że dwa różne łańcuchy z identyczną zawartością nie są sobie równe przez ===, co złamało logikę cachowania danych.
Historia
Pracując z wartościami Int-typami w opakowaniach (np. z kolekcji), deweloperzy porównywali je przez === i otrzymywali nieoczekiwane wyniki, ponieważ instancje obiektów różnych liczb niekoniecznie były internowane jak prymitywy. Prowadziło to do nieprawidłowego zachowania podczas pracy z kolekcjami obiektów.