الخميس، 2 يناير 2020

التعامل مع الاستثناءات في جافا Java Exceptions

التعامل مع الاستثناءات في جافا 

Java  Exceptions

التعامل مع الاستثناءات في جافا Java  Exceptions

الاستثناء (أو الحدث الاستثنائي) هو المشكلة التي تنشأ أثناء تنفيذ البرنامج.  عند حدوث استثناء ، يتم تعطيل التدفق العادي للبرنامج وينتهي البرنامج / التطبيق بشكل غير طبيعي ، وهو أمر غير مستحسن ، لذلك ، يجب معالجة هذه الاستثناءات.

 يمكن أن يحدث استثناء لأسباب عديدة مختلفة.  فيما يلي بعض السيناريوهات التي يحدث فيها استثناء.

 أدخل مستخدم بيانات غير صالحة.

 لا يمكن العثور على ملف يحتاج إلى فتح.

 تم فقد اتصال الشبكة في منتصف الاتصالات أو نفدت ذاكرة JVM.

 بعض هذه الاستثناءات ناتجة عن خطأ المستخدم ، والبعض الآخر بسبب خطأ مبرمج ، والبعض الآخر بسبب الموارد المادية التي فشلت بطريقة ما.

 بناءً على هذه ، لدينا ثلاث فئات من الاستثناءات.  تحتاج إلى فهمهم لمعرفة كيفية عمل الاستثناء في Java.
  • Checked exceptions - الاستثناء المحدد هو استثناء يتم تحديده (إخطار) من قبل المترجم في وقت الترجمة ، وتسمى هذه أيضًا باسم استثناءات وقت الترجمة.  لا يمكن ببساطة تجاهل هذه الاستثناءات ، يجب أن يهتم المبرمج بهذه الاستثناءات.

     على سبيل المثال ، إذا كنت تستخدم فئة FileReader في البرنامج الخاص بك لقراءة البيانات من ملف ، إذا كان الملف المحدد في مُنشئه غير موجود ، عندئذٍ يحدث FileNotFoundException ، ويطالب المحول البرمجي المبرمج بمعالجة الاستثناء.

مثال Example


import java.io.File;
import java.io.FileReader;

public class FilenotFound_Demo {

   public static void main(String args[]) {  
      File file = new File("E://file.txt");
      FileReader fr = new FileReader(file); 
   }
}

إذا حاولت ترجمة البرنامج أعلاه ، فستحصل على الاستثناءات التالية.

المخرجات Output

C:\>javac FilenotFound_Demo.java
FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
      FileReader fr = new FileReader(file);
                      ^
1 error

ملاحظة - نظرًا لأن أساليب read () وإغلاق () فئة FileReader يلقي IOException ، يمكنك ملاحظة أن المحول البرمجي يخطر بمعالجة IOException ، إلى جانب FileNotFoundException.
  • Unchecked exceptions - استثناء لم يتم التحقق منه هو استثناء يحدث في وقت التنفيذ.  وتسمى هذه أيضا وقت التشغيل

     على سبيل المثال ، إذا كنت قد أعلنت عن صفيف بالحجم 5 في البرنامج ، وتحاول استدعاء العنصر السادس للصفيف ، فسيحدث ArrayIndexOutOfBoundsExceptionexception.
  •  Exceptions. وتشمل هذه الأخطاء في البرمجة ، مثل الأخطاء المنطقية أو الاستخدام غير الصحيح لواجهة برمجة التطبيقات.  يتم تجاهل استثناءات وقت التشغيل في وقت الترجمة.

مثال Example


public class Unchecked_Demo {
   
   public static void main(String args[]) {
      int num[] = {1, 2, 3, 4};
      System.out.println(num[5]);
   }
}

إذا قمت بترجمة وتنفيذ البرنامج أعلاه ، فستحصل على الاستثناء التالي.

المخرجات Output

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
 at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
  • Errors الأخطاء − هذه ليست استثناءات على الإطلاق ، ولكنها مشاكل تنشأ خارج سيطرة المستخدم أو المبرمج.  عادة ما يتم تجاهل الأخطاء في التعليمات البرمجية الخاصة بك لأنه نادراً ما يمكنك فعل أي شيء حيال وجود خطأ.  على سبيل المثال ، في حالة حدوث تجاوز سعة مكدس ، سوف يحدث خطأ.  يتم تجاهلها أيضًا في وقت التجميع.

هرمية الاستثناءات Exception Hierarchy

جميع فئات الاستثناء هي أنواع فرعية من فئة java.lang.Exception.  فئة الاستثناء هي فئة فرعية للفئة Throwable.  بخلاف فئة الاستثناء ، توجد فئة فرعية أخرى تسمى Error مشتقة من فئة Throwable.

 الأخطاء هي ظروف غير طبيعية تحدث في حالة الإخفاقات الشديدة ، ولا يتم التعامل معها بواسطة برامج Java.  يتم إنشاء أخطاء للإشارة إلى الأخطاء الناتجة عن بيئة وقت التشغيل.  مثال: JVM نفاد الذاكرة.  عادة ، لا يمكن للبرامج التعافي من الأخطاء.

 تحتوي فئة الاستثناء على فئتين فرعيتين رئيسيتين: فئة IOException و RuntimeException Class.
Exceptions1
فيما يلي قائمة بأكثر استثناءات Java المضمنة والمدققة شيوعًا.

دوال الاستثناءات Exceptions Methods

فيما يلي قائمة بالدوال الهامة المتاحة في الفصل القابل للإلقاء.
الرقم.الدالة والوصف
1
public String getMessage()
إرجاع رسالة مفصلة حول الاستثناء الذي حدث.  تتم تهيئة هذه الرسالة في مُنشئ Throwable.
2
public Throwable getCause()
تُرجع سبب الاستثناء كما يمثله كائن Throwable.
3
public String toString()
تُرجع اسم الفئة متصلاً بنتيجة getMessage ().
4
public void printStackTrace()
يطبع نتيجة toString () مع تتبع المكدس إلى System.err ، دفق إخراج الخطأ.
5
public StackTraceElement [] getStackTrace()
إرجاع مصفوفة يحتوي على كل عنصر في تتبع المكدس.  يمثل العنصر في الفهرس 0 الجزء العلوي من مكدس الاستدعاءات ، ويمثل العنصر الأخير في المصفوفة الطريقة الموجودة أسفل مكدس الاستدعاءات.
6
public Throwable fillInStackTrace()
تعبئة تتبع المكدس لهذا الكائن القابل للإزالة مع تتبع المكدس الحالي ، إضافة إلى أي معلومات سابقة في تتبع المكدس.

استثناءات الاقتناث Catching Exceptions

دالة  الاقتناث  استثناء باستخدام مزيج من الكلمات الأساسية للمحاولة والتقاط.  يتم وضع كتلة try / catch حول الكود الذي قد ينشئ استثناءً.  يشار إلى الكود الموجود داخل كتلة try / catch بالرمز المحمي ، ويبدو بناء جملة استخدام try / catch كما يلي -

الصيغة Syntax

try {
   // Protected code
} catch (ExceptionName e1) {
   // Catch block
}
يتم وضع الكود الذي هو عرضة للاستثناءات في كتلة المحاولة.  عند حدوث استثناء ، تتم معالجة هذا الاستثناء بواسطة كتلة catch المرتبطة به.  يجب أن يتبع كل كتلة محاولة على الفور إما كتلة catch أو كتلة أخيرا.

 يتضمن بيان catch إعلان نوع الاستثناء الذي تحاول التقاطه.  في حالة حدوث استثناء في التعليمات البرمجية المحمية ، يتم فحص كتلة catch (أو الكتل) التي تتبع المحاولة.  إذا تم سرد نوع الاستثناء الذي حدث في كتلة catch ، يتم تمرير الاستثناء إلى كتلة catch كما يتم تمرير وسيطة في معلمة أسلوب.

مثال Example

ما يلي هو مجموعة أعلن مع عنصرين.  ثم يحاول الرمز الوصول إلى العنصر الثالث للصفيف الذي يلقي استثناء.

// File Name : ExcepTest.java
import java.io.*;

public class ExcepTest {

   public static void main(String args[]) {
      try {
         int a[] = new int[2];
         System.out.println("Access element three :" + a[3]);
      } catch (ArrayIndexOutOfBoundsException e) {
         System.out.println("Exception thrown  :" + e);
      }
      System.out.println("Out of the block");
   }
}

المخرجات Output

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block

كتل عديدة باستخدام الاقتناث Multiple Catch Blocks

يمكن أن يتبع كتلة المحاولة كتل الاقتناص  متعددة.  يبدو بناء جملة كتل الاقتناص المتعددة كما يلي -

الصيغة Syntax

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}

توضح العبارات السابقة ثلاث مجموعات من مقاطع الالتقاط ، ولكن يمكنك الحصول على أي عدد منها بعد تجربة واحدة.  في حالة حدوث استثناء في التعليمات البرمجية المحمية ، يتم طرح الاستثناء على كتلة catch الأولى في القائمة.  إذا كان نوع بيانات الاستثناء يطابق ExceptionType1 ، فسيتم اكتشافه هناك.  إذا لم يكن كذلك ، ينتقل الاستثناء إلى العبارة catch الثانية.  يستمر هذا الأمر حتى يتم الاستثناء أو الوقوع في جميع عمليات الصيد ، وفي هذه الحالة تتوقف الطريقة الحالية عن التنفيذ ويتم طرح الاستثناء وصولاً إلى الطريقة السابقة في مكدس الاستدعاءات.

مثال Example

فيما يلي مقطع التعليمات البرمجية الذي يوضح كيفية استخدام عبارات try / catch متعددة.
try {
   file = new FileInputStream(fileName);
   x = (byte) file.read();
} catch (IOException i) {
   i.printStackTrace();
   return -1;
} catch (FileNotFoundException f) // Not valid! {
   f.printStackTrace();
   return -1;
}

اقتناص العديد من الاستثناءات Catching Multiple Type of Exceptions

نظرًا لأن Java 7 ، يمكنك معالجة أكثر من استثناء باستخدام كتلة catch واحدة ، تعمل هذه الميزة على تبسيط التعليمات البرمجية.  إليك كيف ستفعل ذلك -
catch (IOException|FileNotFoundException ex) {
   logger.log(ex);
   throw ex;


جملة الرمي The Throws/Throw Keywords

إذا لم تعالج الطريقة استثناء محددًا ، فيجب أن تقوم الطريقة بتعريفه باستخدام الكلمة الأساسية لرميات.  تظهر الكلمة الأساسية للرميات في نهاية توقيع الطريقة.

 يمكنك رمي استثناء ، إما واحد تم إنشاء مثيل له حديثًا أو استثناء اشتعلت للتو ، باستخدام كلمة "رمي" الأساسية.

 حاول أن تفهم الفرق بين الرميات ورمي الكلمات الرئيسية ، وتستخدم الرميات لتأجيل معالجة الاستثناء المحدد والرمي يستخدم لاستدعاء استثناء صراحة.

 تعلن الطريقة التالية أنه يلقي RemoteException -

مثال Example

import java.io.*;
public class className {

   public void deposit(double amount) throws RemoteException {
      // Method implementation
      throw new RemoteException();
   }
   // Remainder of class definition
}

يمكن أن تعلن إحدى الطرق أنها تطرح أكثر من استثناء ، وفي هذه الحالة يتم الإعلان عن الاستثناءات في قائمة مفصولة بفواصل.  على سبيل المثال ، تعلن الطريقة التالية أنها تطرح RemoteException و InsufficientFundsException -

مثال Example

import java.io.*;
public class className {

   public void withdraw(double amount) throws RemoteException, 
      InsufficientFundsException {
      // Method implementation
   }
   // Remainder of class definition
}

استخدام إطالة الإنهاء The Finally Block

أخيرًا ، يتبع الكتل كتلة try أو كتلة catch.  يتم تنفيذ كتلة أخيرة من التعليمات البرمجية دائمًا ، بغض النظر عن حدوث استثناء.

 يتيح لك استخدام كتلة أخيرة تشغيل أية عبارات من نوع التنظيف تريد تنفيذها ، بغض النظر عما يحدث في التعليمات البرمجية المحمية.

 تظهر كتلة أخيرة في نهاية كتل الالتقاط وتحتوي على بناء الجملة التالي -

الصيغة العامة Syntax

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}finally {
   // The finally block always executes.
}

مثال Example


public class ExcepTest {

   public static void main(String args[]) {
      int a[] = new int[2];
      try {
         System.out.println("Access element three :" + a[3]);
      } catch (ArrayIndexOutOfBoundsException e) {
         System.out.println("Exception thrown  :" + e);
      }finally {
         a[0] = 6;
         System.out.println("First element value: " + a[0]);
         System.out.println("The finally statement is executed");
      }
   }
}

المخرجات Output

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed
لاحظ ما يلي -

 لا يمكن العثور على جملة catch بدون عبارة try.

 ليس من الضروري أن يكون لديك جمل أخيرًا عند وجود كتلة try / catch.

 لا يمكن أن تكون كتلة المحاولة موجودة بدون جملة catch أو جملة أخيرة.

 لا يمكن أن يكون هناك أي كود بين المحاولة ، catch ، أخيرًا الكتل.

الموارد باستخدام جملة المحاولة The try-with-resources

بشكل عام ، عندما نستخدم أي موارد مثل التدفقات ، الاتصالات ، إلخ ، يتعين علينا إغلاقها بشكل صريح باستخدام حظر أخيرًا.  في البرنامج التالي ، نقرأ البيانات من ملف باستخدام FileReader ونقوم بإغلاقها باستخدام كتلة أخيرة.

مثال Example

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class ReadData_Demo {

   public static void main(String args[]) {
      FileReader fr = null;  
      try {
         File file = new File("file.txt");
         fr = new FileReader(file); char [] a = new char[50];
         fr.read(a);   // reads the content to the array
         for(char c : a)
         System.out.print(c);   // prints the characters one by one
      } catch (IOException e) {
         e.printStackTrace();
      }finally {
         try {
            fr.close();
         } catch (IOException ex) {  
            ex.printStackTrace();
         }
      }
   }
}

تُعد try-with-resources ، والتي يشار إليها أيضًا باسم الإدارة التلقائية للموارد ، آلية جديدة لمعالجة الاستثناءات تم تقديمها في Java 7 ، والتي تقوم تلقائيًا بإغلاق الموارد المستخدمة في كتلة try catch.

 لاستخدام هذا البيان ، تحتاج ببساطة إلى الإعلان عن الموارد المطلوبة داخل الأقواس ، وسيتم إغلاق المورد الذي تم إنشاؤه تلقائيًا في نهاية الكتلة.  فيما يلي صيغة جملة try-with-resources.

الصيغة العامة Syntax

try(FileReader fr = new FileReader("file path")) {
   // use the resource
   } catch () {
      // body of catch 
   }
}
فيما يلي البرنامج الذي يقرأ البيانات في ملف باستخدام عبارة try-with-resources.

مثال Example

import java.io.FileReader;
import java.io.IOException;

public class Try_withDemo {

   public static void main(String args[]) {
      try(FileReader fr = new FileReader("E://file.txt")) {
         char [] a = new char[50];
         fr.read(a);   // reads the contentto the array
         for(char c : a)
         System.out.print(c);   // prints the characters one by one
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}
يجب مراعاة النقاط التالية أثناء العمل باستخدام عبارة try-with-resources.

 لاستخدام فئة مع عبارة try-with-resources ، يجب تطبيق واجهة AutoCloseable وسيتم استدعاء طريقة close () منه تلقائيًا في وقت التشغيل.

 يمكنك التصريح عن أكثر من فئة في بيان try-with-resources.

 بينما تقوم بتعريف فئات متعددة في كتلة try الخاصة ببيان try-with-resources ، يتم إغلاق هذه الفئات بترتيب عكسي.

 ما عدا إعلان الموارد داخل الأقواس ، كل شيء هو نفسه مثل كتلة try / catch العادية في كتلة try.

 يتم إنشاء مثيل المورد المُعلن في المحاولة قبل بدء كتلة المحاولة.

 يتم تعريف المورد المعلنة في كتلة المحاولة ضمنيًا على أنها نهائية.

استثناءات مبرمجة من قبل المستخدم User-defined Exceptions

يمكنك إنشاء استثناءات خاصة بك في Java.  ضع النقاط التالية في الاعتبار عند كتابة فصول الاستثناء الخاصة بك -

 يجب أن تكون جميع الاستثناءات طفلًا قابلًا للرمي.

 إذا كنت تريد كتابة استثناء محدد يتم تطبيقه تلقائيًا بواسطة قاعدة التعامل أو إلغاء الإعلان ، فأنت بحاجة إلى تمديد فئة الاستثناء.

 إذا كنت ترغب في كتابة استثناء وقت التشغيل ، فأنت بحاجة إلى توسيع فئة RuntimeException.

 يمكننا تحديد فئة الاستثناء الخاصة بنا على النحو التالي -
class MyException extends Exception {
}

تحتاج فقط إلى توسيع فئة الاستثناء المحددة مسبقًا لإنشاء الاستثناء الخاص بك.  وتعتبر هذه لتكون التحقق من الاستثناءات.  فئة InsufficientFundsException التالية هي استثناء المعرفة من قبل المستخدم الذي يمتد فئة استثناء ، مما يجعله استثناء محددًا.  تشبه فئة الاستثناء أي فئة أخرى ، تحتوي على حقول وأساليب مفيدة.

مثال Example

// File Name InsufficientFundsException.java
import java.io.*;

public class InsufficientFundsException extends Exception {
   private double amount;
   
   public InsufficientFundsException(double amount) {
      this.amount = amount;
   }
   
   public double getAmount() {
      return amount;
   }
}

للتدليل باستخدام الاستثناء المعرف من قبل المستخدم ، تحتوي فئة CheckingAccount التالية على طريقة السحب () التي تطرح InsufficientFundsException.
// File Name CheckingAccount.java
import java.io.*;

public class CheckingAccount {
   private double balance;
   private int number;
   
   public CheckingAccount(int number) {
      this.number = number;
   }
   
   public void deposit(double amount) {
      balance += amount;
   }
   
   public void withdraw(double amount) throws InsufficientFundsException {
      if(amount <= balance) {
         balance -= amount;
      }else {
         double needs = amount - balance;
         throw new InsufficientFundsException(needs);
      }
   }
   
   public double getBalance() {
      return balance;
   }
   
   public int getNumber() {
      return number;
   }
}

يوضح برنامج BankDemo التالي استدعاء طرق الإيداع () والسحب () من CheckingAccount.
// File Name BankDemo.java
public class BankDemo {

   public static void main(String [] args) {
      CheckingAccount c = new CheckingAccount(101);
      System.out.println("Depositing $500...");
      c.deposit(500.00);
      
      try {
         System.out.println("\nWithdrawing $100...");
         c.withdraw(100.00);
         System.out.println("\nWithdrawing $600...");
         c.withdraw(600.00);
      } catch (InsufficientFundsException e) {
         System.out.println("Sorry, but you are short $" + e.getAmount());
         e.printStackTrace();
      }
   }
}

ترجمة جميع الملفات الثلاثة المذكورة أعلاه وتشغيل BankDemo.  هذا سوف ينتج النتيجة التالية -

المخرجات Output

Depositing $500...

Withdrawing $100...

Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsException
         at CheckingAccount.withdraw(CheckingAccount.java:25)
         at BankDemo.main(BankDemo.java:13)

الاسثناءات الشائعة Common Exceptions

في Java ، من الممكن تحديد فئتين من الاستثناءات والأخطاء.
  • JVM Exceptions − هذه استثناءات / أخطاء يتم طرحها بشكل حصري أو منطقي بواسطة JVM.  أمثلة: NullPointerException و ArrayIndexOutOfBoundsException و ClassCastException.
  • Programmatic Exceptions −يتم طرح هذه الاستثناءات بشكل صريح بواسطة التطبيق أو مبرمجي API.  أمثلة: IllegalArgumentException و IllegalStateException. 


التسميات: