В чём смысл OptionalInt, если int — примитив и не может быть null?

Сразу скажу, что я видел этот вопрос. И я прекрасно понимаю, чем отличается Optional и OptionalInt. Но зачем вообще оборачивать int в опциональное значение? Optional был изобретён для борьбы с NPE. Но int — примитив и никак не может быть null. А 0 (значение по умолчанию для целочисленных типов) — вполне нормальное число...


Ответы (1 шт):

Автор решения: Зонтик

Примечание от автора: идея ответа взята из комментария, и поэтому он был сделан общим.

Дело в том, что нужно отличать 0 и отсутствие числа вообще. Что значит "отсутствие числа"? Как такое может получится?

Давайте возьмём пример. Пусть нам надо найти максимальное чётное число в массиве. Представим, что OptionalInt не существует и max() возвращает примитив:

//arrayOfInts = массив int[]
int result = Arrays.stream(arrayOfInts).filter(num -> num % 2 == 0).max();

Вроде всё хорошо? А теперь представьте, что массив arrayOfInts выглядит так:

int[] arrayOfInts = {211, 33, 19, 21, 43};

И что же будет? Ни одно число не пройдёт фильтрацию! И стрим окажется пуст. А так как значение по умолчанию для целых чисел — это 0, то вот оно и вернётся.
Но это неверно: так как такого числа у нас нет. К тому же, массив мог быть и таким:

int[] arrayOfInts = {0, 7, -8, 65};

Тогда ведь 0 — реально максимальное чётное число. И именно для отличения таких ситуаций и придуман OptionalInt. Давайте посмотрим, будет ли разница между первым и вторым случаем:

int[] firstArray = {211, 33, 19, 21, 43};
int[] secondArray = {0, 7, -8, 65};
OptionalInt firstResult = Arrays.stream(firstArray).filter(num -> num % 2 == 0).max();
OptionalInt secondResult = Arrays.stream(secondArray).filter(num -> num % 2 == 0).max();
System.out.println(firstResult.isPresent());
System.out.println(secondResult.isPresent());

Вывод:

false
true
→ Ссылка