JavaRush /Java blogi /Random-UZ /Java-da istisnolar: ushlash va ishlov berish

Java-da istisnolar: ushlash va ishlov berish

Guruhda nashr etilgan
Salom! Men buni sizga sindirishni yomon ko'raman, lekin dasturchi ishining katta qismi xatolar bilan shug'ullanadi. Va ko'pincha - o'zlari bilan. Shunday bo'ladiki, xato qilmaydigan odamlar yo'q. Va bunday dasturlar ham yo'q. Albatta, xato ustida ishlashda asosiy narsa uning sababini tushunishdir. Va dasturda bunday sabablar juda ko'p bo'lishi mumkin. Bir vaqtning o'zida Java yaratuvchilari bir savolga duch kelishdi: dasturlardagi bu juda mumkin bo'lgan xatolar bilan nima qilish kerak? Ulardan butunlay qochish haqiqiy emas. Dasturchilar hatto tasavvur qilib bo'lmaydigan narsalarni yozishlari mumkin :) Bu shuni anglatadiki, tilga xatolar bilan ishlash mexanizmini qurish kerak. Boshqacha qilib aytganda, agar dasturda biron bir xatolik yuz bergan bo'lsa, keyingi ish uchun skript kerak bo'ladi. Xatolik yuz berganda dastur aynan nima qilishi kerak? Bugun biz ushbu mexanizm bilan tanishamiz. Va u "istisnolar " deb ataladi .

Java-da qanday istisno

Istisno - bu dasturning ishlashi paytida yuzaga kelgan ba'zi istisno, rejalashtirilmagan holatlar. Java-da istisnolarga ko'p misollar bo'lishi mumkin. Masalan, siz fayldan matnni o'qiydigan va konsolga birinchi qatorni ko'rsatadigan kod yozdingiz.
public class Main {

   public static void main(String[] args) throws IOException {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   }
}
Ammo bunday fayl mavjud emas! Dasturning natijasi istisno bo'ladi - FileNotFoundException. Xulosa:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
Har bir istisno Java-da alohida sinf bilan ifodalanadi. Barcha istisno sinflar umumiy "ajdod" dan - ota-ona sinfidan keladi Throwable. Istisno sinfining nomi odatda uning paydo bo'lish sababini qisqacha aks ettiradi:
  • FileNotFoundException(Fayl topilmadi)
  • ArithmeticException(matematik amalni bajarishdan istisno)
  • ArrayIndexOutOfBoundsException(massiv yacheykasi soni uning uzunligidan tashqarida ko'rsatilgan). Misol uchun, agar siz 10 uzunlikdagi massiv uchun hujayra massivini [23] ni konsolga chiqarishga harakat qilsangiz.
Java-da 400 ga yaqin bunday sinflar mavjud! Nega shuncha ko'p? Aynan dasturchilarga ular bilan ishlashni qulayroq qilish uchun. Tasavvur qiling: siz dastur yozdingiz va u ishga tushganda, u quyidagicha ko'rinadigan istisnoni chiqaradi:
Exception in thread "main"
Uh-uh :/ Hech narsa aniq emas. Bu qanday xato va qaerdan kelib chiqqanligi noma'lum. Hech qanday foydali ma'lumot yo'q. Ammo bunday xilma-xil sinflar tufayli dasturchi o'zi uchun asosiy narsani - xato turini va sinf nomida mavjud bo'lgan uning ehtimoliy sababini oladi. Axir, konsolda ko'rish mutlaqo boshqacha:
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
Muammo nima bo'lishi mumkinligi va muammoni hal qilish uchun "qaysi yo'nalishda qazish kerakligi" darhol aniq bo'ladi! Istisnolar, sinflarning har qanday misollari kabi, ob'ektlardir.

Qo'lga olish va ishlov berish istisnolari

Java-da istisnolar bilan ishlash uchun maxsus kod bloklari mavjud: try, catchva finally. Istisnolar: ushlash va qayta ishlash - 2Dasturchi istisnolar sodir bo'lishini kutgan kod blokga joylashtiriladi try. Bu, bu joyda istisno albatta sodir bo'ladi degani emas. Bu shuni anglatadiki, u erda sodir bo'lishi mumkin va dasturchi bundan xabardor. Siz qabul qilishni kutayotgan xato turi blokga joylashtiriladi catch(“tutish”). Bu, shuningdek, istisno sodir bo'lganda bajarilishi kerak bo'lgan barcha kodlar joylashtirilgan joy. Mana bir misol:
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");
   }
}
Xulosa:

Ошибка! Файл не найден!
Biz kodimizni ikkita blokga joylashtiramiz. Birinchi blokda "Fayl topilmadi" xatosi paydo bo'lishi mumkinligini kutamiz. Bu blok try. Ikkinchisida, dasturga xatolik yuzaga kelsa, nima qilish kerakligini aytamiz. Bundan tashqari, ma'lum bir xato turi mavjud - FileNotFoundException. Agar biz catchboshqa istisno sinfini blok qavslarga o'tkazsak, u ushlanmaydi.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (ArithmeticException e) {

       System.out.println("Error! File not found!");
   }
}
Xulosa:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
Blokdagi kod catchishlamadi, chunki biz ushbu blokni ushlab turish uchun "sozladik" ArithmeticExceptionva blokdagi kod tryboshqa turdagi - ni chiqarib tashladi FileNotFoundException. Biz skript yozmadik FileNotFoundException, shuning uchun dastur konsolda sukut bo'yicha ko'rsatiladigan ma'lumotlarni ko'rsatdi FileNotFoundException. Bu erda siz 3 narsaga e'tibor berishingiz kerak. Birinchidan. Sinab ko'rish blokidagi kodning istalgan qatorida istisno paydo bo'lishi bilan, undan keyingi kod endi bajarilmaydi. Dasturning bajarilishi darhol blokga "sakrab o'tadi" catch. Masalan:
public static void main(String[] args) {
   try {
       System.out.println("Divide a number by zero");
       System.out.println(366/0);//this line of code will throw an exception

       System.out.println("This");
       System.out.println("code");
       System.out.println("Not");
       System.out.println("will");
       System.out.println("done!");

   } catch (ArithmeticException e) {

       System.out.println("The program jumped to the catch block!");
       System.out.println("Error! You can't divide by zero!");
   }
}
Xulosa:

Делим число на ноль 
Программа перепрыгнула в блок catch! 
Ошибка! Нельзя делить на ноль! 
Ikkinchi qatordagi blokda trybiz raqamni 0 ga bo'lishga harakat qildik, bu istisnoga olib keldi ArithmeticException. Shundan so'ng, blokning 6-10-qatorlari tryendi bajarilmaydi. Aytganimizdek, dastur darhol blokni bajarishni boshladi catch. Ikkinchi. Bir nechta bloklar bo'lishi mumkin catch. Agar blokdagi kod trybitta emas, balki bir nechta istisno turlarini tashlasa, ularning har biri uchun o'z blokingizni yozishingiz mumkin catch.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       System.out.println(366/0);
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");

   } catch (ArithmeticException e) {

       System.out.println("Error! Division by 0!");

   }
}
Ushbu misolda biz ikkita blok yozdik catch. Agar blokda trysodir bo'lsa FileNotFoundException, birinchi blok bajariladi catch. Agar sodir bo'lsa ArithmeticException, ikkinchisi bajariladi. Siz kamida 50 ta blok yozishingiz mumkin catch. Lekin, albatta, 50 xil turdagi xatoliklarni keltirib chiqaradigan kod yozmagan ma'qul :) Uchinchidan. Sizning kodingiz qanday istisnolar keltirishi mumkinligini qanday bilasiz? Albatta, siz ba'zilarini taxmin qilishingiz mumkin, lekin hamma narsani boshingizda ushlab turish mumkin emas. Shuning uchun Java kompilyatori eng keng tarqalgan istisnolar haqida biladi va ular qanday vaziyatlarda yuzaga kelishi mumkinligini biladi. Misol uchun, agar siz kod yozgan bo'lsangiz va kompilyator uning ishlashi davomida 2 turdagi istisnolar paydo bo'lishi mumkinligini bilsa, siz ularni bajarmaguningizcha kodingiz kompilyatsiya qilinmaydi. Buning misollarini quyida ko'rib chiqamiz. Endi istisnolardan foydalanish haqida. Ularni qayta ishlashning 2 usuli mavjud. Biz allaqachon birinchisini uchratdik - usul istisnoni blokda mustaqil ravishda hal qilishi mumkin catch(). Ikkinchi variant ham bor - usul qo'ng'iroqlar to'plamida istisno qilishi mumkin. Bu nima degani? printFirstString()Misol uchun, bizning sinfimizda faylni o'qiydi va konsolga birinchi qatorni ko'rsatadigan bir xil usul mavjud :
public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
Hozirda bizning kodimiz kompilyatsiya qilinmaydi, chunki unda ishlov berilmagan istisnolar mavjud. 1-qatorda siz faylga yo'lni ko'rsatasiz. Kompilyator bunday kod osongina olib kelishi mumkinligini biladi FileNotFoundException. 3-qatorda siz fayldagi matnni o'qiysiz. IOExceptionBu jarayonda kiritish-chiqarish (Kirish-chiqish) paytida xatolik osongina yuzaga kelishi mumkin . Endi kompilyator sizga aytmoqda: “Do‘stim, agar siz ushbu istisnolardan biri yuzaga kelsa, nima qilishim kerakligini aytmaguningizcha, men bu kodni tasdiqlamayman yoki uni kompilyatsiya qilmayman. Va ular, albatta, siz yozgan kod asosida sodir bo'lishi mumkin! ” . Boradigan joy yo'q, ikkalasini ham qayta ishlashingiz kerak! Birinchi ishlov berish opsiyasi bizga allaqachon tanish: kodimizni blokga joylashtirishimiz tryva ikkita blok qo'shishimiz kerak catch:
public static void printFirstString(String filePath) {

   try {
       BufferedReader reader = new BufferedReader(new FileReader(filePath));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error, file not found!");
       e.printStackTrace();
   } catch (IOException e) {
       System.out.println("Error while inputting/outputting data from file!");
       e.printStackTrace();
   }
}
Lekin bu yagona variant emas. Usul ichidagi xato uchun skript yozishdan qochishimiz mumkin va istisnoni yuqoriga tashlashimiz mumkin. throwsBu usul deklaratsiyasida yozilgan kalit so'z yordamida amalga oshiriladi :
public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
So'zdan so'ng, throwsbiz vergul bilan ajratilgan holda, ushbu usul ish paytida tashlashi mumkin bo'lgan barcha turdagi istisnolarni sanab o'tamiz. Bu nima uchun qilinmoqda? Endi, agar dasturdagi kimdir usulni chaqirmoqchi bo'lsa printFirstString(), u istisnolardan foydalanishni o'zi amalga oshirishi kerak bo'ladi. Masalan, dasturning boshqa qismida hamkasblaringizdan biri sizning usulingizni chaqiradigan usulni yozgan printFirstString():
public static void yourColleagueMethod() {

   //...your colleague's method does something

   //...and at one moment calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Eugene\\Desktop\\testFile.txt");
}
Xato, kod kompilyatsiya qilinmadi! Biz usulda printFirstString()xato bilan ishlash skriptini yozmadik . Shuning uchun vazifa bu usuldan foydalanadiganlarning yelkasiga tushadi. Ya'ni, usul yourColleagueMethod()endi bir xil 2 variantga duch keladi: u yoki "uchib ketgan" har ikkala istisnoni yordamida qayta ishlashi try-catchyoki ularni oldinga yo'naltirishi kerak.
public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   //...the method does something

   //...and at one moment calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Eugene\\Desktop\\testFile.txt");
}
Ikkinchi holda, qayta ishlash stekdagi keyingi usulning yelkasiga tushadi - qo'ng'iroq qiladigan yourColleagueMethod(). Shuning uchun bunday mexanizm "istisnoni yuqoriga tashlash" yoki "yuqoriga o'tish" deb ataladi. dan foydalanib istisnolarni tashlaganingizda throws, kod tuziladi. Ayni damda kompilyator: “Yaxshi, mayli. Sizning kodingizda bir qancha potentsial istisnolar mavjud, ammo men uni baribir kompilyatsiya qilaman. Biz bu suhbatga qaytamiz! ” Va dasturning biron bir joyida istisnolardan foydalanmagan usulni chaqirganingizda, kompilyator o'z va'dasini bajaradi va ular haqida yana eslatib turadi. Nihoyat, biz blok haqida gapiramiz finally(so'z o'yinini kechiring). Bu uchlik bilan ishlashning oxirgi qismidir try-catch-finally. Uning o'ziga xosligi shundaki, u har qanday dastur operatsiya stsenariysi bo'yicha bajariladi.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error! File not found!");
       e.printStackTrace();
   } finally {
       System.out.println("And here is the finally block!");
   }
}
Bu misolda blok ichidagi kod finallyikkala holatda ham bajariladi. Agar blokdagi kod tryto'liq bajarilsa va istisno qilmasa, blok oxirida yonadi finally. Agar ichidagi kod tryuzilib qolsa va dastur blokga o'tsa catch, ichidagi kod bajarilgandan so'ng catch, blok hali ham tanlangan bo'ladi finally. Nima uchun kerak? Uning asosiy maqsadi kodning kerakli qismini bajarishdir; holatlardan qat'iy nazar to'ldirilishi kerak bo'lgan qism. Misol uchun, u ko'pincha dastur tomonidan ishlatiladigan ba'zi resurslarni bo'shatadi. Bizning kodimizda biz fayldan ma'lumotni o'qish va uni faylga uzatish uchun oqim ochamiz BufferedReader. Biznikini readeryopish va resurslarni bo'shatish kerak. Bu har qanday holatda ham bajarilishi kerak: dastur kutilganidek ishlaydimi yoki istisno qiladimi, muhim emas. Buni blokda qilish qulay finally:
public static void main(String[] args) throws IOException {

   BufferedReader reader = null;
   try {
       reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } finally {
       System.out.println("And here is the finally block!");
       if (reader != null) {
           reader.close();
       }
   }
}
Endi biz dastur ishlayotgan paytda nima sodir bo'lishidan qat'i nazar, biz egallab olingan resurslarga g'amxo'rlik qilganimizga aminmiz :) Bu istisnolar haqida bilishingiz kerak bo'lgan hamma narsa emas. Xatolarni qayta ishlash dasturlashda juda muhim mavzu: unga bir nechta maqolalar bag'ishlangan. Keyingi darsda biz qanday istisno turlari borligini va o'z istisnolaringizni qanday yaratishni bilib olamiz :) U erda ko'rishguncha!
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION