В Kotlin есть два оператора для сравнения:
== — структурное сравнение (equivalent to .equals()). Оно проверяет содержания: a == b вызывает a?.equals(b) ?: (b == null).=== — ссылочное сравнение. Проверяет, указывают ли обе переменные на один и тот же объект: a === b эквивалентно Java 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 в Kotlin?
Некоторые уверяют, что разницы нет, однако если a — nullable, то вызов a.equals(b) вызовет NullPointerException, а a == b безопасен и вернёт true, если оба null, или false, если только один из них null.
Пример:
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-значениями (например, из коллекций), разработчики сравнивали их через === и получали неожиданные результаты из-за того, что объектные инстансы разных чисел не обязательно интернируются как примитивы. Это приводило к некорректному поведению при работе с коллекциями объектов.