User Tools

Site Tools


java:exceptions_try_catch_block

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
java:exceptions_try_catch_block [2020/02/27 20:08] gthanosjava:exceptions_try_catch_block [2021/03/23 07:29] (current) – [Try with resources block] gthanos
Line 30: Line 30:
 Εντός του **try** block βάζουμε τον κώδικα που μπορεί να δημιουργηθεί μια εξαίρεση. Κάθε **catch** block ορίζει ένα διαφορετικό τύπο εξαίρεσης μέσα σε παρένθεση (''ExceptionTypeOne'', ''ExceptionTypeTwo'', κλπ). Εάν η εξαίρεση που παράγεται συμπίπτει __ως προς τον τύπο__ της με ένα αντικείμενο που ορίζεται εντός της παρενθέσεως ενός **catch** block, τότε αυτό το block θα εκτελεστεί. Θα εκτελεστεί επομένως ο κώδικας αντιστοιχεί στον τύπο δεδομένων ο οποίος παράχθηκε από την εκάστοτε εξαίρεση. Εντός του **try** block βάζουμε τον κώδικα που μπορεί να δημιουργηθεί μια εξαίρεση. Κάθε **catch** block ορίζει ένα διαφορετικό τύπο εξαίρεσης μέσα σε παρένθεση (''ExceptionTypeOne'', ''ExceptionTypeTwo'', κλπ). Εάν η εξαίρεση που παράγεται συμπίπτει __ως προς τον τύπο__ της με ένα αντικείμενο που ορίζεται εντός της παρενθέσεως ενός **catch** block, τότε αυτό το block θα εκτελεστεί. Θα εκτελεστεί επομένως ο κώδικας αντιστοιχεί στον τύπο δεδομένων ο οποίος παράχθηκε από την εκάστοτε εξαίρεση.
  
-==== Παράδειγμα 1ο - Διαίρεση με μηδέν (0) ====+==== Παράδειγμα ====
  
-Ας δούμε ένα μικρό τμήμα κώδικα που εντοπίζει ένα είδος εξαίρεσης το οποίο συναντήσαμε και παραπάνω:+Στο προηγούμενο πρόγραμμα ας δούμε ποιοι τύποι εξαιρέσεων προκύπτουν με βάση τη λανθασμένη είσοδο του χρήστη. Στην περίπτωση που ο χρήστης εισάγει γράμματα αντί για ψηφία θα προκύψει μία εξαίρεση του τύπου [[https://docs.oracle.com/javase/7/docs/api/java/util/InputMismatchException.html|InputMismatchException]], ενώ στην περίπτωση που ο χρήστης πατήσει το συνδυασμό πλήκτρων CTRL+D θα προκύψει μία εξαίρεση του τύπου [[https://docs.oracle.com/javase/7/docs/api/java/util/NoSuchElementException.html|NoSuchElementException]]. 
  
-<code java TestDivideByZero.java+Παρατηρήστε επίσης ότι η κλάση [[https://docs.oracle.com/javase/7/docs/api/java/util/InputMismatchException.html|InputMismatchException]] είναι απόγονος της κλάσης [[https://docs.oracle.com/javase/7/docs/api/java/util/NoSuchElementException.html|NoSuchElementException]].
-import java.io.*; +
-import java.util.Scanner; +
-public class TestDivideByZero { +
-  +
-  public static void main (String[args) { +
-    int x, y, result; +
-    while(true) { +
-     +
-      Scanner input = new Scanner(System.in);+
  
-      System.out.print( "Enter first integer: " ); +Παρακάτω δίνεται το προηγούμενο πρόγραμμα εμπλουτισμένο με κώδικα για τη διαχείριση των πιθανών εξαιρέσεων.
-      x = input.nextInt();+
  
-      System.out.print( "Enter second integer: " ); +<code java ExceptionHandling.java> 
-      y = input.nextInt(); +import java.util.Scanner
-       +import java.util.NoSuchElementException
-      try { +import java.util.InputMismatchException;
-          result = x/y; +
-          System.out.printf( "Product is %d\n", result )+
-      } catch (ArithmeticException ae) { +
-          System.out.println("ArithmeticException occured!")+
-          if(y == 0){ +
-            System.out.println("Division by zero in particular"); +
-          } +
-      } +
-    } +
-  } +
-+
-</code>+
  
-Όπως βλέπουμε έχουμε το προηγούμενο παράδειγμα, εμπλουτισμένο όμως με κώδικα διαχείρισης της διαίρεσης με το μηδέν. Ο κώδικας θα αναγνωρίσει ότι δημιουργείται ''ArithmeticException'' και συγκεκριμένα διαίρεση με το μηδέν (0) και θα εκτυπώσει τα σχετικά μηνύματα. +public class ExceptionHandling {
- +
-==== Παράδειγμα 2ο - Ανοίγοντας ένα αρχείο για διάβασμα ==== +
- +
-Παρακάτω δίνεται ένα πιο σύνθετο παράδειγμα μία μεθόδου που διαβάζει ένα αρχείο κειμένου και το επιστρέφει στη μορφή ενός String. +
- +
-<code java WholeFileReader.java> +
-import java.io.*; +
-import java.lang.*; +
- +
-public class WholeFileReader {+
      
-  public String readFile(String path) { +  public static void main(String []args) { 
 +     
 +    Scanner sc = new java.util.Scanner(System.in); 
 +    
     try {     try {
-      /* open file for reading... +      System.out.print("Width: "); 
-       */ +      int width sc.nextInt(); 
-      File file new File (path); +      System.out.print("Height: "); 
-      FileReader fReader = new FileReader(file); +      int height sc.nextInt(); 
-      BufferedReader in new BufferedReader(fReader); +      double ratio width / (double)height
-      String inputLine; +      System.out.format("Ratio: %.2f", ratio); 
-      StringBuffer strDocument new StringBuffer(); +      sc.close(); 
-      /* read file line by line +    catch(InputMismatchException ex) { 
-       */ +      System.out.println("Input doen not match integer value."); 
-      while ((inputLine = in.readLine()) != null) { +    } catch(NoSuchElementException ex{ 
-        strDocument.append(inputLine); +      System.out.println("You have closed the input from command line.");
-      +
-      System.out.println("Closing File!"); +
-      /* close file and return str... +
-       */ +
-      fReader.close(); +
-      return strDocument.toString();+
     }     }
-    /* If file was not found... 
-     */ 
-    catch(FileNotFoundException ex) { 
-      System.out.println("The specified file was not found at "+ path); 
-      return ""; 
-    } 
-    /* If an I/O related exception occures... 
-     */ 
-    catch(IOException ex) { 
-      System.out.println("IOException occured while reading from file "+path); 
-    }     
-    return "Nothing to return.."; 
   }   }
-   
-  public static void main(String args[]) { 
-    WholeFileReader wfr = new WholeFileReader(); 
-    try { 
-      System.out.println(wfr.readFile(args[0]) ); 
-    } 
-    catch(IndexOutOfBoundsException ex) { 
-      System.out.println("No file has been specified from command line!\n"); 
-    } 
-  } 
- 
 } }
 </code> </code>
  
-===== Περισσότερα του ενός catch blocks - Ιεράρχιση της σειράς εμφάνισης τους =====+<WRAP tip 80% center round> 
 +Η σειρά διαχείρισης των εξαιρέσεων έχει σημασία. Εφόσον, δημιουργηθεί μία εξαίρεση, το JVM ελέγχει εάν πρόκειται για εξαίρεση του πρώτου catch block, δηλαδή του τύπου [[https://docs.oracle.com/javase/7/docs/api/java/util/InputMismatchException.html|InputMismatchException]]. Εάν δεν ταιριάζει ο τύπος στο πρώτο catch block θα πάει στο επόμενο, δηλαδή θα ελέγξει εάν είναι εξαίρεση του τύπου [[https://docs.oracle.com/javase/7/docs/api/java/util/NoSuchElementException.html|NoSuchElementException]].
  
-Παρατηρήστε ότι εμφανίζονται δύο **catch** blocks. Το πρώτο catch block αφορά [[http://docs.oracle.com/javase/7/docs/api/java/io/FileNotFoundException.html|FileNotFoundException]] objectsενώ το δεύτερο catch block αφορά [[http://docs.oracle.com/javase/7/docs/api/java/io/IOException.html|ΙΟException]] objects. Από τους συνδέσμους που παρατίθενται θα παρατηρήσετε ότι το ''FileNotFoundException'' είναι υποκλάση του ''IOException'' και δηλώνει ότι το αρχείο δεν βρέθηκε στο filesystem.+Εάν επιχειρήσετε να αντιμεταθέσετε τα δύο catch blocks αυτό που θα συμβεί είναι να λάβετε ένα μήνυμα λάθους από τον μεταγλωττιστή. Ο λόγος είναι ότι επειδή η κλάση InputMismatchException είναι υποκλάση της [[https://docs.oracle.com/javase/7/docs/api/java/util/NoSuchElementException.html|NoSuchElementException]], η αντιστροφή των catch block συνεπάγεται ότι ακόμη και εάν συμβεί μία εξαίρεση του τύπου [[https://docs.oracle.com/javase/7/docs/api/java/util/InputMismatchException.html|InputMismatchException]]το σχετικό catch block δεν θα κληθεί ποτέ. Ο λόγος είναι ότι το πρώτο catch block για τη διαχείριση των εξαιρέσεων του τύπου [[https://docs.oracle.com/javase/7/docs/api/java/util/NoSuchElementException.html|NoSuchElementException]] θα διαχειριστεί και τις εξαιρέσεις του υπο-τύπου [[https://docs.oracle.com/javase/7/docs/api/java/util/InputMismatchException.html|InputMismatchException]]. 
 +</WRAP>
  
-Εάν στον παραπάνω κώδικα παραλείπονταν οι γραμμές: 
  
-<code java> +===== Finaly Block =====
-    catch(FileNotFoundException ex) { +
-      System.out.println("The specified file was not found at "+ path); +
-      return ""; +
-    }    +
-</code>+
  
-Σε αυτή την περίπτωσηο μη εντοπισμός αρχείου θα ενέπιπτε σε ''IOException'' που αποτελεί γονική κλάση της ''FileNotFoundException''. Όταν θα συνέβαινε ένα //ΙΟException// δεν θα γνωρίζαμε εάν υπάρχει το αρχείο αλλά δεν μπορούμε να το διαβάσουμε (//IOException//) ή δεν υπάρχει καθόλου το αρχείο που θέλουμε να διαβάσουμε στο filesystem (//FileNotFoundException//).+Στον παραπάνω κώδικα, εμφανίζεται η κλήση της μεθόδου [[https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#close()|Scanner.close()]] στο τέλος του try block η οποία κλείνει το αντικείμενο τύπου [[https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html|Scanner]].
  
-Επίσηςδεν θα είχε κανένα νόημα να βάλουμε τα δύο παραπάνω catch blocks με ανάποδη σειρά δηλ. +Η κλήση της μεθόδου όμως συμβαίνει μόνο εάν δεν παραχθεί εξαίρεση. Στην περίπτωση που παραχθεί, το αντικείμενο θα παραμείνει ενεργό, πράγμα που σε ένα μεγαλύτερο πρόγραμμα δεν θα ήταν επιθυμητό (στο παρόν πρόγραμμα, το αντικείμενο θα κλείσει αμέσως μετά με την ολοκλήρωση του προγράμματος). Για το σκοπό αυτό εισάγεται η έννοια του finally block, ως ένα block που έπεται των catch blocks και σκοπό έχει να εκτελεστεί σε όλες τις περιπτώσεις, δηλαδή: 
-<code java> +  * Εάν προκύψει η εξαίρεση που έχουμε φροντίσει να διαχειριστούμε (στο παρακάτω παράδειγμα //FileNotFoundException//). 
-    catch(IOException ex) { +  * Εάν προκύψει μια εξαίρεση ενός τύπου που δεν έχουμε φροντίσει να διαχειριστούμε, εντός των υφιστάμενων catch blocks
-      System.out.println("IOException occured while opening file or reading from file "+path); +  * Εάν δεν προκύψει καμία απολύτως εξαίρεση.
-        +
-    catch(FileNotFoundException ex) { +
-      System.out.println("The specified file was not found at "+ path); +
-      return ""; +
-    } +
-</code>+
  
-Σε αυτή την περίπτωσηεάν παραχθεί ένα //Exception// του τύπου ''FileNotFoundException'' θα διαχειριστεί από το πρώτο block που διαχειρίζεται τα ''IOExcetpions''.+Δείτε το προηγούμενο παράδειγμα, αλλαγμένο ώστε να ενσωματώνει ένα **finally** block. Στο παρακάτω πρόγραμμα το αντικείμενο sc θα κλείσει είτε συμβεί εξαίρεση, είτε όχι.
  
-=== Δημιουργία εξαίρεσης ===+<code java ExceptionHandling.java> 
 +import java.util.Scanner; 
 +import java.util.NoSuchElementException; 
 +import java.util.InputMismatchException;
  
-Τέλος, στο παραπάνω παράδειγμα βγάλτε τα σχόλια από την γραμμή ''throw new IOException();'' +public class ExceptionHandling { 
-<code java> +   
-     while ((inputLine in.readLine()) !null) { +  public static void main(String []args) { 
-        strDocument.append(inputLine); +     
-        //throw new IOException(); +    Scanner sc = new java.util.Scanner(System.in); 
-      }+     
 +    try { 
 +      System.out.print("Width: "); 
 +      int width sc.nextInt()
 +      System.out.print("Height: ")
 +      int height sc.nextInt(); 
 +      double ratio = width / (double)height; 
 +      System.out.format("Ratio: %.2f", ratio); 
 +    } catch(InputMismatchException ex) { 
 +      System.out.println("Input doen not match integer value."); 
 +    } catch(NoSuchElementException ex) { 
 +      System.out.println("You have closed the input from command line."); 
 +    } 
 +    finally { 
 +      sc.close(); 
 +    } 
 +  }  
 +}
 </code> </code>
-με στόχο να δημιουργήσετε ένα ''IOException'' και παρατηρήστε από τα μηνύματα που εκτυπώνονται κατά την εκτέλεση του προγράμματος την πορεία του προγράμματος. 
  
-===== Finaly Block =====+===== Try with resources block =====
  
-Εκτός από τα **catch** blocks τα οποία εκτελούνται όταν έχουμε κάποιο exception, μπορούμε να προσθέσουμε ένα **finaly block** το οποίο θα εκτελεστεί __σε κάθε περίπτωση__. Το **finaly block** θα εκτελεστεί στις παρακάτω περιπτώσεις: +Η Java παρέχει τη δυνατότητα για αυτόματo κλείσιμο των αντικειμένων που οι κλάσεις τους υλοποιούν το interface [[https://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html|AutoClosable]]. Οι κλάσεις που υλοποιούν το συγκεκριμένο interface συνδέονται με την διαχείριση πόρων όπως αρχεία, διάβασμα και γράψιμο στην κονσόλα, άνοιγμα υποδοχέων (sockets) ή άλλων πόρων για την επικοινωνία με απομακρυσμένα σημεία.
-  * Εάν προκύψει η εξαίρεση που έχουμε φροντίσει να διαχειριστούμε (στο παρακάτω παράδειγμα //FileNotFoundException//). +
-  * Εάν προκύψει μια εξαίρεση ενός τύπου που δεν έχουμε φροντίσει να διαχειριστούμε. +
-  * Εάν δεν προκύψει καμία απολύτως εξαίρεση.+
  
-Δείτε το παρακάτω παράδειγμα όπου ενσωματώνει ένα **finally** block. +Η κλάση [[https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html|Scanner]] υλοποιεί το συγκεκριμένο interface. Ας δούμε πως διαμορφώνεται ο προηγούμενος κώδικας εκμεταλλευόμενος την επιπλέον δυνατότητα του interface  [[https://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html|AutoClosable]].
-<code java WholeFileReader.java+
-import java.io.*; +
-import java.lang.*;+
  
-public class WholeFileReader { +<code java ExceptionHandling.java> 
-   +import java.util.Scanner; 
-  public String readFile(String path) {+import java.util.NoSuchElementException; 
 +import java.util.InputMismatchException;
  
-  FileReader fReader = null; +public class ExceptionHandling {
-    try { +
-      File file = new File (path); +
-      fReader = new FileReader(file); +
-      BufferedReader in = new BufferedReader(fReader); +
-      String inputLine; +
-      StringBuffer strDocument = new StringBuffer(); +
-      while ((inputLine = in.readLine()) != null) { +
-        strDocument.append(inputLine); +
-        //throw new IOException(); +
-      } +
-      return strDocument.toString(); +
-    } +
-    catch(FileNotFoundException ex) { +
-      System.out.println("The specified file was not found!"); +
-      return ""; +
-    } +
-    catch(IOException ex) { +
-      System.out.println("IOException occured while reading from file "+path); +
-    } +
-    finally { +
-      if(fReader!=null) { +
-        try{ +
-          System.out.println("Closing file!"); +
-          fReader.close(); +
-        } +
-        catch(IOException ex) { +
-          System.out.println("IOException occured while closing file "+path); +
-        } +
-      } +
-      else { +
-        System.out.println("File already closed!"); +
-      } +
-       +
-    } +
-    return ""; +
-  }+
      
-  public static void main(String args[]) { +  public static void main(String []args) { 
-    WholeFileReader wfr = new WholeFileReader(); +     
-    try { +    try (Scanner sc = new java.util.Scanner(System.in)){ 
-      System.out.println(wfr.readFile(args[0]) ); +      System.out.print("Width: "); 
-    } +      int width = sc.nextInt(); 
-    catch(IndexOutOfBoundsException ex) { +      System.out.print("Height: "); 
-      System.out.println("No file has been specified from command line!\n");+      int height = sc.nextInt()
 +      double ratio = width / (double)height; 
 +      System.out.format("Ratio: %.2f", ratio); 
 +    } catch(InputMismatchException ex) { 
 +      System.out.println("Input doen not match integer value."); 
 +    catch(NoSuchElementException ex) { 
 +      System.out.println("You have closed the input from command line.");
     }     }
   }   }
- 
 } }
 </code> </code>
  
-Ο λόγος που συνήθως χρησιμοποιήσουμε το **finally** block είναι για να συμπεριλάβουμε κώδικα που θέλουμε να εκτελεστεί σε όλες τις περιπτώσεις, όπως για παράδειγμα να κλείσουμε ελεγχόμενα τα αρχεία του προγράμματος ή να κλείσουμε δικτυακές συνδέσεις (π.χ. συνδέσεις με βάσεις δεδομένων κ.α.). Στο παραπάνω παράδειγμα παραλλάσσεται η μέθοδος ReadFile του προηγούμενου παραδείγματος, ώστε στο //finally// block η μέθοδος κλείνει το αρχείο που άνοιξε. Η διαφορά σε σχέση με το προηγούμενο παράδειγμα είναι ότι ακόμη και εάν δημιουργηθεί ένα exception την ώρα που διαβάζουμε, η ροή του προγράμματος θα περάσει από το //finally block// και το αρχείο τελικά θα κλείσει. Αυτό δεν ισχύει στο παράδειγμα που δώσαμε προηγούμενα. +Τα αντικείμενα που θέλουμε να κλείσουν αυτόματα τα δημιουργούμε μέσα σε παρενθέσεις, αμέσως μετά το try blockΗ μεταβλητή sc έχει εμβέλεια εντός του try block και όχι έξω από αυτό. Με την ολοκλήρωση του try blockείτε συμβεί εξαίρεση, είτε δεν συμβεί, το αντικείμενο sc (τύπου Scanner) θα κλείσει αυτόματα.
- +
-Στο παραπάνω παράδειγμα δείτε την πορεία του κώδικα βγάζοντας τα σχόλια και βάζοντας σε σχόλια την γραμμή που δημιουργεί το ''IOException''. +
-<code java> +
-      while ((inputLine = in.readLine()) != null) { +
-        strDocument.append(inputLine); +
-        //throw new IOException(); +
-      } +
-</code>+
  
 |Προηγούμενο: [[:java:exceptions_intro| Εξαιρέσεις ]] | [[ :toc | Περιεχόμενα ]] | Επόμενο: [[:java:exceptions_thrown_by_methods | Χειρισμός της εξαίρεσης σε υψηλότερο επίπεδο ]]| |Προηγούμενο: [[:java:exceptions_intro| Εξαιρέσεις ]] | [[ :toc | Περιεχόμενα ]] | Επόμενο: [[:java:exceptions_thrown_by_methods | Χειρισμός της εξαίρεσης σε υψηλότερο επίπεδο ]]|
  
  
java/exceptions_try_catch_block.1582834124.txt.gz · Last modified: 2020/02/27 20:08 by gthanos