Translate

суббота, 30 июня 2012 г.

Исключения в Java. Разработка класса исключения. Анализ логов приложения в случае возникновения исключения.

 При программировании часто возникают различного рода ошибки — ошибки программиста, пользователя, баги в сторонних библиотеках. Программа должна каким-то образом адекватно реагировать на их возникновение.

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

  Другой пример: юзер заполняет в приложении какую-нибудь анкету. Ввел кучу данных и вдруг записал что-то в неправильном формате. Программа падает, юзер недоволен. А можно было бы вывести сообщение и дать возможность пользователю дозаполнить анкету.


  При программировании на 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);

Убеждаемся, что исключение было брошено и в логах написано ровно то, что нужно.

Комментариев нет:

Отправить комментарий

Related Posts Plugin for WordPress, Blogger...