При программировании часто возникают различного рода ошибки — ошибки программиста, пользователя, баги в сторонних библиотеках. Программа должна каким-то образом адекватно реагировать на их возникновение.
Например, пользователь решил поставить себе игру, управляемую акселерометром, а у него в устройстве этого самого акселерометра-то и нет. Программа должна объяснить это пользователю, а не закрываться с сообщением о неизвестной ошибке, иначе пользователь может решить, что криворукие кодеры не сделали поддержку его устройства и написать плохой отзыв.
Другой пример: юзер заполняет в приложении какую-нибудь анкету. Ввел кучу данных и вдруг записал что-то в неправильном формате. Программа падает, юзер недоволен. А можно было бы вывести сообщение и дать возможность пользователю дозаполнить анкету.
При программировании на android необработанное исключение вызывает сообщение об ошибке, и программа завершает свою работу.
Сначала научимся смотреть логи программы — для этого нужно включить LogCat с помощью Windows->ShowView->Other->LogCat
Для обработки исключений в Java используется механизм try-catch-finally. Создадим новый android проект со следующим кодом главного activity:
Параметром блока catch{} служит класс исключения, который мы пытаемся обработать. В данном примере мы пытаемся поймать все исключения класса Exception и его наследников.
Блок finally(может быть опущен) используется, когда при работе с кодом мы используем внешние ресурсы — файлы, соединения и др. Они должны быть как-то закрыты после выполнения кода. Поэтому инструкции, записанные в блоке finally, исполняются всегда, вне зависимости от того, возникло исключение или нет.
В данном случае в логах приложения мы увидим записи желтого цвета(обработанное исключение), выводящие информацию о том, конкретно где exception и вылез — в onCreate() в строке номер 15. Также там написан конкретный типа исключения — класс-наследник типа Exception, именуемый NullPointerException. Действительно, в 15-й строке мы сделали a.charAt(3) – обратились к непроинициализованной строке а. Если бы мы не использовали try-catch-finally, программа бы упала, а в лог информация записалась бы красным цветом.
Как уже было сказано, исключение — объект особого типа. Практически, при обработке следует понимать, какие exceptions могут возникнуть и обрабатывать их поочередно:
Некоторые классы исключений:
-RuntimeException
-NullPointerException – произведена какая-то операция с чем-то, равным null. Например, попытка обратиться к полю объекта до вызова его конструктора(объект еще не создан)
-IndexOutOfBoundException — ошибки выхода за пределы чего-либо
-ArrayIndexOutOfBoundsException – выход за пределы массива. Внимательно следуите за индексами, которые вы вычисляете
-StringIndexOutOfBoundException – аналогично предыдущему, только вместо массива выступает строка
-IllegalStateException – в функцию подан неккоректный параметр
-ArithmeticException – исключения, связанные с вычислениями
-DivisionByZeroException – целочисленное деление на 0
-ClassCastException – неправильно произведено преобразование классов
-IOException – ошибка при работе с внешним файлом(например, файл не найден)
-другие, в тч удобно собственные классы исключений наследовать от класса Exception
Все исключения в Java можно разделить на 2 большие группы — checkedExceptions и nonCheckedExceptions.
CheckedExceptions — такие исключения, при возникновении которых чего-то очень сильно опасного в программе происходить не должно и мы обязаны такое исключение обработать. В большинстве случаем причиной ошибки должны быть действия пользователя. Например, класс IOException является checkedException – если у нас ошибка при чтении файла, скорее всего, нам скормили какие-то некорректные данные. Особенностью таких исключений является то, что мы любой оператор, способный их бросить, должен оборачиваться в блок try-catch-(finally).
nonCheckedException, соответственно, являются обычно ошибками программистов или библиотек. Все классы, являющиеся наследниками RuntimeException (и он сам, конечно, тоже), являются nonCheckedExceptions, а остальные — наоборот.
Конечно, если мы будем проектировать свой класс, хорошо, если бы он тоже мог бросать исключения. Для этой цели в методе используется инструкция:
throw new <Класс исключения>(аргументы конструктора исключения).
При этом метод, в котором прямо или косвенно используется оператор throw, должен быть снабжен модификатором throws<Класс исключения>
Рассмотрим пример класса, бросающего checkedException. Он описывает отрезок с определенными координатами начала и конца, задаваемыми в конструкторе. Пусто он должен возвращать длину линии и ее ориентирный угол в радианах и градусах (ось х направлена вверх, ось у — вправо, ориентирный угол отсчитывается от оси х по часовой стрелке)
Если при определении ориентирного угла оба приращения координат равны 0, явно что-то нечисто и следует бросить исключение. Код класса отрезка:
Класс исключения:
Теперь изменим код onCreate на:
Убеждаемся, что исключение было брошено и в логах написано ровно то, что нужно.
Например, пользователь решил поставить себе игру, управляемую акселерометром, а у него в устройстве этого самого акселерометра-то и нет. Программа должна объяснить это пользователю, а не закрываться с сообщением о неизвестной ошибке, иначе пользователь может решить, что криворукие кодеры не сделали поддержку его устройства и написать плохой отзыв.
Другой пример: юзер заполняет в приложении какую-нибудь анкету. Ввел кучу данных и вдруг записал что-то в неправильном формате. Программа падает, юзер недоволен. А можно было бы вывести сообщение и дать возможность пользователю дозаполнить анкету.
При программировании на android необработанное исключение вызывает сообщение об ошибке, и программа завершает свою работу.
Сначала научимся смотреть логи программы — для этого нужно включить LogCat с помощью Windows->ShowView->Other->LogCat
Для обработки исключений в Java используется механизм try-catch-finally. Создадим новый android проект со следующим кодом главного activity:
package com.exc;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class ExceptiontestActivity extends Activity {
/** Called when the activity is first created. */
String a;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {//оборачиваем следующий код в блок обработки исключений
a.charAt(3);//код, способный вызвать ошибку
} catch (Exception e) {
//здесь мы должны как-то обработать ошибку — известить пользователя, записать в лог информацию и тд.
e.printStackTrace();//Выведем в лог информацию об ошибке — место возникновения, вплоть до конкретной строки кода, где возникло исключение
}
finally{
//Закрываем внешние ресурсы
Log.d("app", "This is me, finally-block");//Операция записи в лог определенной строки(первый аргумент — тег записи, второй - сообщение)
}
setContentView(R.layout.main);
}
}
В onCreate может возникнуть ошибка. Поэтому соответствующий код обернут в блог try{}, за которым следует блог catch{}, который будет исполняться, если возникло исключение. Параметром блока catch{} служит класс исключения, который мы пытаемся обработать. В данном примере мы пытаемся поймать все исключения класса Exception и его наследников.
Блок finally(может быть опущен) используется, когда при работе с кодом мы используем внешние ресурсы — файлы, соединения и др. Они должны быть как-то закрыты после выполнения кода. Поэтому инструкции, записанные в блоке finally, исполняются всегда, вне зависимости от того, возникло исключение или нет.
В данном случае в логах приложения мы увидим записи желтого цвета(обработанное исключение), выводящие информацию о том, конкретно где exception и вылез — в onCreate() в строке номер 15. Также там написан конкретный типа исключения — класс-наследник типа Exception, именуемый NullPointerException. Действительно, в 15-й строке мы сделали a.charAt(3) – обратились к непроинициализованной строке а. Если бы мы не использовали try-catch-finally, программа бы упала, а в лог информация записалась бы красным цветом.
Как уже было сказано, исключение — объект особого типа. Практически, при обработке следует понимать, какие exceptions могут возникнуть и обрабатывать их поочередно:
try{
//Код
}
catch(<Первый тип исключений> e1){
//Обрабатываем первый тип
}
catch(<Второй тип исключений> e2){
//Обрабатываем второй тип. Конечно, если исключение первого типа возникло ранее, программа сюда уже не дойдет
}
finally{
//закрываем ресурсы
}
Некоторые классы исключений:
-RuntimeException
-NullPointerException – произведена какая-то операция с чем-то, равным null. Например, попытка обратиться к полю объекта до вызова его конструктора(объект еще не создан)
-IndexOutOfBoundException — ошибки выхода за пределы чего-либо
-ArrayIndexOutOfBoundsException – выход за пределы массива. Внимательно следуите за индексами, которые вы вычисляете
-StringIndexOutOfBoundException – аналогично предыдущему, только вместо массива выступает строка
-IllegalStateException – в функцию подан неккоректный параметр
-ArithmeticException – исключения, связанные с вычислениями
-DivisionByZeroException – целочисленное деление на 0
-ClassCastException – неправильно произведено преобразование классов
-IOException – ошибка при работе с внешним файлом(например, файл не найден)
-другие, в тч удобно собственные классы исключений наследовать от класса Exception
Все исключения в Java можно разделить на 2 большие группы — checkedExceptions и nonCheckedExceptions.
CheckedExceptions — такие исключения, при возникновении которых чего-то очень сильно опасного в программе происходить не должно и мы обязаны такое исключение обработать. В большинстве случаем причиной ошибки должны быть действия пользователя. Например, класс IOException является checkedException – если у нас ошибка при чтении файла, скорее всего, нам скормили какие-то некорректные данные. Особенностью таких исключений является то, что мы любой оператор, способный их бросить, должен оборачиваться в блок try-catch-(finally).
nonCheckedException, соответственно, являются обычно ошибками программистов или библиотек. Все классы, являющиеся наследниками RuntimeException (и он сам, конечно, тоже), являются nonCheckedExceptions, а остальные — наоборот.
Конечно, если мы будем проектировать свой класс, хорошо, если бы он тоже мог бросать исключения. Для этой цели в методе используется инструкция:
throw new <Класс исключения>(аргументы конструктора исключения).
При этом метод, в котором прямо или косвенно используется оператор throw, должен быть снабжен модификатором throws<Класс исключения>
Рассмотрим пример класса, бросающего checkedException. Он описывает отрезок с определенными координатами начала и конца, задаваемыми в конструкторе. Пусто он должен возвращать длину линии и ее ориентирный угол в радианах и градусах (ось х направлена вверх, ось у — вправо, ориентирный угол отсчитывается от оси х по часовой стрелке)
Если при определении ориентирного угла оба приращения координат равны 0, явно что-то нечисто и следует бросить исключение. Код класса отрезка:
package com.exc;
public class Line {
private double x1;
private double x2;
private double y1;
private double y2;
private double dx;
private double dy;
private double dirAngle;
public Line(double x1, double y1, double x2, double y2){
this.x1=x1;
this.x2=x2;
this.y1=y1;
this.y2=y2;
}
public double dist(){
findDxAndDy();//определим приращения
return Math.sqrt(dx*dx+dy*dy); //расчет по теореме Пифагора
}
public double findDirAngleInRads() throws LineException {
findDirAngle();//определим ориентирный угол
return dirAngle;
}
public double findDirAngleInDegrees() throws LineException {
findDirAngle();
return dirAngle*180/Math.PI; //Переведем радианы в градусы и вернем результат
}
private void findDxAndDy() {
dx=x2-x1;
dy=y2-y1;
}
private void findDirAngle() throws LineException{
findDxAndDy();
if(dx==0 && dy==0){
//Исключительная ситуация
throw new LineException("Координаты первой точки - Х="+x1+" Y="+y1+" - совпадают с координатами второй");
}
dirAngle=Math.atan2(dy, dx);//Для определения ориентирного угла в радианах следует использовать функций Math.atan2(), так как она возвращает угол в соответствие со знаками приращений
}
}
Класс исключения:
package com.exc;
public class LineException extends Exception {//пусть исключение будет проверяемым
public LineException(String message){
super(message);
}
}
Теперь изменим код onCreate на:
super.onCreate(savedInstanceState);
try {
Line line=new Line(4,2,4,2);
Log.d("app", line.findDirAngleInDegrees()+"");
} catch (LineException e) {
Log.d("app", e.getMessage());
}
finally{
Log.d("app", "This is me, the finally-block");
}
setContentView(R.layout.main);
Убеждаемся, что исключение было брошено и в логах написано ровно то, что нужно.
Комментариев нет:
Отправить комментарий