Можно ли сравнивать два объекта Long через оператор ==
Что проверяют
Различаете ли вы ссылку и значение, помните ли про автоупаковку и знаете ли, что кэш оберток превращает неверный код в код, который проходит тесты. Вопрос короткий, но по ответу видно, писали ли вы что-то сложнее учебных примеров.
Как отвечать
Сразу: нельзя. Long это объект, и == для ссылочных типов сравнивает ссылки, а не содержимое. Результат будет true, только если это один и тот же объект в памяти.
Коварство в автоупаковке: Long x = 100L компилируется в вызов Long.valueOf(100L), а valueOf держит кэш значений от -128 до 127 и возвращает для них один и тот же экземпляр.
Long a = 100L, b = 100L; // оба из кэша
Long c = 200L, d = 200L; // два разных объекта
System.out.println(a == b); // true
System.out.println(c == d); // false
System.out.println(c.equals(d)); // trueПравильные варианты: a.equals(b), Objects.equals(a, b) если возможен null, или a.longValue() == b.longValue(). Отдельный случай: когда один операнд примитивный long, второй распаковывается и сравнение честно идёт по значению, поэтому c == 200L вернёт true.
Где спотыкаются
Проверяют гипотезу на маленьких числах, видят true и делают вывод, что оператор работает. Код доживает до первого значения больше 127, а на тестовых данных с идентификаторами 1 и 2 всё зелёное.
Считают, что equals спасает всегда. Long.equals требует именно Long: сравнение с Integer того же числа вернёт false без единого предупреждения. Та же ловушка в list.remove(1), где вместо значения вызовется перегрузка по индексу.
Забывают про null. Распаковка null даёт NullPointerException, поэтому проверка id == 0L для Long id, пришедшего из мапы или из базы, падает ровно там, где значения не оказалось. Для обёрток, способных быть пустыми, безопаснее Objects.equals.