Throw and catch an exception, or use instanceof?
Solution 1
I'd advise using instanceof
as it will likely be faster. Throwing an exception is a complicated and expensive operation. JVMs are optimized to be fast in the case when exceptions don't happen. Exceptions should be exceptional.
Note that the throw
technique probably won't compile as shown, if your exception type is a checked exception, the compiler will complain that you must catch that type or declare it as thrown (corresponding to an else { ... }
clause if you use the instanceof
technique), which might or might not be helpful, depending on how you want to handle exceptions that are not one of the specific sub-types.
Solution 2
Hate to burst everyone's bubble, but using try/catch
is faster. That's not to say it is the "correct" way, but if performance is key then that's the winner. Here are the results from the following program:
Run 1
- Sub-run 1: Instanceof : 130 ms
- Sub-run 1: Try/catch : 118 ms
- Sub-run 2: Instanceof : 96 ms
- Sub-run 2: Try/catch : 93 ms
- Sub-run 3: Instanceof : 100 ms
- Sub-run 3: Try/catch : 99 ms
Run 2
- Sub-run 1: Instanceof : 140 ms
- Sub-run 1: Try/catch : 111 ms
- Sub-run 2: Instanceof : 92 ms
- Sub-run 2: Try/catch : 92 ms
- Sub-run 3: Instanceof : 105 ms
- Sub-run 3: Try/catch : 95 ms
Run 3
- Sub-run 1: Instanceof : 140 ms
- Sub-run 1: Try/catch : 135 ms
- Sub-run 2: Instanceof : 107 ms
- Sub-run 2: Try/catch : 88 ms
- Sub-run 3: Instanceof : 96 ms
- Sub-run 3: Try/catch : 90 ms
Test environment
- Java: 1.7.0_45
- Mac OSX Mavericks
Discounting warmup sub-runs of each run the instanceof
method only achieves at best the performance of try/catch
. The average (discounting warm-ups) of the instanceof
method is 98 ms and the average of try/catch
is 92 ms.
Please note I did not vary the order in which each method was tested. I always tested a block of instanceof
then a block of try/catch
. I would love to see other results contradicting or confirming these findings.
public class test {
public static void main (String [] args) throws Exception {
long start = 0L;
int who_cares = 0; // Used to prevent compiler optimization
int tests = 100000;
for ( int i = 0; i < 3; ++i ) {
System.out.println("Testing instanceof");
start = System.currentTimeMillis();
testInstanceOf(who_cares, tests);
System.out.println("instanceof completed in "+(System.currentTimeMillis()-start)+" ms "+who_cares);
System.out.println("Testing try/catch");
start = System.currentTimeMillis();
testTryCatch(who_cares, tests);
System.out.println("try/catch completed in "+(System.currentTimeMillis()-start)+" ms"+who_cares);
}
}
private static int testInstanceOf(int who_cares, int tests) {
for ( int i = 0; i < tests; ++i ) {
Exception ex = (new Tester()).getException();
if ( ex instanceof Ex1 ) {
who_cares = 1;
} else if ( ex instanceof Ex2 ) {
who_cares = 2;
}
}
return who_cares;
}
private static int testTryCatch(int who_cares, int tests) {
for ( int i = 0; i < tests; ++i ) {
Exception ex = (new Tester()).getException();
try {
throw ex;
} catch ( Ex1 ex1 ) {
who_cares = 1;
} catch ( Ex2 ex2 ) {
who_cares = 2;
} catch ( Exception e ) {}
}
return who_cares;
}
private static class Ex1 extends Exception {}
private static class Ex2 extends Exception {}
private static java.util.Random rand = new java.util.Random();
private static class Tester {
private Exception ex;
public Tester() {
if ( rand.nextBoolean() ) {
ex = new Ex1();
} else {
ex = new Ex2();
}
}
public Exception getException() {
return ex;
}
}
}
Solution 3
I strongly urge you to actually use a plain object to represent your "constraint". Whether a marking interface (e.g. Message
) or a java.lang.String
is up to you. Exceptions are not meant to be used as you intend, even if either could be made to work (I would expect the second to be faster, but a premature optimization...).
Solution 4
You could also use polymorphism by creating an interface for your custom exceptions that contains the getCustomViolation() method. Then each Custom exception would implement that interface and that method.
Related videos on Youtube
Ruslan
Kotlin and TypeScript developer, Linux and FOSS supporter. In free time play board games (Eclipse) and basketball.
Updated on January 14, 2020Comments
-
Ruslan over 4 years
I have an exception in a variable (not thrown).
What's the best option?
Exception exception = someObj.getExcp(); try { throw exception; } catch (ExceptionExample1 e) { e.getSomeCustomViolations(); } catch (ExceptionExample2 e) { e.getSomeOtherCustomViolations(); }
or
Exception exception = someObj.getExcp(); if (exception instanceof ExceptionExample1) { exception.getSomeCustomViolations(); } else if (exception instanceof ExceptionExample2) { exception.getSomeOtherCustomViolations(); }
-
Elliott Frisch over 10 yearsThe second is the least bad option presented.
-
Ruslan over 10 years@ElliottFrisch custom exception classes contains violations(business, validation, etc.) i need handle this one.
-
Sir_Mr_Bman over 10 yearsThe second one is the best bet, for something that is any good.
-
Elliott Frisch over 10 yearsI'd suggest an interface, and I might call it a
Message
- or just use ajava.lang.String
.
-
-
Ruslan over 10 yearsThank you, that's what I wanted to hear.
-
Andrey Chaschev over 10 years
instanceof
should be faster, but exceptions are not slow and can be optimized by JIT: stackoverflow.com/a/299214/1851024. -
Ruslan over 10 yearsIf I could change the code of Obj class, I would not need such tricks. And just to catch the exception. So, what's the best in performance purposes and code smells?
-
Andrey Chaschev over 10 yearsThis could be a stored error and logic which analyzes exception during multiple constraints checks...
-
Ruslan over 10 yearsYou are absolutely right. This is bad practice. But unfortunately, we are not living in a perfect world.
-
Boann over 10 years@AndreyChaschev In any case, even if
instanceof
isn't faster, it can't be any slower. The best possible optimization ofthrow
would result in the sameinstanceof
logic. -
disrvptor over 10 yearsIf you take a look at my answer and code you will see
try/catch
is faster. I'm not saying it passes code smell tests, but it is faster thaninstanceof
. -
disrvptor over 10 yearsI'm getting inconsistent results. Sometimes one is faster than the other, but not all the time. If you take a look at the actual times you will see that
instanceof
is slower at first, but after about 3 iterationsinstanceof
performs better thantry/catch
. This may be due to JIT optimizations and may not be representative of real-world applications. It's hard if not impossible to get accurate numbers in as testbench when the runtime continuously optimizes for highly recurrent operations. -
disrvptor over 10 yearsIn fact, if I run in interpreted mode only
java -Xint
theninstanceof
is the clear winner. However, if I disable background compilationjava -Xbatch
thentry/catch
wins every time. -
Boann over 10 yearsIt's interesting. Most of the time is taken in
Throwable.fillInStackTrace()
. Then, on the HotSpot Server VM, it is able to turn the simple try-catch into something similar to the if-instanceof (although I can't get that to be faster). On the HotSpot Client VM, the instanceof is a little faster, or if you disable stack traces to exclude them from the test, instanceof is 10 times faster. I'm always impressed by the server VM's optimizations, but it's not the default on 32-bit systems so one can't assume it's there. Either way it seems to not matter unless you're throwing millions of them.