Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

exceptions + signaling end-of-iterator: why is it bad in Java and normal in Python?

I'm really confused: The standard approach in Java is to throw exceptions only in "abnormal" conditions and not to use them to signal end-of-iterator.

examples: Effective Java, item 57 ("Use exceptions only for exceptional conditions") and JavaSpecialists newsletter 162:

Flow control

We should never cause an exception that is otherwise preventable. I have seen code where instead of checking bounds, it is assumed that the data will be correct and then RuntimeExceptions are caught:

Here is an example of bad code (please don't code like this):

public class Antipattern1 {
   public static void main(String[] args) {
     try {
       int i = 0;
       while (true) {
         System.out.println(args[i++]);
       }
     } catch (ArrayIndexOutOfBoundsException e) {
       // we are done
    }
  }
}

whereas it is standard to use this idiom in Python, e.g. StopIteration:

exception StopIteration

Raised by an iterator‘s next() method to signal that there are no further values. This is derived from Exception rather than StandardError, since this is not considered an error in its normal application.

Why is it bad for Java but good for Python?

like image 287
Jason S Avatar asked Oct 17 '11 21:10

Jason S


2 Answers

Python and Java have vastly different approaches to exceptions. In Python, exceptions are normal. Look up EAFP (Easier to ask for forgiveness than permission) in the Python glossary. Also check what Wikipedia has to say.

StopIteration is just an example of EAFP – just go ahead and get the next thing from the iterator, and if that fails, handle the error.

If the code is more readable with a non-local exit, in Python you use an exception. You don't write checks, you just deal with failures if things don't work out. There's absolutely nothing shameful about it, in fact it's encouraged. Unlike in Java.


Now for a specific case of StopIteration: Consider generator functions.

def generator():
    yield 1
    print('Side effect')
    yield 2

To support some kind of has_next() method, the generator would have to check for the next value, triggering the print before the 2 is asked for. The value (or exception raised) would have to be remembered in the iterator. If has_next was called twice, only the first one would trigger the side effect. Or the next value could always be precomputed, even if it's not needed.

I find Python's semantics – computing only whenever the next value is needed – the nicest alternative.

Of course Java doesn't have resumable generators, so it's hard to compare here. But it's some anecdotal evidence that StopIteration generalizes better than hasNext().

like image 180
Petr Viktorin Avatar answered Oct 15 '22 17:10

Petr Viktorin


There is nothing that stops you from using exceptions like that in java, it just looks ugly, at least to a java developer.

The main reason is that stacktraces from exceptions are expensive, and possibly also that java developers might be slightly more concerned about spending computing resources than Python developers.

Java is also a rather "clean" language - some would say fundamentalistic, which is one of the reasons it's a nice language. (* see comment)

Anyway. Fundamentalists (and some normal people) thinks that using exceptions for normal flow just isn't The Right Way... :-)

But besides that, recent jvm's detects that you are generating a lot of stacktraces for the same spot of code, and will actually throw exceptions without them "after a while" to speed up things.

like image 41
KarlP Avatar answered Oct 15 '22 17:10

KarlP