Try-catch для деления на ноль
Я новичок в java, мой вопрос касается блоков try-catch на простом делении на нулевом примере. Вы видите первую попытку? Если я перенесу любую из этих двух переменных в двойную, программа не распознает блок catch. На мой взгляд, должен ли я запускать или не только блокирующий блок. Что не так в этом коде? Спасибо.
public static void main(String[] args) {
int pay=8,payda=0;
try {
double result=pay/(double)payda; // if I cast any of the two variables, program does not recognize the catch block, why is it so?
System.out.println(result);
System.out.println("inside-try");
} catch (Exception e) {
System.out.println("division by zero exception");
System.out.println("inside-catch");
}
}
Ответы
Ответ 1
Деление на ноль допустимо для чисел с плавающей запятой.
- 1/0 дает бесконечность.
- (- 1)/0 дает -Infinity.
- 0/0 дает NaN.
Эти "цифры" правильно определены в IEEE 754.
Целочисленное деление на ноль, с другой стороны, бросает, потому что невозможно представить бесконечность как int
.
Ответ 2
Я предлагаю проверить:
if (divisor != 0) {
// calculate
}
вместо того, чтобы перехватывать исключение
Ответ 3
Поскольку вы являетесь самопровозглашенным "новичком", я думаю, было бы неплохо указать на некоторые более общие проблемы с вашим кодом. (Я знаю, что это не производственный код, а просто допустим ради аргумента, что он был.)
-
Если ожидается исключение, оно обычно проще, яснее и эффективнее, если вы обнаружите условие, которое приведет к возникновению исключения. В этом случае, если вы ожидаете, что divisor
будет иногда нулевым, лучше проверить его перед делением.
-
С другой стороны, если исключение совершенно неожиданно (т.е. "ошибка" ), лучшая стратегия заключается в том, чтобы исключение распространялось на самый внешний уровень. В этот момент ваш захват приложения должен ловить все исключения, регистрировать исключение stacktrace и выходить из системы.
-
Помимо предыдущей пули, неплохо поймать Exception
, RuntimeException
, Throwable
или Error
. Это приведет к большому количеству исключений, которые вы, вероятно, не собираетесь ловить. В этом случае, поскольку вы ожидаете ArithmeticException
, вы должны поймать только это.
-
Редко правильно использовать float
или double
в финансовых приложениях. Эти типы не являются точными, но для финансовых приложений обычно требуется точное количество денег.
-
В более общем плане числа с плавающей запятой изначально трудно усложнять людям (и новичкам). Многие "истины", которые люди ожидают провести, на самом деле не выдерживают. Например, вычисление с плавающей запятой 1.0/3.0 + 1.0/3.0 + 1.0/3.0
не дает 1.0
. Аналогично (как вы обнаружили) деление на ноль ведет себя по-разному. Если вы хотите безопасно использовать плавающие точки, вам необходимо понять подводные камни.
РЕДАКТИРОВАТЬ, в котором будет высвечиваться первая точка в ответ на комментарий @Jay.
Во-первых, я сознательно использовал слово "обычно". Бывают случаи, когда избегать выброса ожидаемого исключения ничего не достигает.
Сказав это, вы часто не хотите, чтобы генерическое "ожидаемое" исключение происходило даже в том случае, если ваше приложение не может сразу разобраться с ситуацией. Например, если код OP был частью чего-то большего, может быть лучше явно бросить IllegalArgumentException
(если это нарушение контракта API) или некоторые отмеченные UserEnteredRubbishException
, если мы знаем, что это результат плохого пользовательский ввод (и есть некоторая возможность сообщить/исправить его).
Тот факт, что мы "ожидаем" исключение, по определению означает, что мы знаем об этом больше, чем (скажем) общий ArithmeticException
. Если мы разрешаем распространение общего исключения, это затрудняет работу блока catch с множеством стековых фреймов. В этом случае, например, удаленный блок блокировки не мог диагностировать причину деления на ноль с какой-либо определенностью. ArithmeticException
может быть получен из другой части приложения и может даже не быть делением на нуль! Способ обращения заключается в явном бросании более конкретного исключения.
Ответ 4
Ответ лежит на вашей собственной программе - он печатает "Бесконечность" для result
. Это связано с тем, что Java только запрещает целочисленное деление на ноль - деление с плавающей запятой на ноль является законным и создает Infinity
.
Смотрите документацию Double и Float для констант POSITIVE_INFINITY
и NEGATIVE_INFINITY
.
Ответ 5
Только деление на ноль с целыми значениями приведет к возникновению исключения ArithmeticException.
Деление на ноль с двойным или плавающим результатом приведет к Бесконечность.
Ответ 6
Потому что деление двух удвоений возвращает бесконечность, но не бросает. Вы можете использовать isInfinite(), чтобы проверить это. Однако подходящее решение (как уже отмечалось) - проверить знаменатель перед делением.
Ответ 7
Никто не должен ожидать, что RuntimeException
будет выброшен из их кода. Эти Exception
могут (и должны быть) легко устранены.