Изключения

Изключения

Изключение(Exception) е събитие, което настъпва по време на изпълнение на програмата и затруднява нейното нормално завършване.

За разлика от други езици, в това число и С, където даден метод връща някакъв код за грешка и след това този код трябва да бъде внимателно проверяван, Java предоставя елегантен начин за обработка на изключения. Програмистът има възможност да дефинира блок с код, наречен код за обработка на изключения, който се изпълнява автоматично при поява на дадена грешка.
exception
В Java всички изклчения са представят в класове, наследници на родителския клас на всички класове – Object. От своя страна класът Throwable e родител на всички изключения.

Класът Error, е наследник на класа Throwable. Грешките от този клас са критични за изпълнението на програмата и при тяхната поява програмата не може да бъде възстановена. Грешките от този клас се „хвърлят” от runtime system и обикновенно са следствие от някакво некоректно условие, което се е появило по време на изпълнение на програмата. Пример за такива грешки са : OutofMemoryError, StackOverflowError. Нека дадем един пример за такава грешка.

Пример:

public class ErrorExample {

public static void main(String[] args) {

ErrorExample err = new ErrorExample();

err.firstMethod();
}

public void firstMethod(){

this.secondMethod();
}
public void secondMethod(){

this.firstMethod();
}
}
Output: Exception in thread "main" java.lang.StackOverflowError
at error.firstMethod(error.java:9)
at error.secondMethod(error.java:13)
at error.firstMethod(error.java:9)
at error.secondMethod(error.java:13)

От друга страна както добре знаем всяка една програма на Java минава през няколко етапа- етап на компилация и етап на изпълнение. Изключенията, които се прихващат по време на компилация са така наречените проверени изключения(Checked Exception), a тези, които се прихващат от JVM по време на изпълнение, се наричат непроверени(Unchecked Exception). Ако дадено „Checked Exception” не бъде прихванато, компилаторът ще ”хвърли” Compilation error. Както става ясно от показаната фигура всички изключения, които са наследници на някой подклас на Exception, но не са наследници на Runtime Exception, са Unchecked Exception.

Важно е да се отбележи, че функционална разлика между Checked Exception и Unchecked Exception няма.

Ключови думи при работата с изключения са: try, catch, throws, throw, finally.

Когато се налага да прихванем дадено изключение, кодът генериращ това изключение трябва да бъде поставен след думата try като блок ограден с фигурни скоби.

try{
some code
}

След използване на try винаги се използва един или повече catch блока, където кодът в даден блок се изпълнява при прихваното изключение от този клас.

catch (SomeException object){
code
}

За по– голяма яснота нека дадем един пример:

import java.util.InputMismatchException;
import java.util.Scanner;
public class ExceptionExample {
public static void main(String[] args) {
int number = 0;
boolean result = false;
do {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter an integer.");
number = scanner.nextInt();
System.out.println(division(100, number));
result = true;
} while (!result);
}
public static int division(int a, int b) {

return a / b;
}
}

Програмата очаква потребителят да въведе цяло число и след това числото 100 да раздели на въведеното число. Основателен би бил въпросът какво би станало, ако потребителят по невнимание или напълно съзнателно въведе някакъв различен символ?

Програмата ще завърши със съобщение в червен цвят подобно на следното:

Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Unknown Source)
at java.util.Scanner.next(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at Exception.main(Exception.java:14)

Никой потребител, не би желал да види това!

Нека сега покажем една подобрена версия на същата програма.

import java.util.InputMismatchException;
import java.util.Scanner;
public class Exception {
public static void main(String[] args) {
int number = 0;
boolean result = false;
do {
try {
Scanner scanner = new Scanner(System.in);

System.out.println("Enter an integer.");

number = scaner.nextInt();

System.out.println(division(100, number));

result = true;
}

catch (InputMismatchException e) {

System.out.println("You didn’t enter integer.");

} catch (ArithmeticException e) {

System.out.println(e.getMessage());

} catch (Exception e) {

e.printStackTrace();
}
} while (!result);
}

public static int division(int a, int b) {

return a / b;
}
}

Както добре се забелязва местата, където очакваме да се появи дадено изключение, са поставени в try блока. Критичните момети в дадената програма са въвеждане на символ, различен от целочислен тип и въвеждане на числото нула. Изключение от първия вид ще бъде обработено от catch(InputMismatchException e) блока, където „е” в скобите е обект от клас InputMismatchException.

Изключение от втория вид ще бъде обработено от catch (ArithmeticException e) блока, където „е” в скобите е обект от клас ArithmeticException.

В горния код е добавен и catch блок за прихващане на изключение от най-общ тип – Exception. Важно е да се спомене, че последователността на прихващане на изключенията е от изключителна важност, поради техния обвиващ характер. Това означава, че прихващането на изключенията трябва да става от по-конкретен към по-общ клас(от наследник към родител). Ако дадено изключение не бъде прихванато, но е прихванато по-общо изключение от него, то по-частното ще се прихване от блока на по-общото. Ако им разменим местата, то ще настъпи компилационна грешка.

Нека обърнем внимание на ключовата дума finally. За целта ще разгледаме следния код:

public class FinallyExample {
public static void main(String[] args) {
int array[] = new int[5];
try {
System.out.println(array[7]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Enter a valid index.");
}
         finally{
System.out.println("This will printing ever.");
}
}
}

В дадената програма се опитваме да достъпим поле извън рамките на масива. Това изключение е прихванато в try блока и обработено в catch блока. Ключовата дума finally гарантира,че блокът след нея ще се изпълни независимо от това дали ще бъде прихванато изключение или не.

Неиният синтаксис е следният:

try{
code
}
catch(….){
}
…….
catch(….){
}
finally{
code
}

Хвърляне на изключения

Когато в даден метод  се появи изключение, методът може или да обработи даденото изключение или да го „хвърли” на викащия го метод. Това означава, че изкючението ще бъде обработено във викащия метод. Изключенията се „ хвърлят” чрез ключовата дума throws.

void  method() throws SomeException{
some code here;
}

Нека дадем по-конкретен пример:

import java.lang.*;
public class ExceptionExample {
public static void main(String[] args) {
try {
division(100, 0);
} catch (ArithmeticException e) {
System.out.println("You can’t divide by zero!");
}
}
public static void division(int a, int b) throws ArithmeticException {
int c = a / b;
System.out.println(c);
}
}

В дадената програма главният метод извиква метода devision, който сме декларирали, че хвърля изключение от тип ArithmeticException. От това, че throws присъства в декларацията на метода, следва че, където и да го извикаме ще трябва да бъде прихваното и обработено или отново изхвърлено даденото изключение.

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

В дадени моменти се налага програмистът сам да поеме управлението върху изключенията и сам да реши кога да хвърли дадено изключение. Java му предоставя тази възможност чрез ключовата дума throw. Пример:

 

import java.lang.*;

public class ExceptionExample {

public static void main(String[] args) {
try {
division(100, 0);
} catch (ArithmeticException e) {
System.out.println("You can’t divide by zero!");
}
}

public static void division(int a, int b) throws ArithmeticException {
if (b == 0) {
throw new ArithmeticException();
} else {
int c = a / b;
System.out.println(c);
}
}

В горната програма, в методът division сме направили проверка дали делителят е нула. Ако е така, то методът хвърля изключение от тип ArithmeticException. Ако в даден метод хвърлим изключение, то задължително трябва да декларираме с throws, че методът го хвърля.

Собствени изключения:

Java разполага с класове за стандартните изключения, които могат да възникнат в една програма. В някои случаи се налага да дефинираме и собствени изключения. Това става лесно, като си дефинираме клас, който наследява класът Exception или RunTimeException. Единственото нещо, което трябва да се направи, е да се предефинират някои методи, наследенени от родителя, например getMessage(). Нека да дадем пример:

public class Example {
public static void main(String[] args) {
try{
readPriceTv();
}
catch(PriceErrorException e){

System.out.println(e.getMessage());
}
}

private static int readPriceTv() throws PriceErrorException{

Scanner scanner = new Scanner(System.in);

int userPrice = scanner.nextInt();
if(userPrice > 500 || userPrice < 100){
throw new PriceErrorException();
}
return userPrice;
}
}

public class PriceErrorException extends Exception {
@Override

public String getMessage(){

return "Invalid price!";

}
}

В дадената програма е написан метод,който приема цена на TV със стойности между 100 и 500. В противен случай хвърля изключение от тип PriceErrorException.

Явор Томов, Даниел Джолев

One thought on “Изключения”

  1. ***Примерна задача***
    Напишете клас User с полета nickName и password. Класът имплементира
    интерфейса validater с абстрактен метод checking. Методът проверява дали nickName е
    email поща, ако е email, обектът се създава и се записва във файл, ако не е email,
    хвърля exception(който си го правим ние) и не позволява обекта да се създаде.
    Напишете статичен метод с 3 параметъра
    1- обект от тип файл
    2-String nickName
    3-String password
    методът връща boolean. По дадените nickName и password проверява във файла дали съществуват и съответсват ,
    ако да методът връща true, ако не съответно връща false.

Leave a Reply

Your email address will not be published. Required fields are marked *