Как безопасно обрабатывать обернутые примитивы Java

1

Я пишу программу, которая должна обрабатывать объекты со многими обернутыми числовыми переменными, такими как Long, Double, Integer и т.д. Как я могу безопасно выполнять числовые операции над ними без необходимости отправлять нулевые проверки везде?

Я ожидаю, что это то, о чем почти каждый программист Java должен иметь дело рано или поздно, поэтому я совершенно удивлен тем, что на эту тему не сотни сообщений в блогах и SO вопросов.

Мое текущее решение состоит в том, чтобы отфильтровать все числа с помощью такого метода:

private static safelyUnbox(Integer i) {
    return i == null ? 0 : i.intValue();
}
...
sumVariable += safelyUnbox(stupidObject.getNumberOfWhatever());
  • 1
    Зачем вам нужны нулевые проверки?
  • 5
    Кроме того, почему безопаснее вернуть 0 чем бросить NPE? Если предполагается, что в коллекции нет нулевых значений, такая хитрость будет скрывать ваши настоящие ошибки. Получить ошибку NPE намного лучше, чем дать пользователю ответ, который только кажется правильным.
Показать ещё 8 комментариев
Теги:
nullpointerexception
autoboxing
primitive

3 ответа

5
Лучший ответ

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
    Это то, что я, вероятно, использовал бы, если бы мог, но я не могу изменить объект, который содержит переменные, допускающие значение NULL, и я не могу использовать Java 8. Тем не менее, хороший ответ.
  • 0
    Хорошо, я добавлю комментарий о том, как вы все еще можете использовать Необязательно.
Показать ещё 3 комментария
2

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

  • Это может быть предварительным условием, что нулевые значения недействительны. В вашем случае вы указываете в своих комментариях, что это не так. Но если это так, вы должны справиться с этим, вместо того, чтобы его избегать.

  • "Безопасное" значение может отличаться. Вы выбрали 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);
}

Что вы выигрываете с помощью метода?

  • 1
    Примечание: Решения, основанные на исчислении делегатов / лямбда (например, спринтера), также хороши, потому что они дают более семантический способ сделать то же самое.
  • 0
    Чего я хочу избежать, так это везде писать нулевые проверки - они немного раздувают код. Я ожидал, что кто-то ответит что-то вроде «эй, для этого есть метод Apache Commons» :-)
1

Вы можете использовать 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() );
}  
  • 0
    В чем преимущество Guava's Optional сравнению с Java 8, кроме отсутствующего метода Set<T> asSet() ?
  • 2
    @glglgl Java 8's Optional вдохновлен Guava's Optional. Если вы не можете использовать Java 8, лучше использовать Guava's Optional.
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню