Меню

Java ошибка при делении на 0

I have code to calculate the percentage difference between 2 numbers — (oldNum - newNum) / oldNum * 100; — where both of the numbers are doubles. I expected to have to add some sort of checking / exception handling in case oldNum is 0. However, when I did a test run with values of 0.0 for both oldNum and newNum, execution continued as if nothing had happened and no error was thrown. Running this code with ints would definitely cause an arithmetic division-by-zero exception. Why does Java ignore it when it comes to doubles?

Aziz Shaikh's user avatar

Aziz Shaikh

16.1k11 gold badges61 silver badges79 bronze badges

asked Mar 4, 2010 at 17:57

froadie's user avatar

3

Java’s float and double types, like pretty much any other language out there (and pretty much any hardware FP unit), implement the IEEE 754 standard for floating point math, which mandates division by zero to return a special «infinity» value. Throwing an exception would actually violate that standard.

Integer arithmetic (implemented as two’s complement representation by Java and most other languages and hardware) is different and has no special infinity or NaN values, thus throwing exceptions is a useful behaviour there.

answered Mar 4, 2010 at 18:16

Michael Borgwardt's user avatar

Michael BorgwardtMichael Borgwardt

340k77 gold badges477 silver badges713 bronze badges

2

The result of division by zero is, mathematically speaking, undefined, which can be expressed with a float/double (as NaN — not a number), it isn’t, however, wrong in any fundamental sense.

As an integer must hold a specific numerical value, an error must be thrown on division by zero when dealing with them.

RubioRic's user avatar

RubioRic

2,4374 gold badges28 silver badges35 bronze badges

answered Mar 4, 2010 at 17:58

Kris's user avatar

KrisKris

14.3k7 gold badges54 silver badges65 bronze badges

13

When divided by zero ( 0 or 0.00 )

  1. If you divide double by 0, JVM will show Infinity.

    public static void main(String [] args){ double a=10.00; System.out.println(a/0); }

    Console:
    Infinity

  2. If you divide int by 0, then JVM will throw Arithmetic Exception.

    public static void main(String [] args){
    int a=10;
    System.out.println(a/0);
    }

    Console: Exception in thread "main" java.lang.ArithmeticException: / by zero

  3. But if we divide int by 0.0, then JVM will show Infinity:

    public static void main(String [] args){
    int a=10;
    System.out.println(a/0.0);
    }

    Console: Infinity

This is because JVM will automatically type cast int to double, so we get infinity instead of ArithmeticException.

answered Oct 1, 2017 at 10:59

Raman Gupta's user avatar

Raman GuptaRaman Gupta

1,53015 silver badges12 bronze badges

The way a double is stored is quite different to an int. See http://firstclassthoughts.co.uk/java/traps/java_double_traps.html for a more detailed explanation on how Java handles double calculations. You should also read up on Floating Point numbers, in particular the concept of Not a Number (NaN).

If you’re interested in learning more about floating point representation, I’d advise reading this document (Word format, sorry). It delves into the binary representation of numbers, which may be helpful to your understanding.

answered Mar 4, 2010 at 18:05

Mike's user avatar

MikeMike

2,3971 gold badge23 silver badges32 bronze badges

0

Though Java developers know about the double primitive type and Double class, while doing floating point arithmetic they don’t pay enough attention to Double.INFINITY, NaN, -0.0 and other rules that govern the arithmetic calculations involving them.

The simple answer to this question is that it will not throw ArithmeticException and return Double.INFINITY. Also, note that the comparison x == Double.NaN always evaluates to false, even if x itself is a NaN.

To test if x is a NaN, one should use the method call Double.isNaN(x) to check if given number is NaN or not. This is very close to NULL in SQL.

It may helpful for you.

answered Feb 2, 2016 at 10:18

ziyapathan's user avatar

Исключения

Exception

try
Оператор throw
Оператор throws
Оператор finally
Встроенные исключения Java
Создание собственных классов исключений

Исключение — это нештатная ситуация, ошибка во время выполнения программы. Самый простой пример — деление на ноль. Можно вручную отслеживать возникновение подобных ошибок, а можно воспользоваться специальным механизмом исключений, который упрощает создание больших надёжных программ, уменьшает объём необходимого кода и повышает уверенность в том, что в приложении не будет необработанной ошибки.

В методе, в котором происходит ошибка, создаётся и передаётся специальный объект. Метод может либо обработать исключение самостоятельно, либо пропустить его. В любом случае исключение ловится и обрабатывается. Исключение может появиться благодаря самой системе, либо вы сами можете создать его вручную. Системные исключения возникают при неправильном использовании языка Java или запрещённых приёмов доступа к системе. Ваши собственные исключения обрабатывают специфические ошибки вашей программы.

Вернёмся к примеру с делением. Деление на нуль может предотвратить проверкой соответствующего условия. Но что делать, если знаменатель оказался нулём? Возможно, в контексте вашей задачи известно, как следует поступить в такой ситуации. Но, если нулевой знаменатель возник неожиданно, деление в принципе невозможно, и тогда необходимо возбудить исключение, а не продолжать исполнение программы.

Существует пять ключевых слов, используемых в исключениях: try, catch, throw, throws, finally. Порядок обработки исключений следующий.

Операторы программы, которые вы хотите отслеживать, помещаются в блок try. Если исключение произошло, то оно создаётся и передаётся дальше. Ваш код может перехватить исключение при помощи блока catch и обработать его. Системные исключения автоматически передаются самой системой. Чтобы передать исключение вручную, используется throw. Любое исключение, созданное и передаваемое внутри метода, должно быть указано в его интерфейсе ключевым словом throws. Любой код, который следует выполнить обязательно после завершения блока try, помещается в блок finally

Схематически код выглядит так:


try {
    // блок кода, где отслеживаются ошибки
}
catch (тип_исключения_1 exceptionObject) {
    // обрабатываем ошибку
}
catch (тип_исключения_2 exceptionObject) {
    // обрабатываем ошибку
}
finally {
    // код, который нужно выполнить после завершения блока try
}

Существует специальный класс для исключений Trowable. В него входят два класса Exception и Error.

Класс Exception используется для обработки исключений вашей программой. Вы можете наследоваться от него для создания собственных типов исключений. Для распространённых ошибок уже существует класс RuntimeException, который может обрабатывать деление на ноль или определять ошибочную индексацию массива.

Класс Error служит для обработки ошибок в самом языке Java и на практике вам не придётся иметь с ним дело.

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


int catNumber;
int zero;
catNumber = 1; // у меня один кот
zero = 0; // ноль, он и в Африке ноль
int result = catNumber / zero;

Я поместил код в обработчик щелчка кнопки. Когда система времени выполнения Java обнаруживает попытку деления на ноль, она создаёт объект исключения и передаёт его. Да вот незадача, никто не перехватывает его, хотя это должны были сделать вы. Видя вашу бездеятельность, объект перехватывает стандартный системный обработчик Java, который отличается вредных характером. Он останавливает вашу программу и выводит сообщение об ошибке, которое можно увидеть в журнале LogCat:

Caused by: java.lang.ArithmeticException: divide by zero at ru.alexanderklimov.test.MainActivity.onClick(MainActivity.java:79)

Как видно, созданный объект исключения принадлежит к классу ArithmeticException, далее системный обработчик любезно вывел краткое описание ошибки и место возникновения.

Вряд ли пользователи вашей программы будут довольны, если вы так и оставите обработку ошибки системе. Если программа будет завершаться с такой ошибкой, то скорее всего вашу программу просто удалят. Посмотрим, как мы можем исправить ситуацию.

Поместим проблемный код в блок try, а в блоке catch обработаем исключение.


int catNumber;
int zero;

try { // мониторим код
    catNumber = 1; // у меня один кот
    zero = 0; // ноль, он и в Африке ноль
    int result = catNumber / zero;
    Toast.makeText(this, "Не увидите это сообщение!", Toast.LENGTH_LONG).show();
} catch (ArithmeticException e) {
    Toast.makeText(this, "Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}
Toast.makeText(this, "Жизнь продолжается", Toast.LENGTH_LONG).show();

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

В данном случае мы уже знали, к какому классу принадлежит получаемая ошибка, поэтому в блоке catch сразу указали конкретный тип. Обратите внимание, что последний оператор в блоке try не срабатывает, так как ошибка происходит раньше строчкой выше. Далее выполнение передаётся в блок catch, далее выполняются следующие операторы в обычном порядке.

Операторы try и catch работают совместно в паре. Хотя возможны ситуации, когда catch может обрабатывать несколько вложенных операторов try.

Если вы хотите увидеть описание ошибки, то параметр e и поможет увидеть ёго.


catch (ArithmeticException e) {
	Toast.makeText(this, e + ": Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}

По умолчанию, класс Trowable, к которому относится ArithmeticException возвращает строку, содержащую описание исключения. Но вы можете и явно указать метод e.toString.

Несколько исключений

Фрагмент кода может содержать несколько проблемных мест. Например, кроме деления на ноль, возможна ошибка индексации массива. В таком случае вам нужно создать два или более операторов catch для каждого типа исключения. Причём они проверяются по порядку. Если исключение будет обнаружено у первого блока обработки, то он будет выполнен, а остальные проверки пропускаются и выполнение программы продолжается с места, который следует за блоком try/catch.


int catNumber;
int zero;

try { // мониторим код
    catNumber = 1; // у меня один кот
    zero = 1; // ноль, он и в Африке ноль
    int result = catNumber / zero;
    // Создадим массив из трёх котов
    String[] catNames = {"Васька", "Барсик", "Мурзик"};
    catNames[3] = "Рыжик";
    Toast.makeText(this, "Не увидите это сообщение!", Toast.LENGTH_LONG).show();
} catch (ArithmeticException e) {
    Toast.makeText(this, e.toString() + ": Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}
catch (ArrayIndexOutOfBoundsException e) {
	Toast.makeText(this, "Ошибка: " + e.toString(), Toast.LENGTH_LONG).show();
}
Toast.makeText(this, "Жизнь продолжается", Toast.LENGTH_LONG).show();

В примере мы добавили массив с тремя элементами, но обращаемся к четвёртому элементу, так как забыли, что отсчёт у массива начинается с нуля. Если оставить значение переменной zero равным нулю, то сработает обработка первого исключения деления на ноль, и мы даже не узнаем о существовании второй ошибки. Но допустим, что в результате каких-то вычислений значение переменной стало равно единице. Тогда наше исключение ArithmeticException не сработает. Но сработает новое добавленное исключение ArrayIndexOutOfBoundsException. А дальше всё пойдёт как раньше.

Тут всегда нужно помнить одну особенность. При использовании множественных операторов catch обработчики подклассов исключений должные находиться выше, чем обработчики их суперклассов. Иначе, суперкласс будет перехватывать все исключения, имея большую область перехвата. Иными словами, Exception не должен находиться выше ArithmeticException и ArrayIndexOutOfBoundsException. К счастью, среда разработки сама замечает непорядок и предупреждает вас, что такой порядок не годится. Увидев такую ошибку, попробуйте перенести блок обработки исключений ниже.

Вложенные операторы try

Операторы try могут быть вложенными. Если вложенный оператор try не имеет своего обработчика catch для определения исключения, то идёт поиск обработчика catch у внешнего блока try и т.д. Если подходящий catch не будет найден, то исключение обработает сама система (что никуда не годится).

Оператор throw

Часть исключений может обрабатывать сама система. Но можно создать собственные исключения при помощи оператора throw. Код выглядит так:


throw экземпляр_Throwable

Вам нужно создать экземпляр класса Throwable или его наследников. Получить объект класса Throwable можно в операторе catch или стандартным способом через оператор new.

Мы могли бы написать такой код для кнопки:


Cat cat;

public void onClick(View view) {
    if(cat == null){
        throw new NullPointerException("Котик не инициализирован");
    }
}

Мы объявили объект класса Cat, но забыли его проинициализировать, например, в onCreate(). Теперь нажатие кнопки вызовет исключение, которое обработает система, а в логах мы можем прочитать сообщение об ошибке. Возможно, вы захотите использовать другое исключение, например, throw new UnsupportedOperationException(«Котик не инициализирован»);.

В любом случае мы передали обработку ошибки системе. В реальном приложении вам нужно обработать ошибку самостоятельно.

Поток выполнения останавливается непосредственно после оператора throw и другие операторы не выполняются. При этом ищется ближайший блок try/catch соответствующего исключению типа.

Перепишем пример с обработкой ошибки.


public void onClick(View view) {
    if (cat == null) {
        try {
            throw new NullPointerException("Кота не существует");
        } catch (NullPointerException e) {
            Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
        }
    }
}

Мы создали новый объект класса NullPointerException. Многие классы исключений кроме стандартного конструктора по умолчанию с пустыми скобками имеют второй конструктор с строковым параметром, в котором можно разместить подходящую информацию об исключении. Получить текст из него можно через метод getMessage(), что мы и сделали в блоке catch.

Теперь программа не закроется аварийно, а будет просто выводить сообщения в всплывающих Toast.

Оператор throws

Если метод может породить исключение, которое он сам не обрабатывает, он должен задать это поведение так, чтобы вызывающий его код мог позаботиться об этом исключении. Для этого к объявлению метода добавляется конструкция throws, которая перечисляет типы исключений (кроме исключений Error и RuntimeException и их подклассов).

Общая форма объявления метода с оператором throws:


тип имя_метода(список_параметров) throws список_исключений {
    // код внутри метода
}

В фрагменте список_исключений можно указать список исключений через запятую.

Создадим метод, который может породить исключение, но не обрабатывает его. А в щелчке кнопки вызовем его.


// Метод без обработки исключения
public void createCat(){
	Toast.makeText(this, "Вы создали котёнка", Toast.LENGTH_LONG).show();
	throw new NullPointerException("Кота не существует");
}

// Щелчок кнопки
public void onClick(View v) {
	createCat();
}

Если вы запустите пример, то получите ошибку. Исправим код.


// Без изменений
public void createCat() throws NullPointerException {
	Toast.makeText(this, "Вы создали котёнка", Toast.LENGTH_LONG).show();
	throw new NullPointerException("Кота не существует");
}

// Щелчок кнопки
public void onClick(View v) {
	try {
		createCat();
	} catch (NullPointerException e) {
		// TODO: handle exception
		Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
	}
}

Мы поместили вызов метода в блок try и вызвали блок catch с нужным типом исключения. Теперь ошибки не будет.

Оператор finally

Когда исключение передано, выполнение метода направляется по нелинейному пути. Это может стать источником проблем. Например, при входе метод открывает файл и закрывает при выходе. Чтобы закрытие файла не было пропущено из-за обработки исключения, был предложен механизм finally.

Ключевое слово finally создаёт блок кода, который будет выполнен после завершения блока try/catch, но перед кодом, следующим за ним. Блок будет выполнен, независимо от того, передано исключение или нет. Оператор finally не обязателен, однако каждый оператор try требует наличия либо catch, либо finally.

Существуют несколько готовых системных исключений. Большинство из них являются подклассами типа RuntimeException и их не нужно включать в список throws. Вот небольшой список непроверяемых исключений.

  • ArithmeticException — арифметическая ошибка, например, деление на нуль
  • ArrayIndexOutOfBoundsException — выход индекса за границу массива
  • ArrayStoreException — присваивание элементу массива объекта несовместимого типа
  • ClassCastException — неверное приведение
  • EnumConstantNotPresentException — попытка использования неопределённого значения перечисления
  • IllegalArgumentException — неверный аргумент при вызове метода
  • IllegalMonitorStateException — неверная операция мониторинга
  • IllegalStateException — некорректное состояние приложения
  • IllegalThreadStateException — запрашиваемая операция несовместима с текущим потоком
  • IndexOutofBoundsException — тип индекса вышел за допустимые пределы
  • NegativeArraySizeException — создан массив отрицательного размера
  • NullPointerException — неверное использование пустой ссылки
  • NumberFormatException — неверное преобразование строки в числовой формат
  • SecurityException — попытка нарушения безопасности
  • StringIndexOutOfBounds — попытка использования индекса за пределами строки
  • TypeNotPresentException — тип не найден
  • UnsupportedOperationException — обнаружена неподдерживаемая операция

Список проверяемых системных исключений, которые можно включать в список throws.

  • ClassNotFoundException — класс не найден
  • CloneNotSupportedException — попытка клонировать объект, который не реализует интерфейс Cloneable
  • IllegalAccessException — запрещен доступ к классу
  • InstantiationException — попытка создать объект абстрактного класса или интерфейса
  • InterruptedException — поток прерван другим потоком
  • NoSuchFieldException — запрашиваемое поле не существует
  • NoSuchMethodException — запрашиваемый метод не существует
  • ReflectiveOperationException — исключение, связанное с рефлексией

Создание собственных классов исключений

Система не может предусмотреть все исключения, иногда вам придётся создать собственный тип исключения для вашего приложения. Вам нужно наследоваться от Exception (напомню, что этот класс наследуется от Trowable) и переопределить нужные методы класса Throwable. Либо вы можете наследоваться от уже существующего типа, который наиболее близок по логике с вашим исключением.

  • final void addSuppressed(Throwable exception) — добавляет исключение в список подавляемых исключений (JDK 7)
  • Throwable fillInStackTrace() — возвращает объект класса Throwable, содержащий полную трассировку стека.
  • Throwable getCause() — возвращает исключение, лежащее под текущим исключение или null
  • String getLocalizedMessage() — возвращает локализованное описание исключения
  • String getMessage() — возвращает описание исключения
  • StackTraceElement[] getStackTrace() — возвращает массив, содержащий трассировку стека и состояний из элементов класса StackTraceElement
  • final Throwable[] getSuppressed() — получает подавленные исключения (JDK 7)
  • Throwable initCause(Throwable exception) — ассоциирует исключение с вызывающим исключением. Возвращает ссылку на исключение.
  • void printStackTrace() — отображает трассировку стека
  • void printStackTrace(PrintStream stream) — посылает трассировку стека в заданный поток
  • void printStackTrace(PrintWriter stream) — посылает трассировку стека в заданный поток
  • void setStackTrace(StackTraceElement elements[]) — устанавливает трассировку стека для элементов (для специализированных приложений)
  • String toString() — возвращает объект класса String, содержащий описание исключения.

Самый простой способ — создать класс с конструктором по умолчанию.


// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.

package ru.alexanderklimov.exception;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void testMethod() throws HungryCatException{
        System.out.println("Возбуждаем HungryCatException из метода testMethod()");
        throw new HungryCatException(); // конструктор по умолчанию
    }

    public void onClick(View view) {
        try {
            testMethod();
        } catch (HungryCatException e) {
            e.printStackTrace();
            System.out.println("Наше исключение перехвачено");
        }
    }

    class HungryCatException extends Exception{
    }
}

Мы создали собственный класс HungryCatException, в методе testMethod() его возбуждаем, а по нажатию кнопки вызываем этот метод. В результате наше исключение сработает.

Создать класс исключения с конструктором, который получает аргумент-строку, также просто.


// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.

package ru.alexanderklimov.exception;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void testMethod() throws HungryCatException {
        System.out.println("Возбуждаем HungryCatException из метода testMethod()");
        throw new HungryCatException(); // конструктор по умолчанию
    }

    public void testMethod2() throws HungryCatException {
        System.out.println("Возбуждаем HungryCatException из метода testMethod2()");
        throw new HungryCatException("Создано во втором методе");
    }

    public void onClick(View view) {
        try {
            testMethod();
        } catch (HungryCatException e) {
            e.printStackTrace();
            System.out.println("Наше исключение перехвачено");
        }

        try {
            testMethod2();
        } catch (HungryCatException e) {
            e.printStackTrace();
        }
    }

    class HungryCatException extends Exception {
        HungryCatException() {
        }

        HungryCatException(String msg) {
            super(msg);
        }
    }
}

Ещё вариант. Добавим также метод toString().


class CustomException extends Exception {
    String message;

    CustomException(String str) {
        message = str;
    }

    public String toString() {
        return ("Custom Exception Occurred: " + message);
    }
}

// где-то вызываем
try {
    throw new CustomException("This is a custom message");
} catch (CustomException e) {
    System.out.println(e);
}

Теперь класс содержит два конструктора. Во втором конструкторе используется конструктор родительского класса с аргументом String, вызываемый ключевым словом super.

Перехват произвольных исключений

Можно создать универсальный обработчик, перехватывающий любые типы исключения. Осуществляется это перехватом базового класса всех исключений Exception:

cacth(Exception e) {
    Log.w("Log", "Перехвачено исключение");
}

Подобная конструкция не упустит ни одного исключения, поэтому её следует размещать в самом конце списка обработчиков, во избежание блокировки следующих за ней обработчиков исключений.

Основные правила обработки исключений

Используйте исключения для того, чтобы:

  • обработать ошибку на текущем уровне (избегайте перехватывать исключения, если не знаете, как с ними поступить)
  • исправить проблему и снова вызвать метод, возбудивший исключение
  • предпринять все необходимые действия и продолжить выполнение без повторного вызова действия
  • попытаться найти альтернативный результат вместо того, который должен был бы произвести вызванный метод
  • сделать все возможное в текущем контексте и заново возбудить это же исключение, перенаправив его на более высокий уровень
  • сделать все, что можно в текущем контексте, и возбудить новое исключение, перенаправив его на более высокий уровень
  • завершить работу программы
  • упростить программу (если используемая схема обработки исключений делает все только сложнее, значит, она никуда не годится)
  • добавить вашей библиотеке и программе безопасности
Реклама

На чтение 14 мин. Опубликовано 21.12.2020

Исключение в Java – это нештатная ситуация, ошибка, случившееся во время выполнения программы. Например, деление на ноль. Возникновение подобных ошибок можно отслеживать вручную или использовать специальный механизм исключений, упрощающий создание более надежных программ, а также уменьшающий объем кода. Так вы будете уверены, что программа не пострадает от необработанной ошибки.

В том методе, где произошла ошибка, создается и передается специальный объект. При этом метод может либо обработать исключение сам, либо пропустить его. Как бы там ни было исключение ловится и обрабатывается. Оно может появиться благодаря системе или вы можете создать его самостоятельно. Системные исключения появляются при использовании запрещенных приемов доступа к системе или неправильном использовании Java. Что касается ваших собственных исключений, то они обрабатывают специфические ошибки программы.

Рассмотрим пример с делением. Проверка соответствующего условия может предотвратить деление на ноль. Но что, если знаменатель является нулем? Если же такой нулевой знаменатель появился неожиданно, то деление невозможно и нужно возбудить исключение, и ни в коем случае не продолжать исполнение программы.

В исключениях используется пять ключевых слов: try, catch, throw, throws, finally. Схема обработки исключений следующая.

В блок try помещаются операторы программы, которые нужно отслеживать. Если произошло исключение, то оно создается и передается дальше. С помощью блока catch код может перехватить исключения и обработать его.

За передачу системных исключений отвечает сама система. Чтобы сделать это вручную, применяется throw. Созданное и передаваемое исключение внутри метода, указывается ключевым словом throws. Код, который обязательно выполнить после завершения блока try, заключается в блок finally.

Пример:

try {
// блок кода, где отслеживаются ошибки
}
catch (тип_исключения_1 exceptionObject) {
// обрабатываем ошибку
}
catch (тип_исключения_2 exceptionObject) {
// обрабатываем ошибку
}
finally {
// код, который нужно выполнить после завершения блока try
}

Для исключений существует специальный класс Trowable, в который входят 2 класса — Exception и Error. Первый используется для обработки исключений вашим приложением. Вы можете наследоваться от него, чтобы создавать собственные исключения. Класс Runtime Exception существует для распространения ошибок, который определяет ошибочную индексацию массива или обрабатывает деление на ноль.

Класс Error применяется для обработки ошибок в языке Java. Поэтому вам не придется с ним работать.
Перед тем, как научиться обрабатывать исключения, любому любопытному программисту захочется посмотреть, что же происходит, если не обработать ошибку. Давайте рассмотрим пример с делением котов на ноль:

intcatNumber;
intzero;
catNumber = 1; // у меня один кот
zero = 0; // ноль, он и в Африке ноль
intresult = catNumber / zero;

Если разместить команду в обработчик щелчка кнопки, то система времени выполнения Java выявит попытку деления на ноль, создаст объект исключения и передаст его. Но никто не перехватывает его, так как это должны быть сделать именно вы. Когда система видит вашу бездеятельность, вступает стандартный системный обработчик с вредным характером. Он остановит программу и покажет сообщение об ошибке. Его можно увидеть в журнале LogCat:

Causedby: java.lang.ArithmeticException: dividebyzeroat ru.alexanderklimov.test.MainActivity.onClick(MainActivity.java:79)

Созданный объект исключений относится к классу Arithmetic Exception. Затем системный обработчик вывел краткое описание ошибки, а также место его возникновения.

Если вы так и оставите процесс обработки ошибки системы, то вызовите недовольство пользователей. Если программа завершится с такой ошибкой, то вероятней всего ее просто удалят. Посмотрим, как разрешить эту ситуацию.

Разместите проблемный код в блок try и обработайте исключение в блоке catch.

intcatNumber;
intzero;

try{ // мониторим код
catNumber = 1; // у меня один кот
zero = 0; // ноль, он и в Африке ноль
intresult = catNumber / zero;
Toast.makeText(this, «Не увидите это сообщение!», Toast.LENGTH_LONG).show();
} catch (ArithmeticException e) {
Toast.makeText(this, «Нельзя котов делить на ноль!», Toast.LENGTH_LONG).show();
}
Toast.makeText(this, «Жизнь продолжается», Toast.LENGTH_LONG).show();

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

В таком случае мы уже знали, к какому именно классу принадлежит эта ошибка, так как в блоке catch указали конкретный тип. Учтите, что последний оператор не срабатывает в блоке try, поскольку ошибка происходит строчкой выше. Затем выполнения передается в catch и в обычном порядке выполняются следующие операторы.

Операторы try и catch действуют в паре. Возможны ситуации, когда catch обрабатывает несколько вложений try.

Параметр е поможет вам увидеть описание ошибки:

catch (ArithmeticException e) {
Toast.makeText(this, e + «: Нельзя котов делить на ноль!», Toast.LENGTH_LONG).show();
}

Класс Trowable, к которому относится Arithmetic Exception, по умолчанию возвращает строку, содержащую описание исключения. Однако вы можете явно указать метод e.toString.

Несколько исключений

Код может содержать ни одно, а несколько проблемных мест. К примеру, помимо деления на ноль, может возникнуть ошибка индексации массива. В этом случае вам необходимо создавать или больше операторов catch для всех типов исключения. При этом они проверяются по порядке. Если будет обнаружено исключение у первого блока, то он будет выполнен, тогда как другие проверки пропускаются и выполнения приложения продолжается с места, следующего за блоком try/catch.

intcatNumber;
intzero;

try{ // мониторим код
catNumber = 1; // у меня один кот
zero = 1; // ноль, он и в Африке ноль
intresult = catNumber / zero;
// Создадим массив из трёх котов
String[] catNames = {«Васька», «Барсик», «Мурзик»};
catNames[3] = «Рыжик»;
Toast.makeText(this, «Не увидите это сообщение!», Toast.LENGTH_LONG).show();
} catch (ArithmeticException e) {
Toast.makeText(this, e.toString() + «: Нельзя котов делить на ноль!», Toast.LENGTH_LONG).show();
}
catch (ArrayIndexOutOfBoundsException e) {
Toast.makeText(this, «Ошибка: » + e.toString(), Toast.LENGTH_LONG).show();
}
Toast.makeText(this, «Жизнь продолжается», Toast.LENGTH_LONG).show();

В рассматриваемом примере, мы использовали массив с тремя элементами, но обращались к четвертому, поскольку забыли, что отсчет у массива начинается с нуля. Если значение переменной zero оставить равным нулю, то сработает обработка первого исключения деления на ноль. При этом мы даже не будем знать о существовании второй ошибки. Но представьте, если в результате определенных вычислений значений переменной = 1. В таком случае Arithmetic Exception не сработает, но вступит новое добавленное Array Index Out Of Bounds Exception. Дальше процесс будет таким же.

Здесь важно знать одну особенность. Используя множественные операторы catch обработки подклассов исключений должны располагаться выше по отношению обработчиков их суперклассов. В противном случае, суперкласс будет перехватывать все исключения, так как имеет большую область перехвата. Другими словами, Exception не должен располагаться выше Arithmetic Exception и Array Index Out Of Bounds Exception. Хорошо, что среда разработки сама обнаружит непорядок и обязательно вас предупредит об этом. Заметив такую ошибку, перенесите блок обработки исключений ниже.

Вложенные операторы try

Операторы try бывают вложенными. Если такой оператор не имеет собственного обработчика catch для определения исключения, то происходит поиск обработчика catch у внешнего блока try и так далее. Если не найдется подходящий catch, то сама система обработает исключения, что, конечно же, недопустимо.

Оператор throw

Система может обрабатывать часть исключений. Но с помощью оператора throw можно создать собственные исключения. Когда выглядит следующим образом:

throw экземпляр_Throwable

Вам необходимо создать экземпляр класса Throwable или же его наследников. Объект класса Throwable можно получить в операторе catch или традиционным способом посредством оператора new.

Пример кода для кнопки:

Catcat;

publicvoidonClick(Viewview) {
if(cat == null){
thrownewNullPointerException(«Котик не инициализирован»);
}
}

В примере был объявлен объект класса Cat, ноне проинициализированный в onCreate(). Нажатие кнопки вызовет исключение, обрабатываемое системой, а в логах вы можете увидеть сообщение об ошибке. Также можно использовать другое исключение по типу thrownewUnsupportedOperationException(«Котик не инициализирован»).

Как бы там ни было, мы передали системе обработку ошибки. В реальной программе вам необходимо самостоятельно обработать ошибку.

При этом поток выполнения останавливается после оператора throw и остальные операторы не выполняются. Ищется ближайший блок try/catch соответствующего исключению типа.

Пример кода с обработкой ошибки:

publicvoidonClick(Viewview) {
if (cat == null) {
try {
thrownewNullPointerException(«Кота не существует»);
} catch (NullPointerException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}

Был создан новый объект класса NullPointerException. По умолчанию многие классы исключений (кроме стандартного конструктора) с пустыми скобками имеют второй конструктор с строковым параметром, где можно разместить информацию об исключении. Текст из него можно получить через метод getMessage(), что собственно и было сделано в блоке catch.

Теперь программа не будет закрыта аварийно, а выведет сообщение в сплывающих Toast.

Оператор throws

В том случае, если метод может продлить исключение, которое он не обрабатывает, он должен задать данное поведение так, чтобы вызывающий его код смог бы позаботиться об этом исключении. Для этой цели к объявлению метода добавляется конструкция throws, перечисляющая типы исключений (кроме Error и Runtime Exception, а также их подклассов).

Общая форма объявления метода с использованием оператора throws:

тип имя_метода(список_параметров) throwsсписок_исключений {
// код внутри метода
}

В фрагменте список_исключений можно через запятую указать список исключений. Создадим метод, который продлит исключение, но не обрабатывает его. И вызовем его при нажатии на кнопку.

// Метод без обработки исключения
publicvoidcreateCat(){
Toast.makeText(this, «Вы создали котёнка», Toast.LENGTH_LONG).show();
thrownewNullPointerException(«Кота не существует»);
}

// Щелчок кнопки
publicvoidonClick(View v) {
createCat();
}

Если вы запустите пример, то получите ошибку. Исправим код.

// Без изменений
publicvoidcreateCat() throwsNullPointerException {
Toast.makeText(this, «Вы создали котёнка», Toast.LENGTH_LONG).show();
thrownewNullPointerException(«Кота не существует»);
}

// Щелчок кнопки
publicvoidonClick(View v) {
try {
createCat();
} catch (NullPointerException e) {
// TODO: handleexception
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}

Вызов метода помещен в блок try. Блок catch с необходимым типом исключения. В данном случае ошибка не произойдет.

Оператор finally

После передачи исключения, выполнения метода направляется по нелинейному пути. Это может спровоцировать проблемы. К примеру, при входе метод открывает файл, а при выходе закрывает. Чтобы из-за обработки исключения не было пропущено закрытие файла, нужно воспользоваться оператором finally.

Оператор finally создаёт блок кода, который будет выполнен после блока try/catch, но перед кодом, идущим за ним. Блок будет выполнен, невзирая на то, будет передано исключение или нет. Оператор finally не обязателен, но каждый оператор try требует наличия либо finally, либо catch.

Встроенные исключения Java

Java поддерживает несколько готовых системных исключений, большая часть из которых является подклассами типа Runtime Exception. При этом их не нужно добавлять в список throws. Приведем наиболее распространенные неповторяемые исключения:

Illegal Monitor State Exception Неверная операция мониторинга
Index Out of Bounds Exception Тип индекса вышел за допустимые пределы
Array Store Exception Присваивание элементу массива объекта несовместимого типа
Type Not Present Exception Тип не найден
Enum Constant Not Present Exception Попытка использования неопределённого значения перечисления
Number Format Exception Неверное преобразование строки в числовой формат
Unsupported Operation Exception Обнаружена неподдерживаемая операция
Arithmetic Exception Арифметическая ошибка, к примеру, деление на ноль
Illegal Thread State Exception Запрашиваемая операция несовместима с текущим потоком
String Index Out Of Bounds Попытка использования индекса за пределами строки
Class Cast Exception Неверное приведение
Security Exception Попытка нарушения безопасности
Illegal Argument Exception Неверный аргумент при вызове метода
Null Pointer Exception Неверное использование пустой ссылки
Array Index Out Of Bounds Exception Выход индекса за границу массива
Unsupported Operation Exception Обнаружена неподдерживаемая операция
Illegal State Exception Некорректное состояние приложения
Negative Array Size Exception Создан массив отрицательного размера

Проверяемые системные исключения, которые можно включать в список throws.

Interrupted Exception Поток прерван другим потоком
Class Not Found Exception Класс не найден
No Such Field Exception Запрашиваемое поле не существует
Illegal Access Exception Запрещен доступ к классу
Reflective Operation Exception Исключение, связанное с рефлексией
Instantiation Exception Попытка создать объект абстрактного класса или интерфейса
CloneNotSupportedException Попытка клонировать объект, который не реализует интерфейс Cloneable
No Such Method Exception Запрашиваемый метод не существует

Создание собственных классов исключений

Система не в состоянии предусмотреть все исключения. В некоторых случаях придется создавать свой тип исключения для собственного приложения. Вам необходимо наследоваться от Exception (данный класс наследуется от Trowable) и переопределить необходимые методы класса Throwable. Также вы можете наследоваться уже от существующего типа, наиболее близкого по логике с исключением.

Stringget Localized Message() Возвращает локализованное описание исключения
Final void add Suppressed (Throwable exception) Добавляет исключение в список подавляемых исключений (JDK 7)
Void print Stack Trace (Print Writer stream) Посылает трассировку стека в заданный поток
String get Message() Возвращает описание исключения
Throwable fill InStack Trace() Возвращает объект класса Throwable, содержащий полную трассировку стека
String to String() Возвращает объект класса String, содержащий описание исключения
Void print Stack Trace() Отображает трассировку стека
Throwable get Cause() Возвращает исключение, лежащее под текущим исключение или null
Void set Stack Trace (Stack Trace Elementelements[]) Устанавливает трассировку стека для элементов (для специализированных приложений)
Final Throwable[] get Suppressed() Получает подавленные исключения (JDK 7)
Stack Trace Element[] get Stack Trace() Возвращает массив, содержащий трассировку стека и состояний из элементов класса StackTraceElement
Throwable init Cause(Throwable exception) Ассоциирует исключение с вызывающим исключением. Возвращает ссылку на исключение

Наиболее простой способ — создать класс с конструктором по умолчанию.

// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.

packageru.alexanderklimov.exception;

importandroid.os.Bundle;
import android.support.v7.app.AppCompatActivity;
importandroid.view.View;

publicclassMainActivityextendsAppCompatActivity {

@Override
protectedvoidonCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

publicvoidtestMethod() throwsHungryCatException{
System.out.println(«Возбуждаем HungryCatException из метода testMethod()»);
thrownewHungryCatException(); // конструктор по умолчанию
}

publicvoidonClick(Viewview) {
try {
testMethod();
} catch (HungryCatException e) {
e.printStackTrace();
System.out.println(«Наше исключение перехвачено»);
}
}

classHungryCatExceptionextendsException{
}
}

В примере создан собственный класс Hungry Cat Exception, который возбужден в методе test Method(). По нажатию кнопки вызываем данный метод. Наше исключение сработает.

Несложно будет и создать класс исключения с конструктором, получающим аргумент-строку.

// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.

packageru.alexanderklimov.exception;

importandroid.os.Bundle;
import android.support.v7.app.AppCompatActivity;
importandroid.view.View;

publicclassMainActivityextendsAppCompatActivity {

@Override
protectedvoidonCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

publicvoidtestMethod() throwsHungryCatException {
System.out.println(«Возбуждаем HungryCatException из метода testMethod()»);
thrownewHungryCatException(); // конструктор по умолчанию
}

publicvoid testMethod2() throwsHungryCatException {
System.out.println(«Возбуждаем HungryCatException из метода testMethod2()»);
thrownewHungryCatException(«Создано во втором методе»);
}

publicvoidonClick(Viewview) {
try {
testMethod();
} catch (HungryCatException e) {
e.printStackTrace();
System.out.println(«Наше исключение перехвачено»);
}

try {
testMethod2();
} catch (HungryCatException e) {
e.printStackTrace();
}
}

classHungryCatExceptionextendsException {
HungryCatException() {
}

HungryCatException(Stringmsg) {
super(msg);
}
}
}

Ещё вариант. Также добавим метод toString().

classCustomExceptionextendsException {
Stringmessage;

CustomException(Stringstr) {
message = str;
}

publicStringtoString() {
return («CustomExceptionOccurred: » + message);
}
}

// где-то вызываем
try {
thrownewCustomException(«Thisis a custommessage»);
} catch (CustomException e) {
System.out.println(e);
}

Теперь наш класс содержит два конструктора. Во втором применяется конструктор родительского класса с аргументом String, который вызывается ключевым словом super.

Перехват произвольных исключений

Создадим универсальный обработчик, который будет перехватывать любые типы исключений. Это осуществляется перехватом базового класса всех исключений Exception:

cacth(Exception e) {
Log.w(«Log», «Перехвачено исключение»);
}

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

Правила обработки исключений

Исключения нужно использовать для того, чтобы:

  • Исправить проблему и повторно вызвать метод, возбудивший исключение.
  • Обработать ошибку на текущем уровне (если не знаете как поступить с исключением, избегайте его перехватывания).
  • Предпринять все действия и продолжить выполнения без необходимости повторно вызова действий.
  • Завершить работу программы.
  • Попытаться найти альтернативное решение (результат вместо того который должен был осуществить вызванный метод).
  • Упростить программу (если схема обработки исключений делает все сложнее, значит она не эффективная).
  • Добавить программе и библиотеке безопасности.

Освоили ли вы этот материал? Какие сложности у вас возникли? Напишите ответ в комментариях.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Java ошибка 1603 как исправить windows 10 64 bit
  • Java ошибка 112 как исправить