User Tools

Site Tools


java:exceptions_try_catch_block

This is an old revision of the document!


Διαχείριση Εξαιρέσεων

Στην προηγούμενη υποενότητα αναφερθήκαμε συνοπτικά στο αντικείμενο της εξαίρεσης. Εδώ θα δούμε τον τρόπο με τον οποίο διαχειριζόμαστε τις εξαιρέσεις.

Try-Catch Block

Κάθε τμήμα του κώδικα που υπάρχει περίπτωση να πυροδοτήσει μια εξαίρεση θα πρέπει να το περικλείουμε σε ένα try block. Το block αυτό του κώδικα περιγράφει τον τρόπο αντιμετώπισης της κάθε πιθανής εξαίρεσης που μπορεί να προκύψει. Ο ορισμός του block είναι ο εξής:

try{
 
   /* 
    * code that may throw an exception here.
    */
 
}catch (ExceptionTypeOne ex) {
 
   /* 
    * exception handler for ExceptionTypeOne objects.
    */
 
}catch (ExceptionTypeTwo ex) {
 
   /* 
    * exception handler for ExceptionTypeOne objects.
    */
 
}

Εντός του try block βάζουμε τον κώδικα που μπορεί να δημιουργηθεί μια εξαίρεση. Κάθε catch block ορίζει ένα διαφορετικό τύπο εξαίρεσης μέσα σε παρένθεση (ExceptionTypeOne, ExceptionTypeTwo, κλπ). Εάν η εξαίρεση που παράγεται συμπίπτει ως προς τον τύπο της με ένα αντικείμενο που ορίζεται εντός της παρενθέσεως ενός catch block, τότε αυτό το block θα εκτελεστεί. Θα εκτελεστεί επομένως ο κώδικας αντιστοιχεί στον τύπο δεδομένων ο οποίος παράχθηκε από την εκάστοτε εξαίρεση.

Παράδειγμα 1ο - Διαίρεση με μηδέν (0)

Ας δούμε ένα μικρό τμήμα κώδικα που εντοπίζει ένα είδος εξαίρεσης το οποίο συναντήσαμε και παραπάνω:

TestDivideByZero.java
import java.io.*;
import java.util.Scanner;
public class TestDivideByZero {
 
  public static void main (String[] args) {
    int x, y, result;
 
    Scanner input = new Scanner(System.in);
 
    System.out.print( "Enter first integer: " );
    x = input.nextInt();
 
    System.out.print( "Enter second integer: " );
    y = input.nextInt();
 
    try {
        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");
        }
    }
 
  }
}

Όπως βλέπουμε έχουμε το προηγούμενο παράδειγμα, εμπλουτισμένο όμως με κώδικα διαχείρισης της διαίρεσης με το μηδέν. Ο κώδικας θα αναγνωρίσει ότι δημιουργείται ArithmeticException και συγκεκριμένα διαίρεση με το μηδέν (0) και θα εκτυπώσει τα σχετικά μηνύματα.

Παράδειγμα 2ο - Ανοίγοντας ένα αρχείο για διάβασμα

Παρακάτω δίνεται ένα πιο σύνθετο παράδειγμα μία μεθόδου που διαβάζει ένα αρχείο κειμένου και το επιστρέφει στη μορφή ενός String.

WholeFileReader.java
import java.io.*;
import java.lang.*;
 
public class WholeFileReader {
 
  public String readFile(String path) {
 
    try {
      File file = new File (path);
      FileReader 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();
      }
      System.out.println("Closing File!");
      fReader.close();
      return strDocument.toString();
    }
    catch(FileNotFoundException ex) {
      System.out.println("The specified file was not found at "+ path);
      return "";
    }   
    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");
    }
  }
 
}

Περισσότερα του ενός catch blocks - Ιεράρχιση της σειράς εμφάνισης τους

Παρατηρήστε ότι εμφανίζονται δύο catch blocks. Το πρώτο catch block αφορά ΙΟException objects, ενώ το δεύτερο catch block αφορά FileNotFoundException objects. Από τους συνδέσμους που παρατίθενται θα παρατηρήσετε ότι το FileNotFoundException είναι υποκλάση του IOException και δηλώνει ότι το αρχείο δεν βρέθηκε στο filesystem.

Εάν στον παραπάνω κώδικα παραλείπονταν οι γραμμές:

    catch(FileNotFoundException ex) {
      System.out.println("The specified file was not found at "+ path);
      return "";
    }   

Σε αυτή την περίπτωση, ο μη εντοπισμός αρχείου θα ενέπιπτε σε IOException που αποτελεί γονική κλάση της FileNotFoundException. Όταν θα συνέβαινε ένα ΙΟException δεν θα γνωρίζαμε εάν υπάρχει το αρχείο αλλά δεν μπορούμε να το διαβάσουμε (IOException) ή δεν υπάρχει καθόλου το αρχείο που θέλουμε να διαβάσουμε στο filesystem (FileNotFoundException).

Επίσης, δεν θα είχε κανένα νόημα να βάλουμε τα δύο παραπάνω catch blocks με ανάποδη σειρά δηλ.

    catch(IOException ex) {
      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 "";
    }

Σε αυτή την περίπτωση, εάν παραχθεί ένα Exception του τύπου FileNotFoundException θα διαχειριστεί από το πρώτο block που διαχειρίζεται τα IOExcetpions.

Δημιουργία εξαίρεσης

Τέλος, στο παραπάνω παράδειγμα βγάλτε τα σχόλια από την γραμμή throw new IOException();

     while ((inputLine = in.readLine()) != null) {
        strDocument.append(inputLine);
        //throw new IOException();
      }

με στόχο να δημιουργήσετε ένα IOException και παρατηρήστε από τα μηνύματα που εκτυπώνονται κατά την εκτέλεση του προγράμματος την πορεία του προγράμματος.

Finaly Block

Εκτός από τα catch blocks τα οποία εκτελούνται όταν έχουμε κάποιο exception, μπορούμε να προσθέσουμε ένα finaly block το οποίο θα εκτελεστεί σε κάθε περίπτωση. Το finaly block θα εκτελεστεί στις παρακάτω περιπτώσεις:

  • Εάν προκύψει η εξαίρεση που έχουμε φροντίσει να διαχειριστούμε (στο παρακάτω παράδειγμα FileNotFoundException).
  • Εάν προκύψει μια εξαίρεση ενός τύπου που δεν έχουμε φροντίσει να διαχειριστούμε.
  • Εάν δεν προκύψει καμία απολύτως εξαίρεση.

Δείτε το παρακάτω παράδειγμα όπου ενσωματώνει ένα finally block.

WholeFileReader.java
import java.io.*;
import java.lang.*;
 
public class WholeFileReader {
 
  public String readFile(String path) {
 
  FileReader fReader = null;
    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[]) {
    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");
    }
  }
 
}

Ο λόγος που συνήθως χρησιμοποιήσουμε το finally block είναι για να συμπεριλάβουμε κώδικα που θέλουμε να εκτελεστεί σε όλες τις περιπτώσεις, όπως για παράδειγμα να κλείσουμε ελεγχόμενα τα αρχεία του προγράμματος ή να κλείσουμε δικτυακές συνδέσεις (π.χ. συνδέσεις με βάσεις δεδομένων κ.α.). Στο παραπάνω παράδειγμα παραλλάσσεται η μέθοδος ReadFile του προηγούμενου παραδείγματος, ώστε στο finally block η μέθοδος κλείνει το αρχείο που άνοιξε. Η διαφορά σε σχέση με το προηγούμενο παράδειγμα είναι ότι ακόμη και εάν δημιουργηθεί ένα exception την ώρα που διαβάζουμε, η ροή του προγράμματος θα περάσει από το finally block και το αρχείο τελικά θα κλείσει. Αυτό δεν ισχύει στο παράδειγμα που δώσαμε προηγούμενα.

Στο παραπάνω παράδειγμα δείτε την πορεία του κώδικα βγάζοντας τα σχόλια και βάζοντας σε σχόλια την γραμμή που δημιουργεί το IOException.

      while ((inputLine = in.readLine()) != null) {
        strDocument.append(inputLine);
        //throw new IOException();
      }
java/exceptions_try_catch_block.1489142078.txt.gz · Last modified: 2017/03/10 10:34 by gthanos