Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Throwing always the same exception instance in Java

It was always told me that Java exception handling is quite expensive.

I'm asking if is it a good practice creating an exception instance of a specific type at the beginning of the program and without creating a new one, throwing always the same exception object.

I just want to make an example. Common code:

if (!checkSomething(myObject))
   throw new CustomException("your object is invalid");

alternative:

static CustomException MYEXP = new CustomException("your object is invalid");

//somewhere else
if (!checkSomething(myObject))
    throw MYEXP;

Of course, I'm doing some assumptions here:

  1. MyCustomException has no parameters
  2. client code, whenever is a good practice or not, is heavlily based on exception handling and refactoring is not an option.

So questions are:

  1. Is this a good practice?
  2. Does this damage some JVM mechanism?
  3. If 1 is yes, there is the possibility of a performance gain? (I think not, but not sure)
  4. If 1 and 3 are yes, why is not sponsored as practice?
  5. If 1 is no, why Martin Odersky told in his introduction to Scala that this is how Scala works in some cases? (At minute 28.30 he tolds that break is implemented has throwing an exception, audience says that this is time consuming and he replies that exception is not created every time)Fosdem 2009

I hope this is not a idle/stupid question, I'm curious about this. I think that real cost in exception handling is handling and not creation.

edit Added reference of precise discussion on FOSDEM presentation

disclaimer: none of my code works like proposed and I have no intention to manage exception like this, I'm just doing a "what-if" question and this curiosity is generated from the affermation that video. I thought: if it's done in Scala, why is not in Java?

like image 403
giampaolo Avatar asked Jan 23 '13 21:01

giampaolo


2 Answers

Even though Exceptions are relatively expensive and should be kept to a minimum, they don't cost so much that you should do obtuse things "for performance purposes" This is so often a bad excuse that it is even considered by some that premature optimisation should be avoided at all costs. While that is not entirely true, you can measure how slow exceptions are.

long start = System.nanoTime();
int exceptionCount = 0;
for (int i = 0; i < 20000; i++)
    try {
        int j = i / (i & 1);
    } catch (ArithmeticException ae) {
        exceptionCount++;
    }
long time = System.nanoTime() - start;
System.out.printf("Each exception took average of %,d ns%n", time / exceptionCount);

prints what I believe is a reasonable estimate.

Each exception took average of 3,064 ns

Note: as the number of loops increases, the Exception is optimised away. i.e. for a 10x the iterations

Each exception took average of 327 ns

and for 10x more

Each exception took average of 35 ns

and for 10x more

Each exception took average of 5 ns

If the exception is thrown enough, it appears the JIT is smart enough to optimise the Exception away.

like image 53
Peter Lawrey Avatar answered Nov 15 '22 21:11

Peter Lawrey


No, don't do that. The expensive part is not handling the exception, it is generating the stacktrace. Unfortunately the stacktrace is also the useful part. If you throw a saved exception you will be passing on a misleading stacktrace.

It could be that within the implementation of Scala there are situations where it makes sense to do this. (Maybe they are doing something recursive and want to generate an exception object upfront so in case they run out of memory they can still produce an exception.) They also have a lot of information about what they're doing so they have a better chance of getting it right. But optimizations made by JVM language implementors are a very special case.

So you wouldn't be breaking anything, unless you think providing misleading information constitutes breakage. It seems like a big risk to me.

Trying out Thomas Eding's suggestion for how to create an exception with no stacktrace seems to work:

groovy:000> class MyException extends Exception {
groovy:001>     public Throwable fillInStackTrace() {}}
===> true
groovy:000> e = new MyException()
===> MyException
groovy:000> Arrays.asList(e.stackTrace)
===> []

Also check out the JLS:

The NullPointerException (which is a kind of RuntimeException) that is thrown by method blowUp is not caught by the try statement in main, because a NullPointerException is not assignable to a variable of type BlewIt. This causes the finally clause to execute, after which the thread executing main, which is the only thread of the test program, terminates because of an uncaught exception, which typically results in printing the exception name and a simple backtrace. However, a backtrace is not required by this specification.

The problem with mandating a backtrace is that an exception can be created at one point in the program and thrown at a later one. It is prohibitively expensive to store a stack trace in an exception unless it is actually thrown (in which case the trace may be generated while unwinding the stack). Hence we do not mandate a back trace in every exception.

like image 41
Nathan Hughes Avatar answered Nov 15 '22 21:11

Nathan Hughes