Context
So I am playing with the code related to How slow are Java exceptions? by adding some method references to it. The modified code is below
/**
* [https://stackoverflow.com/questions/299068/how-slow-are-java-exceptions]
*
* The original code is credited to
* [https://stackoverflow.com/users/15809/mecki] &
* [https://stackoverflow.com/users/581994/hot-licks]
*
*/
public class ThrowableCost {
int value;
public int getValue() {
return value;
}
public void reset() {
value = 0;
}
// This one will regularly throw one
public void method3(int i) {
value = ((value + i) / i) << 1;
// i & 1 is equally fast to calculate as i & 0xFFFFFFF; it is both
// an AND operation between two integers. The size of the number plays
// no role. AND on 32 BIT always ANDs all 32 bits
if ((i & 0x1) == 1) {
throw new RuntimeException();
}
}
// Similar to {@link #method3} but not throw the newly created exceptions.
public void method5(int i) {
value = ((value + i) / i) << 1;
// i & 1 is equally fast to calculate as i & 0xFFFFFFF; it is both
// an AND operation between two integers. The size of the number plays
// no role. AND on 32 BIT always ANDs all 32 bits
if ((i & 0x1) == 1) {
new RuntimeException();
}
}
private RuntimeException e = new RuntimeException();
// Similar to {@link #method3} but throw the pre-created exception.
public void method6(int i) {
value = ((value + i) / i) << 1;
// i & 1 is equally fast to calculate as i & 0xFFFFFFF; it is both
// an AND operation between two integers. The size of the number plays
// no role. AND on 32 BIT always ANDs all 32 bits
if ((i & 0x1) == 1) {
throw e;
}
}
public static void main(String[] args) {
System.out.println("Running...");
ThrowableCost t = new ThrowableCost();
invokeWithTryCatch(t, t::method3, "method3");
invokeWithTryCatch(t, t::method5, "method5");
invokeWithTryCatch(t, t::method6, "method6");
System.out.println("Done!");
}
private static void invokeWithTryCatch(ThrowableCost t, Consumer c, String label) {
long l = System.currentTimeMillis();
int i;
t.reset();
for (i = 1; i < 100000000; i++) {
try {
c.accept(i);
} catch (Exception e) {
// Do nothing here, as we will get here
}
}
l = System.currentTimeMillis() - l;
System.out.println(String.format("%s took %d ms, result was %d", label, l, t.getValue()));
}
}
/**
* Similar to {@link java.util.function.Consumer} but avoid auto-boxing in our case.
*/
interface Consumer{
void accept(int i);
}
The output is
Running...
method3 took 30088 ms, result was 2
method5 took 29948 ms, result was 2
method6 took 6298 ms, result was 2
Done!
As you can see the execution time of method6
is around 6000 ms.
However, if I
- invoked the
method6
alone (by commenting out otherinvokeWithTryCatch
s) OR - invoked the
method6
first (by swapping order ofinvokeWithTryCatch
s) OR - invoked the
method6
via instancet
instead ofc
inside ofinvokeWithTryCatch
then the execution of the method6
is much shorter (i.e: around 700 ms)
Question
Why does the order of invokeWithTryCatch
s impact on the execution time of method6
in this approach ?
Note I tried with both JDK8 and JDK11.