commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rodney Waldhoff <rwaldh...@apache.org>
Subject RE: Checked vs Runtime exceptions
Date Tue, 24 Jun 2003 22:12:36 GMT
I'm not sure that "ownership" necessarily enters into it, but here's some
concrete examples:

Consider a simple logging API:

interface Log {
  void debug(String message);
  void info(String message);
  void fatal(String message);
}

One implementation of that interface might write the output to standard
out.  Since System.out (java.io.PrintStream I guess) never throws a
checked exception, there's no need to ever throw a checked exception from
that implementation or that interface.

Another implementation of that interface might write to some external
file.  Any of those write calls might throw an IOException, in which case
I should add "throws IOException" to all of my logging methods unless I'm
gonna swallow all of those exceptions (while swallowing exceptions *might*
be OK in the logging case, it certainly isn't OK in the general case).

interface Log {
  void debug(String message) throws IOException;
  void info(String message) throws IOException;
  void fatal(String message) throws IOException;
}

Now even if I'm using a System.out logger, I've got to catch or throw
IOException, just in case.

Yet another implementation of that interface might write log messages to a
database.  Any of those insert statements might throw a SQLException, in
which case I should add "throws SQLException" to all my logging methods:

interface Log {
  void debug(String message) throws IOException, SQLException;
  void info(String message) throws IOException, SQLException;
  void fatal(String message) throws IOException, SQLException;
}

Of course, I'll never be able to anticipate all of the specific types of
Exception that might be thrown.  I may as well drop back to the general
case:

interface Log {
  void debug(String message) throws Exception;
  void info(String message) throws Exception;
  void fatal(String message) throws Exception;
}

but now I have all of the disadvantages of checked exceptions--I need to
explictly catch or throw Exception every time I invoke one of these
methods--but none of the advantages of checked exceptions--I don't have
any guarentee that the specific type of exception that might be throw by
the implementation code is going to be specifically handled by the calling
code.  How's this any better than RuntimeException?

As another example, consider java.util.Iterator.  I can do lots of useful
things with Iterators (chain them, filter them, transform them, apply some
function to each element within the iteration, etc.).  One source of
Iterators is the Collections API.  But it's not difficult to create an
Iterator from other sources--say an Iterator over the lines in a file:

class LineIterator implements Iterator {
  LineIterator(BufferedReader reader) {
     this.reader = reader;
  }

  Object next() {
    if(hasNext()) {
       nextSet = false;
       return nextLine;
    } else {
       throw new NoSuchElementException();
    }
  }

  boolean hasNext() {
    if(!nextSet) {
      setNext();
    }
    return nextLine != null;
  }

  private setNext() throws IOException {
     nextLine = reader.readLine();
     nextSet = true;
  }

  private Reader reader;
  private String nextLine;
  private boolean nextSet = false;
}

or the values in some column in a database table:

class ColumnIterator implements Iterator {
  ColumnIterator(ResultSet rset, int column) {
     this.rset = rset;
     this.column = column;
  }

  Object next() {
    if(hasNext()) {
       nextSet = false;
       return next;
    } else {
       throw new NoSuchElementException();
    }
  }

  boolean hasNext() {
    if(!nextSet) {
      setNext();
    }
    return nextSet;
  }

  private setNext() throws SQLException {
     if(rset.next()) {
        next = rset.getString(column);
        nextSet = true;
     } else {
        nextSet = false;
     }
  }

  private ResultSet rset;
  private int column;
  private Object next;
  private boolean nextSet = false;
}

Of course, those don't quite work because the checked IOExceptions and
SQLExceptions aren't being handled.  In theory, one could add "throws
Exception" to all of the Iterator methods (subject to the limitations
above), but in practice that's not going to happen.

Why not just throw RuntimeException in this case (and ignore the tunneling
concept)?  Because there are times when I might be able to handle or
announce the underlying cause:

// process the commands in the given stream, ignoring lines that start
with #
void processCommandStream(Reader in) throws IOException {
   UnaryPredicate startsWithHash = new UnaryPredicate() {
      public boolean evaluate(Object obj) {
         return ((String)obj).startsWith("#");
      }
   }

   Iterator iterator = new FilteringIterator(
      new NotPredicate(startsWithHash),
      new LineIterator(in));

   try {
     while(iterator.hasNext()) {
        processCommand((String)iterator.next());
     }
   } catch(TunneledException e) {
     if(e.getException() instanceof IOException) {
        throw (IOException)(e.getException());
     }
   }
}

- Rod <http://radio.weblogs.com/0122027/>

On Tue, 24 Jun 2003, David Graham wrote:

> > I see his proposed technique as being useful in the case where we own
> > layers
> > A and C, and need to get through layer B in the cleanest way, where
> > layer B
> > doesn't expose a proper middleware understanding of exception handling.
> > I
> > would not want to see new middleware use his proposal as an "excuse" not
> > to
> > provide for checked exceptions in the interface.
>
> Can you provide a concrete example of layers A, B, and C?  A
> RuntimeException wrapping a checked exception class may be useful in some
> cases but adding it to commons implies that Jakarta Commons supports poor
> programming practices.
>
> David
>
> >
> > 	--- Noel
> >
>
>
> __________________________________
> Do you Yahoo!?
> SBC Yahoo! DSL - Now only $29.95 per month!
> http://sbc.yahoo.com
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message