352

I am working on an application and one design approach involves extremely heavy use of the instanceof operator. While I know that OO design generally tries to avoid using instanceof, that is a different story and this question is purely related to performance. I was wondering if there is any performance impact? Is is just as fast as ==?

For example, I have a base class with 10 subclasses. In a single function that takes the base class, I do checks for if the class is an instance of the subclass and carry out some routine.

One of the other ways I thought of solving it was to use a "type id" integer primitive instead, and use a bitmask to represent categories of the subclasses, and then just do a bit mask comparison of the subclasses "type id" to a constant mask representing the category.

Is instanceof somehow optimized by the JVM to be faster than that? I want to stick to Java but the performance of the app is critical. It would be cool if someone that has been down this road before could offer some advice. Am I nitpicking too much or focusing on the wrong thing to optimize?

JSK NS
  • 3,346
  • 2
  • 25
  • 42
Josh
  • 17,834
  • 7
  • 50
  • 68
  • 88
    I think the point of the question, however, was to set aside the question of best OO practice, and examine the performance. – Dave L. Sep 19 '08 at 16:50
  • 4
    @Dave L. Normally I would agree, but the OP does mention that he's looking for some general optimization techniques and he's not sure if his problem is related to 'instanceof'. I think it's worth at least mentioning the 'correct' design so he can profile both choices. – Tim Frey Sep 19 '08 at 16:54
  • 58
    Ugh... Why do all the answers miss the point of the question and supply the same old Knuth rhetoric about optimisation? Your question is about whether instanceof is significantly/surprisingly slower than checking the class object with ==, and I've found that it is not. – gub May 12 '10 at 10:18
  • 3
    The performance of instanceof and casting is quite good. I posted some timing in Java7 around different approaches to the problem here: http://stackoverflow.com/questions/16320014/java-optimization-nitpick-is-it-faster-to-cast-something-and-let-it-throw-excep/28858680#28858680 – Wheezil Mar 06 '15 at 12:37
  • 2
    It is necessary for proper implementations of `equals(Object)` to use `instanceof`, and calls of `equals(Object)` are very common, so I would expect most JVMs can do it very efficiently. – Raedwald Dec 07 '20 at 21:01

24 Answers24

346

Approach

I wrote a benchmark program to evaluate different implementations:

  1. instanceof implementation (as reference)
  2. object-orientated via an abstract class and @Override a test method
  3. using an own type implementation
  4. getClass() == _.class implementation

I used jmh to run the benchmark with 100 warmup calls, 1000 iterations under measuring, and with 10 forks. So each option was measured with 10 000 times, which takes 12:18:57 to run the whole benchmark on my MacBook Pro with macOS 10.12.4 and Java 1.8. The benchmark measures the average time of each option. For more details see my implementation on GitHub.

For the sake of completeness: There is a previous version of this answer and my benchmark.

Results

| Operation  | Runtime in nanoseconds per operation | Relative to instanceof |
|------------|--------------------------------------|------------------------|
| INSTANCEOF | 39,598 ± 0,022 ns/op                 | 100,00 %               |
| GETCLASS   | 39,687 ± 0,021 ns/op                 | 100,22 %               |
| TYPE       | 46,295 ± 0,026 ns/op                 | 116,91 %               |
| OO         | 48,078 ± 0,026 ns/op                 | 121,42 %               |

tl;dr

In Java 1.8 instanceof is the fastest approach, although getClass() is very close.

Michael Dorner
  • 17,587
  • 13
  • 87
  • 117
  • The code also suffers from a clear opportunity to do Dead Code Elimination. The `doX()` method calls have no lasting effect. – Marko Topolnik Sep 28 '16 at 06:42
  • It flips the sign? – Michael Dorner Sep 28 '16 at 09:16
  • 3
    I saw in your test that for every `instanceof X` that you do `X` has no sub-types. This could (theoretically) be optimized by the JVM (similar to how it replaces `invokevirtual` with direct method call in such cases). Using deeper hierarchies and including interfaces could provide a more accurate result. But I would not expect a significantly different outcome. – PeterG May 08 '17 at 12:55
  • OK, what about string table lookup with `switch()`? That is, let's say I have to say `if(x instanceof Integer || x instanceof Long || x instanceof Short)` and I have a long list of things to check. Would it be more efficient to do a `switch(x.getClass().getName)` and have a lot of `case "java.lang.Integer":`, etc.? Would the string switch be more efficient than having a lot of `instanceof` comparisons? – Garret Wilson Jul 12 '18 at 22:50
  • 1
    The JMH test is not well done. You are measuring a cast operation, using no Blackholes. I think your test is reporting a false truth. Especially with regards of `measureGETCLASS` that is indeed faster than – JeanValjean May 11 '20 at 16:48
  • I wouldn't agree on that: As far as In understood, Blackholes in JMH prevent dead code elimination. But there is no potential dead code as the sign flip is stored in the object. So it must be evaluated. Or have I misunderstood your comment? – Michael Dorner May 11 '20 at 20:12
295

Modern JVM/JIT compilers have removed the performance hit of most of the traditionally "slow" operations, including instanceof, exception handling, reflection, etc.

As Donald Knuth wrote, "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." The performance of instanceof probably won't be an issue, so don't waste your time coming up with exotic workarounds until you're sure that's the problem.

Gurwinder Singh
  • 38,557
  • 6
  • 51
  • 76
Steve
  • 3,471
  • 1
  • 18
  • 14
  • I don't have specific java versions, but any JVMs released by the major players (Sun/Oracle, IBM, Apple, etc) from the last 10 years or so could probably be considered "modern" in this regard. – Steve Apr 08 '11 at 19:17
  • 170
    Always there's someone, who cites Knuth when performance is the topic... Forgetting, that Knuth also stated (in the same article) "In established engineering disciplines a 12 % improvement, easily obtained, is never considered marginal and I believe the same viewpoint should prevail in software engineering", nearly all his work was about efficiency of algorithms and he wrote algorithms in assembly to (inter alia) achieve better performance. Meh... – kgadek Sep 01 '11 at 08:43
  • 5
    An aside here but would `try { ObjT o = (ObjT)object } catch (e) { no not one of these }` would be any faster slower ?? – peterk Feb 13 '12 at 15:51
  • 39
    If "object" is an instance of ObjT, casting it is a little faster than doing an instanceof, but the difference my quick test found was 10-20ms over 10,000,000 iterations. If "object" isn't an ObjT, though, catching the exception was over 3000x slower - over 31,000ms vs ~10ms for the instanceof. – Steve Feb 18 '12 at 00:27
  • 24
    such a strong argument without any "reference", is completely useless because just opinionated. – marcorossi Apr 17 '13 at 23:29
  • @Steve: I agree with marcorossi. I would like to know which the specific performance characteristics are, rather than rely on a blanket statement like this. Otherwise, how would i justify using instanceof in a Code Review - because Steve on SO says so won't fly in the real world. Kudos to your above commend about exception handling vs instanceof, though. That at least gives me some idea of what you are talking about. – josiah Jan 27 '15 at 01:35
  • @peterk "casting vs instanceOf". Think like implementing your own virtual machine. In case of instanceOf you will refer to a class defination(object Class class) and checks for its parent reference. Compare the cost of this operation to operation involves in trying to assign the object to a variable of ObjT: VM tries to find out if object is of type ObjT(this should involves looking into ObjT Class class), if it is not, VM should raise an exception.Your code catches the exception. All these are extra instructions being executed. Hence casting will perform much worse than instanceOf. – mawia Mar 29 '15 at 08:10
  • 1
    @mawia: the costs of type casts and the `instanceof` operator are exactly the same in the successful case, as what the JVM does is the same, the only difference is the treatment of `null` references. In either case, [modern JVMs don’t traverse the type hierarchy anymore](http://stackoverflow.com/a/26337040/2711488). The subsequent assignment to the local variable is irrelevant, it has no effect. – Holger Sep 28 '16 at 11:07
  • 2
    You should always answer a question. Not just tell them don't do it. – Kimi Chiu Aug 12 '17 at 04:31
  • Check out empirical observations in other answers and in this other question. In general, anything involving a stack trace is going to be _much_ slower. https://stackoverflow.com/questions/299068/how-slow-are-java-exceptions – Darrell Teague Aug 31 '18 at 18:11
  • Due diligence is important. The more emphasis upon making computers do all the work for us, the more we take advantage of Moore's law as a crutch rather than a gift. While splitting hairs over use of instanceof might be fruitless, I have found in my own organization that the general stigma against thinking about high performance code while you write it has resulted in, not just a few inefficient instructions, but several hundred. We need to load balance better between the carbon-based units and the silicon-based units. – Coder Guy Dec 09 '20 at 18:24
  • I should add that due diligence includes making time for performance profiling for issues like these that are not certain. I was convinced that using Scala's `Either.fold` method would be faster than performing a pattern match on it. The latter approach did result in more bytecode as expected, but using `Either.fold` was actually slower. This was very unexpected. – Coder Guy Dec 10 '20 at 02:27
  • While I'm a big fan of that Don Knuth quote, there's nothing inherent about instanceof that would lend itself to a particularly fast implementation (you still have to walk up the class hierarchy and compare class pointers). And you can't just apply the Knuth quote to any language feature that is not efficient. Have you ever tried single-stepping through the Java libraries as a method is being invoked reflectively, i.e. through all the security check code etc.? There's no way that will ever be sped up with a smart JIT. Java 8 lambdas are similar, if you've ever looked at a debug trace: bleuch! – Luke Hutchison Jun 03 '21 at 05:28
76

I just made a simple test to see how instanceOf performance is comparing to a simple s.equals() call to a string object with only one letter.

in a 10.000.000 loop the instanceOf gave me 63-96ms, and the string equals gave me 106-230ms

I used java jvm 6.

So in my simple test is faster to do a instanceOf instead of a one character string comparison.

using Integer's .equals() instead of string's gave me the same result, only when I used the == i was faster than instanceOf by 20ms (in a 10.000.000 loop)

20

The items which will determine the performance impact are:

  1. The number of possible classes for which the instanceof operator could return true
  2. The distribution of your data - are most of the instanceof operations resolved in the first or second attempt? You'll want to put your most likely to return true operations first.
  3. The deployment environment. Running on a Sun Solaris VM is significantly different than Sun's Windows JVM. Solaris will run in 'server' mode by default, while Windows will run in client mode. The JIT optimizations on Solaris, will make all method access able the same.

I created a microbenchmark for four different methods of dispatch. The results from Solaris are as follows, with the smaller number being faster:

InstanceOf 3156
class== 2925 
OO 3083 
Id 3067 
brianegge
  • 29,240
  • 13
  • 74
  • 99
19

Answering your very last question: Unless a profiler tells you, that you spend ridiculous amounts of time in an instanceof: Yes, you're nitpicking.

Before wondering about optimizing something that never needed to be optimized: Write your algorithm in the most readable way and run it. Run it, until the jit-compiler gets a chance to optimize it itself. If you then have problems with this piece of code, use a profiler to tell you, where to gain the most and optimize this.

In times of highly optimizing compilers, your guesses about bottlenecks will be likely to be completely wrong.

And in true spirit of this answer (which I wholeheartly believe): I absolutely don't know how instanceof and == relate once the jit-compiler got a chance to optimize it.

I forgot: Never measure the first run.

Olaf Kock
  • 46,930
  • 8
  • 59
  • 90
  • 1
    But the original poster mentioned performance was critical for this application, so it's not unreasonable to optimize early in that situation. In other words you wouldn't write a 3d game in GWBasic and then at the end say, ok let's start optimizing this, first step is to port it to c++. – LegendLength Jan 07 '16 at 02:26
  • GWBasic might be a great start for 3d games, if there are proper libraries available. But that aside (as it's an artificial argument): OP is not asking for a complete rewrite as optimization. It's about a single construct where we don't even know if the impact is significant (even if there's a better performing way to do the same *in the current version of the compiler*). I'm firmly standing behind http://c2.com/cgi/wiki?ProfileBeforeOptimizing and my answer. Preliminary Optimization is the root of all evil! It makes maintenance harder - and maintenance is the aspect that is worth optimizing – Olaf Kock Jan 11 '16 at 14:46
16

I have got same question, but because i did not find 'performance metrics' for use case similar to mine, i've done some more sample code. On my hardware and Java 6 & 7, the difference between instanceof and switch on 10mln iterations is

for 10 child classes - instanceof: 1200ms vs switch: 470ms
for 5 child classes  - instanceof:  375ms vs switch: 204ms

So, instanceof is really slower, especially on huge number of if-else-if statements, however difference will be negligible within real application.

import java.util.Date;

public class InstanceOfVsEnum {

    public static int c1, c2, c3, c4, c5, c6, c7, c8, c9, cA;

    public static class Handler {
        public enum Type { Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, TypeA }
        protected Handler(Type type) { this.type = type; }
        public final Type type;

        public static void addHandlerInstanceOf(Handler h) {
            if( h instanceof H1) { c1++; }
            else if( h instanceof H2) { c2++; }
            else if( h instanceof H3) { c3++; }
            else if( h instanceof H4) { c4++; }
            else if( h instanceof H5) { c5++; }
            else if( h instanceof H6) { c6++; }
            else if( h instanceof H7) { c7++; }
            else if( h instanceof H8) { c8++; }
            else if( h instanceof H9) { c9++; }
            else if( h instanceof HA) { cA++; }
        }

        public static void addHandlerSwitch(Handler h) {
            switch( h.type ) {
                case Type1: c1++; break;
                case Type2: c2++; break;
                case Type3: c3++; break;
                case Type4: c4++; break;
                case Type5: c5++; break;
                case Type6: c6++; break;
                case Type7: c7++; break;
                case Type8: c8++; break;
                case Type9: c9++; break;
                case TypeA: cA++; break;
            }
        }
    }

    public static class H1 extends Handler { public H1() { super(Type.Type1); } }
    public static class H2 extends Handler { public H2() { super(Type.Type2); } }
    public static class H3 extends Handler { public H3() { super(Type.Type3); } }
    public static class H4 extends Handler { public H4() { super(Type.Type4); } }
    public static class H5 extends Handler { public H5() { super(Type.Type5); } }
    public static class H6 extends Handler { public H6() { super(Type.Type6); } }
    public static class H7 extends Handler { public H7() { super(Type.Type7); } }
    public static class H8 extends Handler { public H8() { super(Type.Type8); } }
    public static class H9 extends Handler { public H9() { super(Type.Type9); } }
    public static class HA extends Handler { public HA() { super(Type.TypeA); } }

    final static int cCycles = 10000000;

    public static void main(String[] args) {
        H1 h1 = new H1();
        H2 h2 = new H2();
        H3 h3 = new H3();
        H4 h4 = new H4();
        H5 h5 = new H5();
        H6 h6 = new H6();
        H7 h7 = new H7();
        H8 h8 = new H8();
        H9 h9 = new H9();
        HA hA = new HA();

        Date dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerInstanceOf(h1);
            Handler.addHandlerInstanceOf(h2);
            Handler.addHandlerInstanceOf(h3);
            Handler.addHandlerInstanceOf(h4);
            Handler.addHandlerInstanceOf(h5);
            Handler.addHandlerInstanceOf(h6);
            Handler.addHandlerInstanceOf(h7);
            Handler.addHandlerInstanceOf(h8);
            Handler.addHandlerInstanceOf(h9);
            Handler.addHandlerInstanceOf(hA);
        }
        System.out.println("Instance of - " + (new Date().getTime() - dtStart.getTime()));

        dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerSwitch(h1);
            Handler.addHandlerSwitch(h2);
            Handler.addHandlerSwitch(h3);
            Handler.addHandlerSwitch(h4);
            Handler.addHandlerSwitch(h5);
            Handler.addHandlerSwitch(h6);
            Handler.addHandlerSwitch(h7);
            Handler.addHandlerSwitch(h8);
            Handler.addHandlerSwitch(h9);
            Handler.addHandlerSwitch(hA);
        }
        System.out.println("Switch of - " + (new Date().getTime() - dtStart.getTime()));
    }
}
Xtra Coder
  • 3,389
  • 4
  • 40
  • 59
  • Which result was java 6 and which was java 7? Have you revisited this under Java 8? More significantly here, you're comparing a length if of instanceofs to what is essential a case statement on ints. I think we would expect an int switch to be lightening fast. – Azeroth2b Apr 24 '17 at 13:10
  • 1
    I can't remember exactly what was happening 5 years ago - I think both Java 6 and Java 7 had similar result, that's why there is only one result provided (provided 2 lines are for different depth of class hierarchy)... and no, i did not try comparing with Java 8. The whole code of test is provided - you may copy/paste it and check in the environments you need (note - nowadays I would use JMH test for this). – Xtra Coder Apr 26 '17 at 11:27
  • This code doesn't properly warm up the VM, which will balloon the first loop. That seems to have skewed the results. – blurryrunner Feb 18 '21 at 23:07
13

instanceof is really fast, taking only a few CPU instructions.

Apparently, if a class X has no subclasses loaded (JVM knows), instanceof can be optimized as:

     x instanceof X    
==>  x.getClass()==X.class  
==>  x.classID == constant_X_ID

The main cost is just a read!

If X does have subclasses loaded, a few more reads are needed; they are likely co-located so the extra cost is very low too.

Good news everyone!

irreputable
  • 44,725
  • 9
  • 65
  • 93
  • 2
    *can* be optimized or *is* optimized? source? –  Feb 09 '15 at 21:23
  • @vaxquis _can_ as its jvm impl specific – RecursiveExceptionException Aug 19 '16 at 22:35
  • 1
    @itzJanuary *sigh* you missed the point of my question here: everybody knows that compiler *can* optimize `foo` - but *is `foo` actually currently optimized by Oracle's javac/VM - or is it just possible that it'll do that in the future?* Also, I asked the answerer *does he have any backing source (be it docs, source code, dev blog) documenting that it indeed can be optimized or is optimized*? Without it, this answer is just some random musing about what compiler *can* possibly do. –  Aug 21 '16 at 19:43
  • @vaxquis You never mentioned the Hotspot VM but in that case I do not know if it is "optimized". – RecursiveExceptionException Aug 22 '16 at 13:59
  • 2
    Recently read that JIT (JVM 8) will optimize a call site for 1 or 2 types by direct calls, but reverts to the vtable if more than two actual types are encountered. So only having two concrete types passing through a call site at runtime represents a performance advantage. – simon.watts Jan 17 '17 at 18:44
6

instanceof is probably going to be more costly than a simple equals in most real world implementations (that is, the ones where instanceof is really needed, and you can't just solve it by overriding a common method, like every beginner textbook as well as Demian above suggest).

Why is that? Because what is probably going to happen is that you have several interfaces, that provide some functionality (let's say, interfaces x, y and z), and some objects to manipulate that may (or not) implement one of those interfaces... but not directly. Say, for instance, I have:

w extends x

A implements w

B extends A

C extends B, implements y

D extends C, implements z

Suppose I am processing an instance of D, the object d. Computing (d instanceof x) requires to take d.getClass(), loop through the interfaces it implements to know whether one is == to x, and if not do so again recursively for all of their ancestors... In our case, if you do a breadth first exploration of that tree, yields at least 8 comparisons, supposing y and z don't extend anything...

The complexity of a real-world derivation tree is likely to be higher. In some cases, the JIT can optimize most of it away, if it is able to resolve in advance d as being, in all possible cases, an instance of something that extends x. Realistically, however, you are going to go through that tree traversal most of the time.

If that becomes an issue, I would suggest using a handler map instead, linking the concrete class of the object to a closure that does the handling. It removes the tree traversal phase in favor of a direct mapping. However, beware that if you have set a handler for C.class, my object d above will not be recognized.

here are my 2 cents, I hope they help...

5

Instanceof is very fast. It boils down to a bytecode that is used for class reference comparison. Try a few million instanceofs in a loop and see for yourself.

Apocalisp
  • 34,834
  • 8
  • 106
  • 155
5

instanceof is very efficient, so your performance is unlikely to suffer. However, using lots of instanceof suggests a design issue.

If you can use xClass == String.class, this is faster. Note: you don't need instanceof for final classes.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
5

I write a performance test based on jmh-java-benchmark-archetype:2.21. JDK is openjdk and version is 1.8.0_212. The test machine is mac pro. Test result is:

Benchmark                Mode  Cnt    Score   Error   Units
MyBenchmark.getClasses  thrpt   30  510.818 ± 4.190  ops/us
MyBenchmark.instanceOf  thrpt   30  503.826 ± 5.546  ops/us

The result shows that: getClass is better than instanceOf, which is contrary with other test. However, I don't know why.

The test code is below:

public class MyBenchmark {

public static final Object a = new LinkedHashMap<String, String>();

@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean instanceOf() {
    return a instanceof Map;
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean getClasses() {
    return a.getClass() == HashMap.class;
}

public static void main(String[] args) throws RunnerException {
    Options opt =
        new OptionsBuilder().include(MyBenchmark.class.getSimpleName()).warmupIterations(20).measurementIterations(30).forks(1).build();
    new Runner(opt).run();
}
}
salexinx
  • 99
  • 1
  • 4
  • If I was to speculate, what instanceof does is arguably more complex. A getClass() == check will do a precise 1:1 check, where instanceof checks a hierarchy i.e. myHashSet instanceof Collection would pass, but myHashSet.getClass() == Collection.class would not. Essentially, they are not equivalent operations, so I am not too surprised that the performance is different as well. – Alexander Terp Jun 02 '20 at 01:17
4

Generally the reason why the "instanceof" operator is frowned upon in a case like that (where the instanceof is checking for subclasses of this base class) is because what you should be doing is moving the operations into a method and overridding it for the appropriate subclasses. For instance, if you have:

if (o instanceof Class1)
   doThis();
else if (o instanceof Class2)
   doThat();
//...

You can replace that with

o.doEverything();

and then have the implementation of "doEverything()" in Class1 call "doThis()", and in Class2 call "doThat()", and so on.

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
  • 14
    But sometimes you can't. If you're implementing an interface that has you taking in an Object, and you need to tell which type it is, then instanceof is really the only option. You could try casting, but instanceof is generally cleaner. – Herms Sep 19 '08 at 17:29
4

'instanceof' is actually an operator, like + or -, and I believe that it has its own JVM bytecode instruction. It should be plenty fast.

I should not that if you have a switch where you are testing if an object is an instance of some subsclass, then your design might need to be reworked. Consider pushing the subclass-specific behavior down into the subclasses themselves.

Tim Frey
  • 9,901
  • 9
  • 44
  • 60
4

It's hard to say how a certain JVM implements instance of, but in most cases, Objects are comparable to structs and classes are as well and every object struct has a pointer to the the class struct it is an instance of. So actually instanceof for

if (o instanceof java.lang.String)

might be as fast as the following C code

if (objectStruct->iAmInstanceOf == &java_lang_String_class)

assuming a JIT compiler is in place and does a decent job.

Considering that this is only accessing a pointer, getting a pointer at a certain offset the pointer points to and comparing this to another pointer (which is basically the same as testing to 32 bit numbers being equal), I'd say the operation can actually be very fast.

It doesn't have to, though, it depends a lot on the JVM. However, if this would turn out to be the bottleneck operation in your code, I'd consider the JVM implementation rather poor. Even one that has no JIT compiler and only interprets code should be able to make an instanceof test in virtually no time.

Mecki
  • 125,244
  • 33
  • 244
  • 253
  • 1
    Doesn't it have to figure out if o inherits from java.lang.String? – WW. Feb 02 '09 at 08:08
  • 1
    That's why I said it "might" be as fast. In reality it performs a loop, first checking iAmInstanceOf against the class in question, then it goes upwards the inheritance tree of o and repeating this check for every super-class of o (so it it might have to run this loop a couple of times for a match) – Mecki Feb 02 '09 at 17:41
4

Demian and Paul mention a good point; however, the placement of the code to execute really depends on how you want to use the data...

I'm a big fan of small data objects that can be used in many ways. If you follow the override (polymorphic) approach, your objects can only be used "one way".

This is where patterns come in...

You can use double-dispatch (as in the visitor pattern) to ask each object to "call you" passing itself -- this will resolve the type of the object. However (again) you'll need a class that can "do stuff" with all of the possible subtypes.

I prefer to use a strategy pattern, where you can register strategies for each subtype you want to handle. Something like the following. Note that this only helps for exact type matches, but has the advantage that it's extensible - third-party contributors can add their own types and handlers. (This is good for dynamic frameworks like OSGi, where new bundles can be added)

Hopefully this will inspire some other ideas...

package com.javadude.sample;

import java.util.HashMap;
import java.util.Map;

public class StrategyExample {
    static class SomeCommonSuperType {}
    static class SubType1 extends SomeCommonSuperType {}
    static class SubType2 extends SomeCommonSuperType {}
    static class SubType3 extends SomeCommonSuperType {}

    static interface Handler<T extends SomeCommonSuperType> {
        Object handle(T object);
    }

    static class HandlerMap {
        private Map<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>> handlers_ =
            new HashMap<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>>();
        public <T extends SomeCommonSuperType> void add(Class<T> c, Handler<T> handler) {
            handlers_.put(c, handler);
        }
        @SuppressWarnings("unchecked")
        public <T extends SomeCommonSuperType> Object handle(T o) {
            return ((Handler<T>) handlers_.get(o.getClass())).handle(o);
        }
    }

    public static void main(String[] args) {
        HandlerMap handlerMap = new HandlerMap();

        handlerMap.add(SubType1.class, new Handler<SubType1>() {
            @Override public Object handle(SubType1 object) {
                System.out.println("Handling SubType1");
                return null;
            } });
        handlerMap.add(SubType2.class, new Handler<SubType2>() {
            @Override public Object handle(SubType2 object) {
                System.out.println("Handling SubType2");
                return null;
            } });
        handlerMap.add(SubType3.class, new Handler<SubType3>() {
            @Override public Object handle(SubType3 object) {
                System.out.println("Handling SubType3");
                return null;
            } });

        SubType1 subType1 = new SubType1();
        handlerMap.handle(subType1);
        SubType2 subType2 = new SubType2();
        handlerMap.handle(subType2);
        SubType3 subType3 = new SubType3();
        handlerMap.handle(subType3);
    }
}
Scott Stanchfield
  • 29,742
  • 9
  • 47
  • 65
3

I'll get back to you on instanceof performance. But a way to avoid problem (or lack thereof) altogether would be to create a parent interface to all the subclasses on which you need to do instanceof. The interface will be a super set of all the methods in sub-classes for which you need to do instanceof check. Where a method does not apply to a specific sub-class, simply provide a dummy implementation of this method. If I didn't misunderstand the issue, this is how I've gotten around the problem in the past.

Jose Quijada
  • 558
  • 6
  • 13
2

In modern Java version the instanceof operator is faster as a simple method call. This means:

if(a instanceof AnyObject){
}

is faster as:

if(a.getType() == XYZ){
}

Another thing is if you need to cascade many instanceof. Then a switch that only call once getType() is faster.

Horcrux7
  • 23,758
  • 21
  • 98
  • 156
1

InstanceOf is a warning of poor Object Oriented design.

Current JVMs do mean the instanceOf is not much of a performance worry in itself. If you are finding yourself using it a lot, especially for core functionality, it is probably time to look at the design. The performance (and simplicity/maintainability) gains of refactoring to a better design will greatly outweigh any actual processor cycles spent on the actual instanceOf call.

To give a very small simplistic programming example.

if (SomeObject instanceOf Integer) {
  [do something]
}
if (SomeObject instanceOf Double) {
  [do something different]
}

Is a poor architecture a better choice would have been to have SomeObject be the parent class of two child classes where each child class overrides a method (doSomething) so the code would look as such:

Someobject.doSomething();
Demian Krige
  • 163
  • 3
  • 62
    I'm aware of that. That was not what I asked. – Josh Oct 06 '08 at 14:35
  • Unsure of whether to vote this up or not as it is a good point, but doesn't answer the question asked ... – jklp Nov 12 '08 at 00:09
  • 7
    I think the code example is actually a very bad one: You cannot extend the class Double, and also you cannot derive Double from some other class. If you had used other classes for the example, it would have been ok. – Lena Schimmel Jan 07 '09 at 16:16
  • 6
    Also if the child classes of SomeObject are value objects, then you don't want to put the logic in them. E.g. Pie and Roast might not be the correct place for putInOven() and putInMouth() logic. – sk. Jan 27 '09 at 18:34
  • self cooking pie and roast would be awesome though – binboavetonik Sep 07 '17 at 10:44
1

If speed is your sole aim then using int constants to identify sub classes seems to shave a milliseconds of the time

static final int ID_A = 0;
static final int ID_B = 1;
abstract class Base {
  final int id;
  Base(int i) { id = i; }
}
class A extends Base {
 A() { super(ID_A); }
}
class B extends Base {
 B() { super(ID_B); }
}
...
Base obj = ...
switch(obj.id) {
case  ID_A: .... break;
case  ID_B: .... break;
}

terrible OO design, but if your performance analysis indicates this is where you bottleneck is then maybe. In my code the dispatch code takes 10% of total execution time and this maybe contributed to a 1% total speed improvement.

Salix alba
  • 7,536
  • 2
  • 32
  • 38
0

You should measure/profile if it's really a performance issue in your project. If it is I'd recommend a redesign - if possible. I'm pretty sure you can't beat the platform's native implementation (written in C). You should also consider the multiple inheritance in this case.

You should tell more about the problem, maybe you could use an associative store, e.g. a Map<Class, Object> if you are only interested in the concrete types.

Karl
  • 3,170
  • 1
  • 21
  • 28
0

I also prefer an enum approach, but I would use a abstract base class to force the subclasses to implement the getType() method.

public abstract class Base
{
  protected enum TYPE
  {
    DERIVED_A, DERIVED_B
  }

  public abstract TYPE getType();

  class DerivedA extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_A;
    }
  }

  class DerivedB extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_B;
    }
  }
}
mike
  • 4,929
  • 4
  • 40
  • 80
0

I thought it might be worth submitting a counter-example to the general consensus on this page that "instanceof" is not expensive enough to worry about. I found I had some code in an inner loop that (in some historic attempt at optimization) did

if (!(seq instanceof SingleItem)) {
  seq = seq.head();
}

where calling head() on a SingleItem returns the value unchanged. Replacing the code by

seq = seq.head();

gives me a speed-up from 269ms to 169ms, despite the fact that there are some quite heavy things happening in the loop, like string-to-double conversion. It's possible of course that the speed-up is more due to eliminating the conditional branch than to eliminating the instanceof operator itself; but I thought it worth mentioning.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • This might be because of the `if` itself. If the distribution of `true`s and `false`s is close to even, speculative execution becomes useless, which leads to significant lags. – Dmytro Sep 05 '18 at 08:41
0

With regard to Peter Lawrey's note that you don't need instanceof for final classes and can just use a reference equality, be careful! Even though the final classes cannot be extended, they are not guaranteed to be loaded by the same classloader. Only use x.getClass() == SomeFinal.class or its ilk if you are absolutely positive that there is only one classloader in play for that section of code.

-5

You're focusing on the wrong thing. The difference between instanceof and any other method for checking the same thing would probably not even be measurable. If performance is critical then Java is probably the wrong language. The major reason being that you can't control when the VM decides it wants to go collect garbage, which can take the CPU to 100% for several seconds in a large program (MagicDraw 10 was great for that). Unless you are in control of every computer this program will run on you can't guarantee which version of JVM it will be on, and many of the older ones had major speed issues. If it's a small app you may be ok with Java, but if you are constantly reading and discarding data then you will notice when the GC kicks in.

tloach
  • 8,009
  • 1
  • 33
  • 44
  • 8
    That is much less true of the more modern java garbage collection algorithms than it ever used to be. Even the simplest algorithms don't care any more how much memory you discard just after you useit - they only care how much is retained across young-generation collections. – Bill Michell Sep 23 '08 at 14:34
  • 3
    Great, except I'm on the most recent JVM and my computer still crawls when the GC runs. On a dual-core, 3GB ram server. Java is not a language to use if performance actually matters. – tloach Oct 08 '08 at 00:20
  • @David: You don't need require real-time to have issues when your app goes away for a period of time. A fun one I've encountered is a java app that connected to a TCP stream that died when the GC ran because it didn't close the stream first and couldn't handle the overload of network traffic when it came back - it would immediately go into a loop where GC runs, when app resumes it tries to churn through a bunch of data, which made it run out of memory, which triggered the GC, etc. Java is great for a lot of tasks, but not tasks where very strong performance is a requirement. – tloach Oct 28 '11 at 13:04
  • 8
    @tloach sounds to me like bad app design. you talk about "performance" as if it was one-dimensional. I've worked with (and on) plenty of java apps that were, for instance, performant in providing snappy interactive statistical analysis and visualization of very large data sets, or performant in processing very large transaction volumes very quickly. "performance" isn't just one thing, and the fact that someone can write an application that manages memory badly and lets GC get in its own way doesn't mean anything requiring "performance" should be written in something else. – David Moles Nov 01 '11 at 22:25