Как да се справим с Java изключенията по правилния начин

Как да се справим с Java изключенията по правилния начин

Като начинаещ в програмирането, концепцията за обработка на изключения може да е трудно да увиете главата си. Не че самата концепция е трудна, но терминологията може да я накара да изглежда по -напреднала, отколкото е. И това е толкова мощна функция, че е склонна към злоупотреба и злоупотреба.





В тази статия ще научите какви са изключенията, защо са важни, как да ги използвате и често срещани грешки, които трябва да избягвате. Повечето съвременни езици имат някакъв вид обработка на изключения, така че ако някога преминете от Java, можете да вземете повечето от тези съвети със себе си.





Разбиране на Java изключенията

В Java, an изключение е обект, който показва, че нещо необичайно (или „изключително“) е станало по време на изпълнението на вашето приложение. Такива изключения са хвърлен , което основно означава, че е създаден обект на изключение (подобно на начина, по който грешките се „повдигат“).





Красотата е, че можеш улов хвърлени изключения, което ви позволява да се справите с ненормалното състояние и да позволите на приложението ви да продължи да работи, сякаш нищо не се обърка. Например, докато нулев указател в C може да срине приложението ви, Java ви позволява да хвърляте и улавяте

NullPointerException

s преди нулева променлива да има шанс да причини срив.



Не забравяйте, че изключението е просто обект, но с една важна характеристика: то трябва да бъде разширено от

Exception

клас или всеки подклас на





Exception

. Въпреки че Java има всякакви вградени изключения, можете също да създадете свои собствени, ако желаете. Някои от най -често срещаните Java изключения включват:

  • NullPointerException
  • NumberFormatException
  • IllegalArgumentException
  • RuntimeException
  • IllegalStateException

И така, какво се случва, когато хвърлите изключение?





Първо, Java гледа в рамките на непосредствения метод, за да види дали има код, който обработва вида на изключението, което сте хвърлили. Ако манипулатор не съществува, той разглежда метода, който извиква текущия метод, за да види дали там съществува дръжка. Ако не, той разглежда метода, който се обажда че метод, а след това следващият метод и т.н. Ако изключението не е уловено, приложението отпечатва проследяване на стека и след това се срива. (Всъщност това е по -нюансирано, отколкото просто срив, но това е напреднала тема извън обхвата на тази статия.)

ДА СЕ проследяване на стека е списък на всички методи, които Java преминава, докато търси манипулатор на изключения. Ето как изглежда следата на стека:

Exception in thread 'main' java.lang.NullPointerException
at com.example.myproject.Book.getTitle(Book.java:16)
at com.example.myproject.Author.getBookTitles(Author.java:25)
at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Можем да извлечем много от това. Първо, хвърленото изключение беше a

NullPointerException

. Това се случи през

getTitle()

метод на ред 16 на Book.java. Този метод е извикан от

getBookTitles()

на ред 25 на Author.java. Че методът е извикан от

main()

на ред 14 на Bootstrap.java. Както можете да видите, познаването на всичко това улеснява отстраняването на грешки.

Но отново, истинската полза от изключенията е, че можете да се справите с ненормалното състояние, като хванете изключението, зададете нещата както трябва и възобновите приложението, без да се сривате.

Използване на Java изключения в Code

Да кажем, че имате

someMethod()

който приема цяло число и изпълнява някаква логика, която може да се счупи, ако цяло число е по -малко от 0 или по -голямо от 100. Това би могло да бъде добро място за хвърляне на изключение:

код за грешка в центъра за помощ на Disney 83
public void someMethod(int value) {
if (value 100) {
throw new
IllegalArgumentException

За да уловите това изключение, трябва да отидете къде

someMethod()

се извиква и използва блок за опитване на улавяне :

public void callingMethod() {
try {
someMethod(200);
someOtherMethod();
} catch (IllegalArgumentException e) {
// handle the exception in here
}
// ...
}

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

В нашия пример влизаме в блока try и веднага се обаждаме

someMethod()

. Тъй като 200 не е между 0 и 100, an

IllegalArgumentException

е хвърлен. Това незабавно прекратява изпълнението на

someMethod()

, прескача останалата логика в блока try ((

someOtherMethod()

никога не се извиква) и възобновява изпълнението в рамките на блока catch.

Какво би станало, ако се обадим

someMethod(50)

вместо? The

IllegalArgumentException

никога нямаше да бъде хвърлен.

someMethod()

ще се изпълни нормално. Блокът try ще се изпълни нормално, извиквайки

someOtherMethod()

когато someMethod () завърши. Кога

someOtherMethod()

завършва, блокът за улов ще бъде пропуснат и

callingMethod()

ще продължи.

Имайте предвид, че можете да имате няколко блока за улавяне на блок за опит:

public void callingMethod() {
try {
someMethod(200);
someOtherMethod();
} catch (IllegalArgumentException e) {
// handle the exception in here
} catch (NullPointerException e) {
// handle the exception in here
}
// ...
}

Също така имайте предвид, че по избор най -накрая съществува и блок:

public void method() {
try {
// ...
} catch (Exception e) {
// ...
} finally {
// ...
}
}

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

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

Обърнете внимание, че можете да имате последен блок без блок за улов:

public void method() {
try {
// ...
} finally {
// ...
}
}

Това ви позволява да правите всяко необходимо почистване, като същевременно позволява на хвърлени изключения да разпространяват стека за извикване на метода (т.е. не искате да обработвате изключението тук, но все пак трябва първо да почистите).

Проверени срещу Непроверени изключения в Java

За разлика от повечето езици, Java прави разлика между проверени изключения и неконтролирани изключения (например C# има само непроверени изключения). Проверено изключение трябва да да бъде хванат в метода, при който се изхвърля изключението, в противен случай кодът няма да се компилира.

За да създадете проверено изключение, продължете от

Exception

. За да създадете непроверено изключение, продължете от

RuntimeException

.

Всеки метод, който хвърля проверено изключение, трябва да означава това в подписа на метода, използвайки хвърля ключова дума. Тъй като Java е вграден

IOException

е проверено изключение, следният код няма да се компилира:

public void wontCompile() {
// ...
if (someCondition) {
throw new IOException();
}
// ...
}

Първо трябва да декларирате, че хвърля проверено изключение:

public void willCompile() throws IOException {
// ...
if (someCondition) {
throw new IOException();
}
// ...
}

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

Кога трябва да използвате проверени или непроверени изключения?

Официалната документация по Java има страница по този въпрос . Той обобщава разликата с кратко сбито правило: „Ако може разумно да се очаква клиент да се възстанови след изключение, направете го проверено изключение. Ако клиентът не може да направи нищо, за да се възстанови от изключението, направете го непроверено изключение. '

Но тази насока може да е остаряла. От една страна, проверените изключения водят до по -стабилен код. От друга страна, никой друг език не е проверявал изключения по същия начин като Java, което показва две неща: едно, функцията не е достатъчно полезна за други езици, за да я открадне, и две, можете абсолютно да живеете без тях. Освен това проверените изключения не играят добре с ламбда изрази, въведени в Java 8.

Указания за използване на Java изключения

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

  • Предпочитайте конкретни изключения пред общите изключения. Използвайте | _+_ | над | _+_ | когато е възможно, в противен случай използвайте | _+_ | над | _+_ | когато е възможно.
  • Никога не хващайте | _+_ | ! | _+_ | клас действително разширява | _+_ | , и блокът за улов действително работи с | _+_ | или всеки клас, който разширява Throwable. Въпреки това, | _+_ | клас също разширява | _+_ | , и никога не искате да хванете | _+_ | защото | _+_ | s показват сериозни невъзстановими проблеми.
  • Никога не хващайте | _+_ | ! | _+_ | разширява | _+_ | , така че всеки блок, който улавя | _+_ | също ще хване | _+_ | , и това е много важно изключение, с което не искате да се забърквате (особено в многопоточни приложения), освен ако не знаете какво правите. Ако не знаете кое изключение да хванете вместо това, помислете да не хванете нищо.
  • Използвайте описателни съобщения, за да улесните отстраняването на грешки. Когато хвърляте изключение, можете да предоставите | _+_ | съобщение като аргумент. Това съобщение може да бъде достъпно в блока за улов с помощта на | _+_ | метод, но ако изключението никога не бъде уловено, съобщението също ще се появи като част от трасирането на стека.
  • Опитайте се да не улавяте и пренебрегвате изключенията. За да заобиколят неудобството на проверените изключения, много начинаещи и мързеливи програмисти ще настроят блок за улов, но го оставят празен. Лошо! Винаги се справяйте грациозно, но ако не можете, най -малкото разпечатайте следа от стека, за да знаете, че изключението е хвърлено. Можете да направите това с помощта на | _+_ | метод.
  • Пазете се от прекомерно използване на изключения. Когато имате чук, всичко изглежда като пирон. Когато за първи път научавате за изключения, може да се почувствате длъжни да превърнете всичко в изключение ... до точката, в която по -голямата част от контролния поток на вашето приложение се свежда до обработката на изключения. Не забравяйте, че изключенията са предназначени за „изключителни“ събития!

Сега трябва да сте достатъчно удобни с изключенията, за да разберете какви са те, защо се използват и как да ги включите в собствения си код. Ако не разбирате напълно концепцията, това е добре! Отне ми известно време, докато „щракне“ в главата ми, така че не чувствайте, че трябва да бързате. Отделете време.

Имате ли въпроси? Знаете ли за други съвети, свързани с изключения, които съм пропуснал? Споделете ги в коментарите по -долу!

Дял Дял Туит електронна поща Как да създадете диаграма на потока от данни, за да визуализирате данни от всеки проект

Диаграмите на потока от данни (DFD) на всеки процес ви помагат да разберете как данните протичат от източника до местоназначението. Ето как да го създадете!

Прочетете Напред
Свързани теми
  • Програмиране
  • Java
За автора Джоел Ли(1524 публикувани статии)

Джоел Лий е главен редактор на MakeUseOf от 2018 г. Той има бакалавърска степен по компютърни науки и над девет години професионален опит в писането и редактирането.

проблем с превъртането на мишката нагоре и надолу
Още от Джоел Лий

Абонирайте се за нашия бюлетин

Присъединете се към нашия бюлетин за технически съвети, рецензии, безплатни електронни книги и изключителни оферти!

Щракнете тук, за да се абонирате