java:exceptions_intro

Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Next revision Both sides next revision
java:exceptions_intro [2015/03/03 06:46]
gthanos [Exception Handler]
java:exceptions_intro [2015/03/03 07:33]
gthanos [Χειρισμός της εξαίρεσης σε υψηλότερο επίπεδο]
Line 127: Line 127:
       while ((inputLine = in.readLine()) != null) {       while ((inputLine = in.readLine()) != null) {
         strDocument.append(inputLine);​         strDocument.append(inputLine);​
 +        //throw new IOException();​
       }       }
 +      System.out.println("​Closing File!"​);​
       fReader.close();​       fReader.close();​
       return strDocument.toString();​       return strDocument.toString();​
Line 136: Line 138:
     }        }   
     catch(IOException ex) {     catch(IOException ex) {
-      System.out.println("​IOException occured while opening file or reading from file "+path); +      System.out.println("​IOException occured while reading from file "​+path);​
-      System.out.println("​Exiting..."​);​ +
-      System.exit(1);+
     }    ​     }    ​
-    return "";​+    return "Nothing to return..";
   }   }
   ​   ​
Line 153: Line 153:
   }   }
  
-}</​code>​+} 
 +</​code>​
  
 Παρατηρήστε ότι εμφανίζονται δύο **catch** blocks. Το πρώτο catch block αφορά [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​io/​IOException.html|ΙΟException]] objects, ενώ το δεύτερο catch block αφορά [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​io/​FileNotFoundException.html|FileNotFoundException]] objects. Από τους συνδέσμους που παρατίθενται θα παρατηρήσετε ότι το ''​FileNotFoundException''​ είναι υποκλάση του ''​IOException''​. Ο παραπάνω κώδικας θα μπορούσε να παραλείπει τις γραμμές Παρατηρήστε ότι εμφανίζονται δύο **catch** blocks. Το πρώτο catch block αφορά [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​io/​IOException.html|ΙΟException]] objects, ενώ το δεύτερο catch block αφορά [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​io/​FileNotFoundException.html|FileNotFoundException]] objects. Από τους συνδέσμους που παρατίθενται θα παρατηρήσετε ότι το ''​FileNotFoundException''​ είναι υποκλάση του ''​IOException''​. Ο παραπάνω κώδικας θα μπορούσε να παραλείπει τις γραμμές
Line 164: Line 165:
 </​code>​ </​code>​
  
-καθώς ο μη εντόπισμός αρχείου θα ενέπιπτε σε ''​IOException''​ που είναι η γονική κλάση. Σε αυτή την περίπτωση όμως όταν θα συνέβαινε ​το exception ​δεν θα γνωρίζαμε εάν υπάρχει το αρχείο αλλά δεν μπορούμε να το διαβάσουμε ή δεν υπάρχει καθόλου το αρχείο που θέλουμε να διαβάσουμε στο filesystem. Επίσης,​ δεν θα είχε κανένα νόημα να βάλουμε τα catch blocks με ανάποδη σειρά δηλ.+καθώς ο μη εντόπισμός αρχείου θα ενέπιπτε σε ''​IOException''​ που είναι η γονική κλάση ​του ''​FileNotFoundException''​. Σε αυτή την περίπτωση όμως όταν θα συνέβαινε ​κάποιο Exception ​δεν θα γνωρίζαμε εάν υπάρχει το αρχείο αλλά δεν μπορούμε να το διαβάσουμε ή δεν υπάρχει καθόλου το αρχείο που θέλουμε να διαβάσουμε στο filesystem. ​ 
 + 
 +Επίσης,​ δεν θα είχε κανένα νόημα να βάλουμε τα catch blocks με ανάποδη σειρά δηλ.
 <code java> <code java>
     catch(IOException ex) {     catch(IOException ex) {
       System.out.println("​IOException occured while opening file or reading from file "​+path);​       System.out.println("​IOException occured while opening file or reading from file "​+path);​
-      System.out.println("​Exiting..."​);​ 
-      System.exit(1);​ 
     }    ​     }    ​
     catch(FileNotFoundException ex) {     catch(FileNotFoundException ex) {
Line 177: Line 178:
 </​code>​ </​code>​
 Σε αυτή την περίπτωση,​ ακόμη και ένα Exception του τύπου ''​FileNotFoundException''​ θα διαχειριστεί από το πρώτο block που διαχειρίζεται τα ''​IOExcetpions''​. Σε αυτή την περίπτωση,​ ακόμη και ένα Exception του τύπου ''​FileNotFoundException''​ θα διαχειριστεί από το πρώτο block που διαχειρίζεται τα ''​IOExcetpions''​.
 +
 +Τέλος, στο παραπάνω παράδειγμα βγάλτε τα σχόλια από την γραμμή ''​throw new IOException();''​
 +<code java>
 +     while ((inputLine = in.readLine()) != null) {
 +        strDocument.append(inputLine);​
 +        //throw new IOException();​
 +      }
 +</​code>​
 +για να δημιουργήσετε ένα ''​IOException''​ και παρατηρήστε την πορεία του κώδικα.
  
 ==== Finaly Block ==== ==== Finaly Block ====
Line 193: Line 203:
   ​   ​
   public String readFile(String path) {   public String readFile(String path) {
-    ​FileReader fReader = null; + 
-  ​+  ​FileReader fReader = null;
     try {     try {
       File file = new File (path);       File file = new File (path);
Line 201: Line 211:
       String inputLine;       String inputLine;
       StringBuffer strDocument = new StringBuffer();​       StringBuffer strDocument = new StringBuffer();​
-      ​try { +      while ((inputLine = in.readLine()) != null) { 
-        ​while ((inputLine = in.readLine()) != null) { +        strDocument.append(inputLine);​ 
-          strDocument.append(inputLine);​ +        ​//throw new IOException();​
-        ​+
-        ​+
       }       }
-      ​catch(IOException ex) { +      ​fReader.close();
-        System.out.println("​IOException occured while reading from file "​+path);​ +
-        System.out.println("​Exiting..."​);​ +
-        System.exit(1); +
-      }      ​+
       return strDocument.toString();​       return strDocument.toString();​
     }     }
     catch(FileNotFoundException ex) {     catch(FileNotFoundException ex) {
-      System.out.println("​The specified file was not found at "+ path);+      System.out.println("​The specified file was not found!");
       return "";​       return "";​
 +    }
 +    catch(IOException ex) {
 +      System.out.println("​IOException occured while reading from file "​+path);​
     }     }
     finally {     finally {
-      if( fReader != null) { +      if(fReader!=null) { 
-        try { +        try{ 
-          System.out.println("​Closing file"​);​+          System.out.println("​Closing file!");
           fReader.close();​           fReader.close();​
-        } +        }
         catch(IOException ex) {         catch(IOException ex) {
-          System.out.println("​IOException occured while reading from file "+path); +          System.out.println("​IOException occured while closing ​file "​+path);​
-          System.out.println("​Exiting..."​);​ +
-          System.exit(1);+
         }         }
       }       }
 +      else {
 +        System.out.println("​File already closed!"​);​
 +      }
 +      ​
     }     }
-    ​+    ​return "";​
   }   }
   ​   ​
Line 240: Line 249:
     }     }
     catch(IndexOutOfBoundsException ex) {     catch(IndexOutOfBoundsException ex) {
-      System.out.println("​No file has been specified!\n"​);​+      System.out.println("​No file has been specified ​from command line!\n");
     }     }
   }   }
Line 248: Line 257:
  
 Ο λόγος που συνήθως χρησιμοποιήσουμε το **finally** block είναι για να συμπεριλάβουμε κώδικα που θέλουμε να εκτελεστεί σε όλες τις περιπτώσεις,​ όπως για παράδειγμα να κλείσουμε ελεγχόμενα τα αρχεία του προγράμματος ή να κλείσουμε δικτυακές συνδέσεις (π.χ. συνδέσεις με βάσεις δεδομένων κ.α.). Στο παραπάνω παράδειγμα παραλλάσσεται η μέθοδος ReadFile του προηγούμενου παραδείγματος,​ ώστε στο //finally// block η μέθοδος κλείνει το αρχείο που άνοιξε. Η διαφορά σε σχέση με την προηγούμενη μέθοδο είναι ότι ακόμη και εάν δημιουργηθεί ένα exception την ώρα που διαβάζουμε η ροή του προγράμματος θα περάσει από το finally block και το αρχείο θα κλείσει. Αυτό δεν ισχύει στο παράδειγμα που δώσαμε προηγούμενα. Ο λόγος που συνήθως χρησιμοποιήσουμε το **finally** block είναι για να συμπεριλάβουμε κώδικα που θέλουμε να εκτελεστεί σε όλες τις περιπτώσεις,​ όπως για παράδειγμα να κλείσουμε ελεγχόμενα τα αρχεία του προγράμματος ή να κλείσουμε δικτυακές συνδέσεις (π.χ. συνδέσεις με βάσεις δεδομένων κ.α.). Στο παραπάνω παράδειγμα παραλλάσσεται η μέθοδος ReadFile του προηγούμενου παραδείγματος,​ ώστε στο //finally// block η μέθοδος κλείνει το αρχείο που άνοιξε. Η διαφορά σε σχέση με την προηγούμενη μέθοδο είναι ότι ακόμη και εάν δημιουργηθεί ένα exception την ώρα που διαβάζουμε η ροή του προγράμματος θα περάσει από το finally block και το αρχείο θα κλείσει. Αυτό δεν ισχύει στο παράδειγμα που δώσαμε προηγούμενα.
 +
 +Στο παραπάνω παράδειγμα δείτε την πορεία του κώδικα βγάζοντας τα σχόλια και βάζοντας σε σχόλια την γραμμή που δημιουργεί το ''​IOException''​.
 +<code java>
 +      while ((inputLine = in.readLine()) != null) {
 +        strDocument.append(inputLine);​
 +        //throw new IOException();​
 +      }
 +</​code>​
 ====== Χειρισμός της εξαίρεσης σε υψηλότερο επίπεδο ====== ====== Χειρισμός της εξαίρεσης σε υψηλότερο επίπεδο ======
  
 Στην προηγούμενη ενότητα δείξαμε πως μπορούμε να χειριστούμε μια εξαίρεση όταν προκύπτει. Η Java μας δίνει την δυνατότητα να μην διαχειριστούμε την εξαίρεση μέσα στην μέθοδο που προκύπτει,​ αλλά να σε κάποια άλλη μέθοδο πιο πάνω που καλεί την μέθοδο που προκύπτει. Ας ξαναδούμε το προηγούμενο παράδειγμα ελαφρά παραλλαγμένο. ​ Στην προηγούμενη ενότητα δείξαμε πως μπορούμε να χειριστούμε μια εξαίρεση όταν προκύπτει. Η Java μας δίνει την δυνατότητα να μην διαχειριστούμε την εξαίρεση μέσα στην μέθοδο που προκύπτει,​ αλλά να σε κάποια άλλη μέθοδο πιο πάνω που καλεί την μέθοδο που προκύπτει. Ας ξαναδούμε το προηγούμενο παράδειγμα ελαφρά παραλλαγμένο. ​
  
-Σε προηγούμενο παράδειγμα αναφερθήκαμε ​στη PrintWriter class και βάλαμε ένα ​try-catch block για να διαχειριστούμε τη πιθανή δημιουργία μας εξαίρεσης+  - Κατ'​ αρχήν διαχωρίζουμε το ''​FileNotFoundException''​ από to ''​IOException''​ σε δύο ​διαφορετικά try blocks. 
 +  - Στην συνέχεια κάνουμε comment-out ​τις γραμμές που ​ελέγχουν το ''​FileNotFoundException''​ και αντ' ​αυτού προσθέτουμε μία δήλωση ''​throws FileNotFoundException''​ στην δήλωση της ​μεθόδου
 +  - Τέλος διαχειριζόμαστε την ​εξαίρεση ​μέσα στη μέθοδο ''​main''​.
  
 <code java> <code java>
Line 283: Line 302:
       return strDocument.toString();​       return strDocument.toString();​
     }     }
-    ​+    ​/* //Remove exception from here. Handle it at a higher level 
 +    catch(FileNotFoundException ex) { 
 +      System.out.println("​The specified file was not found at "+ args[0]); 
 +    }*/
     finally {     finally {
       if( fReader != null) {       if( fReader != null) {
Line 316: Line 338:
 </​code>​ </​code>​
  
-Στον παραπάνω κώδικα βλέπουμε την περίπτωση στην οποία δεν διαχειριζόμαστε την εξαίρεση εντός της μεθόδου ''​readFile''​ αλλά αφήνουμε να περνάμε την εξαίρεση στην μέθοδο που την καλεί (στην περίπτωση μας η main) και την διαχειριζόμαστε εκεί. ​Παρατηρήστε ότι εφόσον δεν διαχειριζόμαστε το Exception στην δήλωση της μεθόδου υπάρχει η επιπλέον δήλωση ''​throws FileNotFoundException'',​ όπου περιγράφεται ποιά Exceptions μπορεί να "​πετάξει"​ η μέθοδος στις μεθόδους που την καλού. Μία μέθοδος μπορεί να κάνει throw περισσότερα του ενός Exceptions.+Στον παραπάνω κώδικα βλέπουμε την περίπτωση στην οποία ​__δεν__ διαχειριζόμαστε την εξαίρεση εντός της μεθόδου ''​readFile''​ αλλά αφήνουμε να περνάμε την εξαίρεση στην μέθοδο που την καλεί (στην περίπτωση μας η ''​main''​) και την διαχειριζόμαστε εκεί. ​Eφόσον δεν διαχειριζόμαστε το Exception στην δήλωση της μεθόδου υπάρχει η επιπλέον δήλωση ''​throws FileNotFoundException'',​ όπου περιγράφεται ποια Exceptions μπορεί να "​πετάξει"​ η κάθε ​μέθοδος στις μεθόδους που την καλούν. Μία μέθοδος μπορεί να κάνει ​**throw** περισσότερα του ενός Exceptions. Η δήλωση throw υποχρεώνει τον compiler να βγάλει error  
 +  * εάν δεν διαχειριστούμε το Exception στην μέθοδο από την οποία καλούμε την μέθοδο με την δήλωση **throw**. 
 +  * ή εάν δεν έχουμε μία δήλωση **throw** στην μέθοδο από την οποία καλούμε την εν λόγω μέθοδο.
  
 ====== Πυροδότηση μιας εξαίρεσης ====== ====== Πυροδότηση μιας εξαίρεσης ======
-Στις προηγούμενες ενότητες είδαμε τον τρόπο με τον οποίο χειριζόμαστε μια εξαίρεση. Μέχρι αυτό το σημείο έχουμε αναφερθεί σε εξαιρέσεις που παρέχονται απο κλάσεις του συστήματος. Πως όμως δημιουργούνται αυτές οι εξαιρέσεις και πως και εμείς μπορούμε να καλέσουμε μια εξαίρεση;​ +Στις προηγούμενες ενότητες είδαμε τον τρόπο με τον οποίο χειριζόμαστε μια εξαίρεση. Μέχρι αυτό το σημείο έχουμε αναφερθεί σε εξαιρέσεις που παρέχονται από κλάσεις του συστήματος. Πως όμως δημιουργούνται αυτές οι εξαιρέσεις και πως και εμείς μπορούμε να καλέσουμε μια εξαίρεση;​
- +
-Οπως τονίσαμε και παραπάνω η εξαίρεση είναι και αυτή ένα αντικείμενο. Για να καλέσουμε ένα αντικείμενο εξαίρεσης το μόνο που έχουμε να κάνουμε είναι να βάλουμε τη δεσμευμένη λέξη **throw** και δίπλα το αντικείμενο της εξαίρεσης που θέλουμε να καλέσουμε. +
- +
-<code java> +
-public Object pop() { +
-    Object obj; +
- +
-    if (size == 0) { +
-        throw new EmptyStackException();​ +
-    } +
- +
-    obj = objectAt(size - 1); +
-    setObjectAt(size - 1, null); +
-    size--; +
-    return obj; +
-+
-</​code>​  +
- +
-Στο παραπάνω παράδειγμα έχουμε δημιουργήσει μια μέθοδο η οποία βγάζει ένα αντικείμενο απο μια stack και το επιστρέφει. Θέλουμε σε περίπτωση που δεν υπάρχει κάποιο αντικείμενο στη stack και καλέσουμε pop να πυροδοτηθεί μια εξαίρεση. ​+
  
 Επανερχόμενοι στο παράδειγμα ανάγνωσης ενός αρχείου ας υποθέσουμε ότι θέλουμε να δημιουργούμε μία εξαίρεση αν το αρχείο είναι άδειο, δηλ δεν περιέχει κανένα χαρακτήρα. Για τον σκοπό αυτό δημιουργούμε ένα νέο τύπο εξαίρεσης με όνομα ''​EmptyFileException''​. ​ Επανερχόμενοι στο παράδειγμα ανάγνωσης ενός αρχείου ας υποθέσουμε ότι θέλουμε να δημιουργούμε μία εξαίρεση αν το αρχείο είναι άδειο, δηλ δεν περιέχει κανένα χαρακτήρα. Για τον σκοπό αυτό δημιουργούμε ένα νέο τύπο εξαίρεσης με όνομα ''​EmptyFileException''​. ​
Line 347: Line 352:
 </​code>​ </​code>​
  
-Στην συνέχεια εάν μετά την ολοκλήρωση διαβάσματος του αρχείου αντιληφθούμε ότι το αρχείο που διαβάσαμε ήταν κενό τότε το πρόγραμμα μας ​πετάει το παραπάνω Exception. Δείτε τον κώδικα.+Όπως ​τονίσαμε και παραπάνω ​η εξαίρεση είναι και αυτή ένα αντικείμενο. Για να καλέσουμε ένα αντικείμενο εξαίρεσης το μόνο που ​έχουμε να κάνουμε είναι να βάλουμε τη δεσμευμένη λέξη **throw** και δίπλα το αντικείμενο της εξαίρεσης που θέλουμε να καλέσουμε. Στο παρακάτω παράδειγμαεάν μετά την ολοκλήρωση διαβάσματος του αρχείου αντιληφθούμε ότι το αρχείο που διαβάσαμε ήταν κενό τότε το πρόγραμμα μας ​δημιουργεί ​το παραπάνω Exception. Δείτε τον κώδικα. 
 <code java > <code java >
 import java.io.*; import java.io.*;
java/exceptions_intro.txt · Last modified: 2019/04/20 05:02 by gthanos