Я пишу программу, которая должна обрабатывать объекты со многими обернутыми числовыми переменными, такими как Long, Double, Integer и т.д. Как я могу безопасно выполнять числовые операции над ними без необходимости отправлять нулевые проверки везде?
Я ожидаю, что это то, о чем почти каждый программист Java должен иметь дело рано или поздно, поэтому я совершенно удивлен тем, что на эту тему не сотни сообщений в блогах и SO вопросов.
Мое текущее решение состоит в том, чтобы отфильтровать все числа с помощью такого метода:
private static safelyUnbox(Integer i) {
return i == null ? 0 : i.intValue();
}
...
sumVariable += safelyUnbox(stupidObject.getNumberOfWhatever());
Java 8 обеспечивает хорошую альтернативу проверке на null
. Если Integer (например) может иметь или не иметь значения, вы можете объявить его как Optional<Integer>
. Optional
класс имеет множество полезных утилит для возврата значений по умолчанию, исключения исключений, проверки наличия и т.д.
Преимущество объявления Optional<Integer>
заключается в том, что вы полностью поняли читателю, что "нет значения" является законным состоянием. Любой, кто поддерживает ваш код, не имеет другого выбора, кроме как использовать Optional
методы, чтобы решить, что произойдет, если значение присутствует или отсутствует.
Если, с другой стороны, аргумент является обязательным, самым простым вариантом является просто утверждение, что оно не является нулевым до его использования.
Огромное преимущество (на мой взгляд) использования Optional
когда значение может отсутствовать, заключается в том, что вы можете начать полагаться на свой код, исходя из предположения, что значение null
всегда является ошибкой.
Optional
даже обеспечивает опрятный способ преобразования потенциально нулевой переменной в Optional
(например, если он передан вам, и вы не контролируете его значение при вводе кода). Он работает следующим образом:
Optional<Integer> optVal = Optional.ofNullable(val);
Затем вы можете использовать новую переменную так же, как и любую другую Optional
. Например:
optVal.ifPresent(myList::add);
Или:
return optVal.orElse(27);
У вас очень специфическая проблема, и вы пытаетесь обобщить ее, не задумываясь об этом.
Это может быть предварительным условием, что нулевые значения недействительны. В вашем случае вы указываете в своих комментариях, что это не так. Но если это так, вы должны справиться с этим, вместо того, чтобы его избегать.
"Безопасное" значение может отличаться. Вы выбрали 0
потому что вы суммируете числа, что, если вы умножаете (или используете его как фактор)? Это знание, которое ваш метод safelyUnbox
не имеет.
Избегайте обобщения всего. Для вашего случая лучший код так же просто, как:
for(Integer integ : myCollection) {
if (integ != null) {
sum += integ;
}
}
Каждая другая ситуация будет иметь свое, наиболее подходящее решение. Сравните это с
for(Integer integ : myCollection) {
sum += safeUnboxThatDefaultsto0(integ);
}
или
for(Integer integ : myCollection) {
sum += safeUnbox(integ, 0);
}
Что вы выигрываете с помощью метода?
Вы можете использовать Google Guava Library, используя и избегая нулевого
Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5
Самое большое преимущество Optional
- не readability
: преимущество - его идиот-доказательство. Это заставляет вас активно думать о отсутствующем случае, если вы хотите, чтобы ваша программа вообще компилировалась, так как вы должны активно разворачивать опцию и обращаться к этому случаю. Null делает это довольно легко, просто забыть о вещах.
Предположим, что этот случай:
String meterReading=getValueFromRemoteSite();
System.out.println(meterReading.toLowerCase()); //Chances for NPE
но использование необязательного сценария отличается
Optional meterReading = Optional.of(getValueFromRemoteSite(););
if( meterReading.isPresent() )
{
System.out.println( meterReading.get() );
}
Optional
сравнению с Java 8, кроме отсутствующего метода Set<T> asSet()
?
0
чем бросить NPE? Если предполагается, что в коллекции нет нулевых значений, такая хитрость будет скрывать ваши настоящие ошибки. Получить ошибку NPE намного лучше, чем дать пользователю ответ, который только кажется правильным.