попробуй для деления на ноль - PullRequest
14 голосов
/ 14 февраля 2010

Мой вопрос касается блоков 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");

    }
}

Ответы [ 7 ]

23 голосов
/ 14 февраля 2010

Деление на ноль действительно для чисел с плавающей запятой.

  • 1/0 дает бесконечность.
  • (- 1) / 0 дает -Infinity.
  • 0/0 дает NaN.

Эти "числа" правильно определены в IEEE 754.

Целочисленное деление на ноль, с другой стороны, выбрасывает, потому что нельзя представить бесконечность как int.

14 голосов
/ 14 февраля 2010

Я бы предложил проверить:

if (divisor != 0) {
    // calculate
}

вместо того, чтобы поймать исключение

8 голосов
/ 14 февраля 2010

Поскольку вы самопровозглашенный «новичок», я думаю, что было бы неплохо указать на некоторые более широкие проблемы с вашим кодом. (Я знаю, что это не рабочий код, но давайте просто предположим, что это так.)

  • Если ожидается исключение, обычно проще, понятнее и эффективнее, если вы обнаружите условие, которое приведет к исключению. В этом случае, если вы ожидаете, что divisor иногда будет равен нулю, лучше проверить его перед выполнением деления.

  • С другой стороны, если исключение является совершенно неожиданным (т. Е. «Ошибкой»), лучшая стратегия состоит в том, чтобы исключение распространялось на самый внешний уровень. В этот момент ваш перехват приложения должен перехватить все исключения, записать трассировку стека исключений и выручить.

  • Помимо предыдущей маркировки, ловить 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 сказал бы. Если мы разрешим распространению универсального исключения, это усложнит для блока перехвата много кадров стека, чтобы действовать должным образом. В этом случае, например, удаленный блок перехвата не может с уверенностью диагностировать причину деления на ноль. ArithmeticException может происходить из другой части приложения, а не может даже делиться на ноль! Способ решения проблемы заключается в явном генерировании более конкретного исключения.

3 голосов
/ 14 февраля 2010

Ответ лежит в собственном выводе вашей программы - он печатает «Бесконечность» для result. Это потому, что Java запрещает только целочисленное деление на ноль - деление с плавающей запятой на ноль допустимо и выдает Infinity.

См. Документацию Double и Float для констант POSITIVE_INFINITY и NEGATIVE_INFINITY.

2 голосов
/ 14 февраля 2010

Только деление на ноль с целыми числами вызовет исключение ArithmeticException. Деление на ноль с двойным или с плавающей точкой приведет к Бесконечность .

1 голос
/ 14 февраля 2010

Потому что деление двух двойных возвращает бесконечность, но не бросает. Вы можете использовать isInfinite () , чтобы проверить это. Однако подходящим решением (как уже отмечалось) является проверка знаменателя перед делением.

0 голосов
/ 14 февраля 2010

Никто не должен ожидать, что RuntimeException будет выброшено из их кода. Этих Exception можно (и нужно) легко избежать.

...