В чем разница между null в SQL и null в Java
Что проверяют
Понимаете ли вы, что под одним словом скрыты два разных понятия: в Java null значит «ссылка никуда не указывает», а в SQL NULL значит «значение неизвестно», и логика с ним трёхзначная. Следом часто просят объяснить, почему WHERE col <> 5 не вернул строки с NULL, или как пустое значение из JDBC доезжает до поля сущности.
Как отвечать
- Java:
nullэто значение ссылочного типа, примитиву его не присвоить.null == nullдаётtrue, вызов метода на пустой ссылке даётNullPointerException. С Java 15 по умолчанию включены подробные сообщения NPE, они называют, какая именно ссылка оказалась пустой; - SQL: сравнение с
NULLчерез=или<>даёт неTRUEи неFALSE, аUNKNOWN, иWHEREтакую строку отбрасывает. Проверяют черезIS NULLиIS NOT NULL, в PostgreSQL есть ещёIS DISTINCT FROM; - агрегаты:
COUNT(*)считает все строки, аCOUNT(col),SUM,AVGпропускаютNULL.SUMпо однимNULLвернётNULL, а не ноль, поэтому пишутCOALESCE(SUM(x), 0); - ловушка
NOT IN: если подзапрос вернул хотя бы одинNULL, условие не пропустит ни одной строки. БезопаснееNOT EXISTS.
Затем покажите стык двух миров. ResultSet.getInt() для NULL вернёт 0, отличить пустое значение можно только через wasNull(). Поэтому в JPA-сущностях для nullable-колонок берут Integer, а не int, иначе пустота из базы молча превратится в ноль. Для результата «значения может не быть» в Java принят Optional, но в полях и параметрах его обычно не держат.
Где спотыкаются
Говорят, что NULL = NULL в SQL даёт FALSE. Результат UNKNOWN, и разница важна: NOT (UNKNOWN) тоже UNKNOWN, поэтому отрицание условия строку с NULL не вернёт.
Объясняют null в Java как «переменная не инициализирована». Неинициализированную локальную переменную компилятор просто не даст прочитать, а null это конкретное значение, которое присвоили явно или которое поле объекта получило по умолчанию.
Забывают про автораспаковку: Integer count = null; int x = count; падает с NPE, хотя в строке нет ни одного вызова метода.