Java Exclusion Rate

Using exceptions for a normal code flow is bad - it’s slow, it’s a poor quality code, and we've all drummed into our heads since day one. At least I have it! This also makes sense, exceptions generate stack traces on every call, stack traces take a long time to generate, and thus the exception is thrown and caught much slower than the equivalent if statement.

So I decided to make a quick example to demonstrate this.

public static void main(String[] args) throws Exception { Object[] objs = new Object[500000]; for (int i = 0; i < objs.length; i++) { if (Math.random() < 0.5) { objs[i] = new Object(); } } long cur = System.currentTimeMillis(); for (Object o : objs) { try { System.out.print(o.getClass()); } catch (Exception e) { System.out.print("null"); } } System.err.println("Try / catch: "+(System.currentTimeMillis() - cur)); cur = System.currentTimeMillis(); for (Object o : objs) { if(o==null) { System.out.print("null"); } else { System.out.print(o.getClass()); } } System.err.println("If: "+(System.currentTimeMillis() - cur)); } 

However, when I ran the code, I was shocked to see the following:

 Try / catch: 11204 If: 11953 

I ran the code again, this time “if” was faster:

 Try / catch: 12188 If: 12187 

... but only with ms.

All this is done on the server virtual machine, I know that most of the time will be examined by print() statements, and some runs show if the bit is faster than try / catch. But regardless, shouldn't they be close? And how could one generate stack traces faster than a single if statement?

EDIT: To clarify, this question is purely academic - I know well that using exceptions for a normal code flow is bad and will never be so!

+4
source share
7 answers

This has been discussed recently in a new release of Java Specialists: http://www.javaspecialists.eu/archive/Issue187.html

Short answer: it does not generate a stack trace every time, but caches an exception instance.

+4
source

Since the exception throwing point and the catch point are in the same area, and the JIT can prove that you never look at the stack trace, you can optimize the exception in one branch. Perhaps you can avoid this by explicitly highlighting a custom type exception, ideally, across the border of the function call. To control the cost of placing, in the case of no throw, be sure to create an instance of the specified exception object in any case (and ideally return it to ensure that the escape analysis cannot convert it to a stack distribution).

However, JIT can do all kinds of weird things. It’s best to try a test case that is as similar as possible to the real code, rather than such an artificial case, so that you can see the test results after any optimizations that JIT can apply to your real code.

+2
source

I believe that in an earlier version of Java, stack traces were very slow. In fact, I wrote a program that looped a 1000 x 800 UK grid map, and using if statements, the program worked after 10 minutes, working within exceptions and traps, it worked after 2 hours. That was 10 years ago.

More recently, the JVM has a much more efficient use of try-catch.

I also had that “exceptions for exceptional circumstances” drummed into me from the very beginning, and when I saw that the game infrastructure used exceptions as a global goto statement to execute the control flow, I was shocked at first. But, working in real-life scenarios, it is very fast. This was another misconception that I completely blew away, and open your mind to many new ways to use exceptions as a design pattern.

+1
source

The main reason is that the stack trace data set is now deferred until it is actually needed, where it was originally populated when the exception was thrown.

You might want to print your stack for ByteArrayOutputStream to see siutation where stacktrace is actually used for something.

+1
source

It is worth noting that while many consider using exceptions to control flow to be “bad form”, it is not necessarily slower. For example, you may have a choice between

  • checking for value at each iteration
  • Assuming a value exists and throws an exception if it does not

In cases where the value exists less frequently, the test-each-iteration version is likely to be faster. For cases where the value exists more often, the catch-the-failure version is likely to be faster. Admittedly, the choice between the two assumes that you understand your data well and, hopefully, you can run the profiler to see what effect the transition between them has.

All that is said, if you don’t really know that the thrown exception will be faster, you are probably better off with the test-each-iteration version, since it (for many people) is more obvious what it does.

+1
source

a few things

  • The test test is wrong.
  • catch / throwing java exception is fast, very fast
  • stack trace creation and collection is slower (but hotspots annotate the stack)

That said: exceptions are not slow. Printing a stack trace is another issue.

Extra bonus: null checks can be fast, as well as null traps if you do not use an exception

0
source

However, speed is not the only reason for not using exceptions in a normal thread. Exceptions are a mechanism that indicates that a method contract has been violated. If you start using exceptions as a flow control, then it will defeat this goal. You can usually write multiple lines for code to avoid an exception.

0
source

Source: https://habr.com/ru/post/1337600/


All Articles