Diferență între revizuiri ale paginii „Exception Handling”

De la WikiLabs
Jump to navigationJump to search
 
(Nu s-au afișat 8 versiuni intermediare efectuate de același utilizator)
Linia 9: Linia 9:
 
An exception is generated by using keyword '''throw''':
 
An exception is generated by using keyword '''throw''':
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
public void setAge(int _age) throws Exception{
+
public void setAge(int _age) {
 
     if(_age < 0 || _age > 150){
 
     if(_age < 0 || _age > 150){
         Exception _e = new Exception("Invalid age " + _age);
+
         Error _e = new Error("Invalid age " + _age);
 
         throw _e;
 
         throw _e;
 
     }
 
     }
Linia 19: Linia 19:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
An exception once thrown, the normal execution of the program is interrupted and it is resumed in a '''catch''' block associated to that type of exception (see [[#Managing Exceptions]]. For example, in the case above, after the exception has been thrown, the assignment ''age = _age;'' is not executed anymore.
+
An exception once thrown, the normal execution of the program is interrupted and it is resumed in a '''catch''' block associated to that type of exception (see [[#Catching Exceptions|Catching Exceptions]]). For example, in the case above, after the exception has been thrown, the assignment ''age = _age;'' is not executed anymore.
  
== Tratarea excepțiilor ==
+
== Handling Exceptions ==
  
În anumite situații, excepțiile întrerup definitiv execuția programului. Aceste tipuri de excepții nu se administrează (cele extinse din clasa '''Error'''). Există totuși excepții care pot fi tratate, cele extinse din clasa '''Exception'''. Acestea sunt de două tipuri:
+
In certain situations, exceptions interrupt the program for good. These exceptions are not managed (those extended from class '''Error'''). There are however, exceptions that can be managed, those extended from class '''Exception'''. There are two types of these:
* verificate la compile-time (cele extinse direct din '''Exception''', EXCLUSIV [http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html java.lang.RuntimeException]), numite ''checked exceptions'';
+
* checked at compile-time (those extended directly from '''Exception''', but NOT [http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html java.lang.RuntimeException]), called ''checked exceptions'';  
* verificate la runtime (cele extinse din [http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html java.lang.RuntimeException]), numite ''unchecked exceptions''.
+
* checked at runtime (those extended from [http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html java.lang.RuntimeException]), called ''unchecked exceptions''.
  
<div class="regula"><font color="#ff0000">Regulă:</font> Excepțiile ''checked'' care nu sunt administrate în metoda curentă trebuie obligatoriu să apară în lista de excepții generate ale metodei. Excepțiile ''unchecked'' care nu sunt administrate în metoda curentă NU trebuie obligatoriu să apară în lista de excepții generate ale metodei. Excepțiile de tip '''Error''' sunt de tip ''unchecked''.</div>
+
<div class="regula"><font color="#ff0000">Rule:</font> ''Checked'' exceptions which are not caught (managed) in the current method, must appear in the list of thrown exceptions of the method. ''Unchecked'' exceptions that are not caught (managed) in the current method don't need to appear in the list of thrown exceptions of the method. '''Error''' type exceptions are ''unchecked''.</div>
  
Lista de excepții ''checked'' generate de o metodă se scrie după lista de argumente, dar înainte de corpul metodei, utilizând cuvântul cheie '''throws''':
+
The list of ''checked'' exceptions generated by a method is placed after the list of arguments, but before the body of the method, using the word '''throws'''
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
public void setAge(int _age) throws Exception{
 
public void setAge(int _age) throws Exception{
Linia 41: Linia 41:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Cum clasa '''Exception''' este de tip ''checked'', ea trebuie să apară în lista de excepții generată de metodă. În schimb '''RuntimeException''' poate să lipsească:
+
Since class '''Exception''' is ''checked'', it needs to appear in the list of exceptions generated by the method. However, '''RuntimeException''' can be missing:
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
public void setAge(int _age){
 
public void setAge(int _age){
Linia 53: Linia 53:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Propagarea pe stivă ===
+
=== Stack Propagation ===
  
Stiva de execuție a unui program reprezintă secvența de metode apelate una de cealaltă.
+
The execution stack of a program represents the sequence of methods that called one another.
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
Linia 95: Linia 95:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
+
In the situation when the caller method does not catch the exception either, then it's considered that it throws the exception itself, in a sort of recursive manner:
În situația în care nici metoda apelantă nu administrează excepția generată, atunci se consideră că și ea la rândul ei generează același tip de excepție, într-un mod recursiv:
 
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
public class Person{
 
public class Person{
Linia 128: Linia 127:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Administrarea excepțiilor ===
+
=== Catching Exceptions ===
  
Administrarea unei excepții de face într-un bloc '''try-catch'''. Instrucțiunile care pot genera excepții (apeluri de metode sau instrucțiuni '''throw''') se plasează într-un bloc '''try''' după care apar unul sau mai multe blocuri '''catch''' care administrează efectiv fiecare tip de excepție care poate fi generată:
+
Catching an exception is done in a '''try-catch''' block. Instructions that can throw exceptions (calls to methods that throw exceptions or '''throw''' instructions) are placed in a '''try''' block, after which one or more '''catch''' blocks are placed, where the exception is effectively managed:
 
+
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
 
 
public class Person{
 
public class Person{
  
Linia 182: Linia 180:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
O metodă poate arunca mai multe excepții. Acestea pot fi, fiecare în parte, administrate sau propagate mai departe pe stivă. Atenție, principiul polimorfismului se aplică și aici:
+
A method can throw multiple exceptions. These can be, together or separately, caught or throws further up the stack. Therefore, the principle of polymorphism applies here as well:
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
import java.io.*;
 
import java.io.*;
Linia 216: Linia 214:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Cum [http://docs.oracle.com/javase/7/docs/api/java/io/IOException.html java.io.IOException] este extinsă din '''java.lang.Exception''', atunci ar fi fost suficient ca metoda '''readAgeFromFile()''' declare că aruncă doar '''java.lang.Exception''', dar atunci cele două excepții nu ar fi putut fi tratate separat în două blocuri '''catch'''. Din același motiv, dacă blocul '''catch''' care administrează excepția de tip '''java.lang.Exception''' ar fi fost prima după blocul '''try''', atunci acest bloc '''catch''' ar fi prins și excepțiile de tip '''java.io IOException''', deci în acest caz, ordinea blocurilor '''catch''' contează.
+
Since [http://docs.oracle.com/javase/7/docs/api/java/io/IOException.html java.io.IOException] is extended from '''java.lang.Exception''', then it would have been sufficient for the method '''readAgeFromFile()''' to only declare '''java.lang.Exception''' as thrown. However, if the '''catch''' block that handle the exception of type '''java.lang.Exception''' would have been the first after the '''try''' block, then this '''catch''' block would also catch exceptions of type '''java.io IOException''', so the order of the '''catch''' blocks if often very important.
  
=== Blocul finally și try-with-resources ===
+
=== The finally Block and try-with-resources ===
  
Există situații în care se dorește execuția unei bucăți de program indiferent dacă o excepție a fost generată sau dacă blocul '''try''' a fost executat cu succes. În acest caz se folosește un bloc '''finally''' după ultimul '''catch'''. De cele mai multe ori, motivul pentru utilizarea unui bloc '''finally''' este de a elibera resursele care au rămas potențial alocate:
+
There are situations where a certain part of the program needs to be executed even if an exception has been thrown or not. In this case, a '''finally''' block is used, after the last '''catch''' block. Usually, the '''finally''' block is used to free any allocated resources:
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
public void writeAgeToFile(int _age, String _filename){
+
public void writeAgeToFile(int _age, String _filename) throws IOException{
 
     FileOutputStream _file = null;
 
     FileOutputStream _file = null;
  
Linia 241: Linia 239:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Începând cu versiunea Java 7.0, a fost introdus un nou tip de bloc '''try''': ''try-with-resources''. Acesta primește ca argumente o serie de expresii de instanțiere a unor obiecte. Aceste obiecte trebuie obligatoriu să implementeze interfața [http://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html java.lang.AutoClosable]. Avantajul este că la ieșirea din blocul ''try-with-resources'', aceste resurse sunt eliberate automat:
+
Starting with Java 7, a new type of block has been introduced: ''try-with-resources''. This takes as arguments a series of expressions used to initialize objects. The classes of these objects must implement the interface [http://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html java.lang.AutoClosable]. The advantage is that at the end of the ''try-with-resources'' block, these resources are freed automatically:
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
Linia 251: Linia 249:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
este echivalent cu:
+
is the same as:
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
Linia 266: Linia 264:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Mai multe despre excepții pe [http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html site-ul oficial Oracle].
+
More about exceptions on [http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html the official Oracle website].

Versiunea curentă din 15 decembrie 2013 12:44

In Java, exceptions represent an interruption in the normal execution of the algorithm. They are used to manage the issues that appear during the execution and to take action in order to recover and resume the program when possible. Exceptions, like everything else in Java, are objects. The base class for any type of exception is java.lang.Throwable.

From class Throwable, two other classes are derived:

  • java.lang.Error - a type of exception describing a serious problem in program execution because of which the application can no longer continue; these types of exceptions usually can't be managed or recovered.
  • java.lang.Exception - a class of exceptions that the application can manage and after which execution can resume correctly.

Generating (Throwing) Exceptions

An exception is generated by using keyword throw:

public void setAge(int _age) {
    if(_age < 0 || _age > 150){
        Error _e = new Error("Invalid age " + _age);
        throw _e;
    }

    age = _age;
}

An exception once thrown, the normal execution of the program is interrupted and it is resumed in a catch block associated to that type of exception (see Catching Exceptions). For example, in the case above, after the exception has been thrown, the assignment age = _age; is not executed anymore.

Handling Exceptions

In certain situations, exceptions interrupt the program for good. These exceptions are not managed (those extended from class Error). There are however, exceptions that can be managed, those extended from class Exception. There are two types of these:

Rule: Checked exceptions which are not caught (managed) in the current method, must appear in the list of thrown exceptions of the method. Unchecked exceptions that are not caught (managed) in the current method don't need to appear in the list of thrown exceptions of the method. Error type exceptions are unchecked.

The list of checked exceptions generated by a method is placed after the list of arguments, but before the body of the method, using the word throws

public void setAge(int _age) throws Exception{
    if(_age < 0 || _age > 150){
        Exception _e = new Exception("Invalid age " + _age);
        throw _e;
    }

    age = _age;
}

Since class Exception is checked, it needs to appear in the list of exceptions generated by the method. However, RuntimeException can be missing:

public void setAge(int _age){
    if(_age < 0 || _age > 150){
        RuntimeException _e = new RuntimeException("Invalid age " + _age);
        throw _e;
    }

    age = _age;
}

Stack Propagation

The execution stack of a program represents the sequence of methods that called one another.

public class Person{

    private String fullName;
    private int age;
    private boolean gender;

public Person(String _fullName, int _age, boolean _gender){
    setAge(_age);
} 

public static void main(String[] _args){
    Person _p = new Person("Ghita Vasile", 20, true);
}

public void setAge(int _age){
     /* in this point, the execution stack is as follows:
      * 
      *  /---------------------------------\    ^
      *  |        void setAge(int)         |    |
      *  +---------------------------------+    |
      *  |  Person(String, int, boolean)   |    |
      *  +---------------------------------+    |
      *  |    static void main(String[])   |    |
      *  \---------------------------------/    |
      *
      *  where method main(String[]) is at the 
      *  bottom of the stack (first one called)
      *  and method setAge(int) is on the top
      *  of the stack (last one called), and it's
      *  the method that's currently in execution.
      */
     age = _age;
}

}

In the situation when the caller method does not catch the exception either, then it's considered that it throws the exception itself, in a sort of recursive manner:

public class Person{

    private String fullName;
    private int age;
    private boolean gender;

public Person(String _fullName, int _age, boolean _gender) throws Exception{
    //...
    /* setAge() throws a checked exception of type Exception
     * which isn't caught in this method, so this method will
     * throw the exception further up the stack, thus the 'throws Exception'
     * in the method declaration
     */  
    setAge(_age);
    //..
    System.out.println("If setAge() throws an exception, this line will not be executed!");
} 

public void setAge(int _age) throws Exception{
    if(_age < 0 || _age > 150){
        Exception _e = new Exception("Invalid age " + _age);
        throw _e;
    }

    age = _age;
}

}

Catching Exceptions

Catching an exception is done in a try-catch block. Instructions that can throw exceptions (calls to methods that throw exceptions or throw instructions) are placed in a try block, after which one or more catch blocks are placed, where the exception is effectively managed:

public class Person{

    private String fullName;
    private int age;
    private boolean gender;

public Person(String _fullName, int _age, boolean _gender) throws Exception{
    //...
    /* setAge() throws a checked exception of type Exception
     * which isn't caught in this method, so this method will
     * throw the exception further up the stack, thus the 'throws Exception'
     * in the method declaration
     */  
    setAge(_age);
    //..
    System.out.println("If setAge() throws an exception, this line will not be executed!");
} 

public static void main(String[] _args){
    try{
        Person _p = new Person("Ghita Vasile", -30, true);
    }catch(Exception _e){
        /* if an exception is thrown by the constructor, the execution
         * is continued with this catch block. The reference _e is to 
         * the object that has been thrown. In this particular case, 
         * the instantiation of the object is not complete, therefor
         * _p is still null.
         */
         System.out.println("Can't create Person object: " + _e.getMessage());
    }

    /* after the catch block completes, or in case no exception is thrown,
     * the execution continues from here.
     */
    System.out.println("Program done!");
}

public void setAge(int _age) throws Exception{
    if(_age < 0 || _age > 150){
        Exception _e = new Exception("Invalid age " + _age);
        throw _e;
    }

    age = _age;
}

}

A method can throw multiple exceptions. These can be, together or separately, caught or throws further up the stack. Therefore, the principle of polymorphism applies here as well:

import java.io.*;

public class Person{

public static void main(String[] _args){
    try{
        Person _p = new Person();
        int _age = _p.readAgeFromFile("ageFile.bin");
    }catch(IOException _e){
         System.out.println("Unable to open file for reading: " + _e.getMessage());
    }catch(Exception _e){
         System.out.println("The age is invalid: " + _e.getMessage());
    }

    System.out.println("Program done!");
}

public int readAgeFromFile(String _fileName) throws IOException, Exception{
    FileInputStream _fileInputStream = new FileInputStream(_fileName);
    int _age = _fileInputStream.read();
    _fileInputStream.close();

    if(_age < 0 || _age > 150){
        throw new Exception("Invalid age read from file: " + _age);
    }

    return _age;
}

}

Since java.io.IOException is extended from java.lang.Exception, then it would have been sufficient for the method readAgeFromFile() to only declare java.lang.Exception as thrown. However, if the catch block that handle the exception of type java.lang.Exception would have been the first after the try block, then this catch block would also catch exceptions of type java.io IOException, so the order of the catch blocks if often very important.

The finally Block and try-with-resources

There are situations where a certain part of the program needs to be executed even if an exception has been thrown or not. In this case, a finally block is used, after the last catch block. Usually, the finally block is used to free any allocated resources:

public void writeAgeToFile(int _age, String _filename) throws IOException{
    FileOutputStream _file = null;

    try{
        _file = new FileOutputStream(_filename);
        _file.write(100 / _age);        
    }catch(ArithmeticException e){
        System.err.println("Caught ArithmeticException: " +  e.getMessage());
    }catch(IOException e){
        System.err.println("Caught IOException: " +  e.getMessage());
    }finally{
        if(_file != null){
             _file.close();
        }
    }
}

Starting with Java 7, a new type of block has been introduced: try-with-resources. This takes as arguments a series of expressions used to initialize objects. The classes of these objects must implement the interface java.lang.AutoClosable. The advantage is that at the end of the try-with-resources block, these resources are freed automatically:

static String readFirstLineFromFile(String _path) throws IOException{
    try(BufferedReader _reader = new BufferedReader(new FileReader(_path))){
        return _reader.readLine();
    }
}

is the same as:

static String readFirstLineFromFileWithFinallyBlock(String _path) throws IOException{
    BufferedReader _reader = new BufferedReader(new FileReader(_path));
    try{
        return _reader.readLine();
    }finally{
        if (_reader != null){
            _reader.close();
        }
    }
}

More about exceptions on the official Oracle website.