Difference between revisions of "Java Exception Handling"

From MPDLMediaWiki
Jump to navigation Jump to search
m
 
(8 intermediate revisions by the same user not shown)
Line 50: Line 50:
=== No distinction between exceptions and errors/checked and unchecked exceptions ===
=== No distinction between exceptions and errors/checked and unchecked exceptions ===
Compare [http://java.sun.com/javase/6/docs/api/java/lang/Exception.html Exception] and [http://java.sun.com/javase/6/docs/api/java/lang/Error.html Error]
Compare [http://java.sun.com/javase/6/docs/api/java/lang/Exception.html Exception] and [http://java.sun.com/javase/6/docs/api/java/lang/Error.html Error]
=== Different interface boundaries handle exceptions differently ===
* Java --> Java exception handling
* EJB --> partly controlled Java exception handling (RemoteException, EJBException)
* SOAP --> eventually generating exception classes
* REST --> error communication via status codes


== Conclusion ==
== Conclusion ==
=== Distinguish between repairable exceptions and errors ===
=== Distinguish between repairable exceptions and errors ===
Decide whether your module is able to fix the exception (take default values, look somewhere else, try again, ...) or not.
Decide whether your module is able to fix the exception (take default values, look somewhere else, try again, ...) or not.


=== Prefer unchecked exceptions inside a module ===
=== Only catch repairable exceptions ===
* If an exception is somehow repairable, try this in the catch-block
* If the repairing is critical in some respect, at least log a warning message (e.g. logger.warn("Value for xyz not found, taking default value"))
* If repairing fails treat the exception as an error


=== Only catch repairable exceptions ===
=== Inside a module, prefer unchecked exceptions ===
Turn checked exceptions from third-party modules into unchecked exceptions, e.g.
<code>
    private void myMethod()
        try
        {
            connection.executeStatement(sql);
        }
        catch (SQLException sqle)
        {
            throw new RuntimeException("Error executing statement '" + sql + "'", sqle);
        }
    }
</code>


=== Inside a module, always throw errors up as they are ===
=== Inside a module, always throw errors up as they are (alternatively) ===
Do not care for exceptions at all, just declare them to be thrown, e.g.
<code>
    private void myMethod() throws SQLException
        connection.executeStatement(sql);
    }
</code>


=== When catching exceptions, log appropriately ===
=== When catching exceptions, log appropriately ===
Line 69: Line 96:
** <s>logger.error("Error geting server.name property");</s> --> Exception information is lost
** <s>logger.error("Error geting server.name property");</s> --> Exception information is lost
** <s>logger.error(ex);</s> --> Only ex.toString() is logged, other exception information is lost
** <s>logger.error(ex);</s> --> Only ex.toString() is logged, other exception information is lost
* when an exception is rethrown, do not log (except when throwing out of the module)


=== Do not throw self-defined exceptions without a surplus ===
=== Throw self-defined exceptions that are defined inside the throwing module ===


If the exception name is the only gain a self-defined exception brings (e.g. IncorrectArxivIdException), a generic Exception given an appropriate message is better (e.g. new IllegalArgumentException("Incorrect arXiv id " + arxivId))
* For exceptions concerning the logic of the module, exceptions should be defined and checked
* No third module should be necessary to define these exceptions


=== Between modules, throw only generic exceptions ===
=== Between modules, throw only generic exceptions ===
e.g. [http://java.sun.com/javase/6/docs/api/java/lang/IllegalArgumentException.html IllegalArgumentException], [http://java.sun.com/javase/6/docs/api/java/lang/IllegalStateException.html IllegalStateException], [http://java.sun.com/javase/6/docs/api/java/lang/RuntimeException.html RuntimeException]
e.g. [http://java.sun.com/javase/6/docs/api/java/lang/IllegalArgumentException.html IllegalArgumentException], [http://java.sun.com/javase/6/docs/api/java/lang/IllegalStateException.html IllegalStateException], [http://java.sun.com/javase/6/docs/api/java/lang/RuntimeException.html RuntimeException]
== Open questions ==
* Shall interfaces define checked exceptions?
** If so, shall self-defined exceptions be used?


== Links ==
== Links ==
* [http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html OnJava: Best Practices for Exception Handling]
* [http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html OnJava: Best Practices for Exception Handling]
* [http://www.ibm.com/developerworks/library/j-ejbexcept.html IBM: Best practices in EJB exception handling]
* [http://www.ibm.com/developerworks/library/j-ejbexcept.html IBM: Best practices in EJB exception handling]
* [http://today.java.net/pub/a/today/2003/12/04/exceptions.html Sun: Three Rules for Effective Exception Handling]
[[Category:Best_Practice]]

Latest revision as of 13:50, 27 November 2008

Problem description[edit]

Modules need dependencies of other modules only because of their exception classes[edit]

From validation/ItemValidating:

   String validateItemXml(final String itemXml) throws
           ValidationSchemaNotFoundException,
           TechnicalException;

From importmanager/ImportHandler:

   byte[] doFetch(String sourceName, String identifier) throws FileNotFoundException, 
           IdentifierNotRecognisedException, 
           SourceNotAvailableException, 
           TechnicalException,
           FormatNotRecognizedException;

Stacktraces are sometimes swallowed[edit]

   try 
   {
       ...					
   } 
   catch (MalformedURLException e) 
   {LOGGER.error("Error when replacing regex in fetching URL"); e.printStackTrace(); }
   catch(UnsupportedEncodingException e)
   {e.printStackTrace();}

   try 
   {
       ...					
   } 
   catch (JiBXException e) 
   {
       e.getCause();
   }

Sometimes, excessive stacktraces are shown, even without useful information[edit]

Example from coreservices: File:Exception1.txt

Logger.error, System.out and e.printStackTrace are mixed up happily[edit]

see above

No distinction between exceptions and errors/checked and unchecked exceptions[edit]

Compare Exception and Error

Different interface boundaries handle exceptions differently[edit]

  • Java --> Java exception handling
  • EJB --> partly controlled Java exception handling (RemoteException, EJBException)
  • SOAP --> eventually generating exception classes
  • REST --> error communication via status codes

Conclusion[edit]

Distinguish between repairable exceptions and errors[edit]

Decide whether your module is able to fix the exception (take default values, look somewhere else, try again, ...) or not.

Only catch repairable exceptions[edit]

  • If an exception is somehow repairable, try this in the catch-block
  • If the repairing is critical in some respect, at least log a warning message (e.g. logger.warn("Value for xyz not found, taking default value"))
  • If repairing fails treat the exception as an error

Inside a module, prefer unchecked exceptions[edit]

Turn checked exceptions from third-party modules into unchecked exceptions, e.g.

   private void myMethod()
       try
       {
           connection.executeStatement(sql);
       }
       catch (SQLException sqle)
       {
           throw new RuntimeException("Error executing statement '" + sql + "'", sqle);
       }
   }

Inside a module, always throw errors up as they are (alternatively)[edit]

Do not care for exceptions at all, just declare them to be thrown, e.g.

   private void myMethod() throws SQLException
       connection.executeStatement(sql);
   }

When catching exceptions, log appropriately[edit]

  • use log4j, not System.out
  • use the two-argument methods:
    • logger.error("Error geting server.name property", ex);
    • logger.error("Error geting server.name property"); --> Exception information is lost
    • logger.error(ex); --> Only ex.toString() is logged, other exception information is lost
  • when an exception is rethrown, do not log (except when throwing out of the module)

Throw self-defined exceptions that are defined inside the throwing module[edit]

  • For exceptions concerning the logic of the module, exceptions should be defined and checked
  • No third module should be necessary to define these exceptions

Between modules, throw only generic exceptions[edit]

e.g. IllegalArgumentException, IllegalStateException, RuntimeException

Open questions[edit]

  • Shall interfaces define checked exceptions?
    • If so, shall self-defined exceptions be used?

Links[edit]