ARTICLE AD BOX
Does Java perform any optimization to avoid repeated method calls?
No, and, there's something fundamental here:
In java, the signature is separate from the implementation.
You are free to change the implementation later. This will not require recompilation of callers. If you're used to C, this is fundamentally different: in C there is no difference; the end product is a fully compiled binary that is indivisible: You can't mix and match parts (but you could, if you're using DLLs / solibs / dynamic libraries, which is going a little too deep for this question).
In other words, imagine that today your getFoo() method is this:
public int getFoo() { return 5; }And you write int x = getFoo(); int y = getFoo();. You may think: Java should notice i'm calling the same thing twice in a row and optimize by just calling that method once and re-using the result.
But that'd be wrong. Because tomorrow that method might turn into:
public int getFoo() { return random.nextInt(6); }Here, the method is not stable - calling it repeatedly does not produce the same result. If java were to compile your code by calling getFoo() only once, that'd be terrible. I'll show you why by only changing the names of methods:
public int rollDie() { return random.nextInt(6); } int player1Roll = rollDie(); int player2Roll = rollDie();Now you should see why, if java spec says that this means rollDie() is invoked only once and will then 're use' the result, that'd mean java is a useless piece of garbage.
Thus, some highlights:
Javac does not know what the content of a method is. Callers only take into account the signature (the bit before the open bracket that begins the method body). The output of javac is divisible - you can compile a source tree into 50 class files, and then later on recompile just 5 class files and drop them in, and this works fine. More practically speaking, you can split your project into separate units and ship updated to these separately. Think 'libraries'. It's nice that 'update this dependency' does not involve 'recompile... absolutely everything for all platforms again'. Just because a method starts with get does not mean that it is therefore immutable. Java has no way to convey that you intend for a method to be 'memoized' (that either the compiled version of the method itself gets festooned with a bunch of infrastructure to cache calls, or that callers are free to cache calls / reuse results / 'compress' identical calls down to a single call, reusing the result). There is no 'stable' keyword or some such. ... java goes through 2 compilation steps. First, .java files to .class files, and second, .class files are executed; the JVM keeps track of which parts of the code being executed by this JVM are run a lot and will eventually recompile them into finetuned machine code. Java may conclude that a method is 'stable' and rewrite, but, the whole idea is that you will not be able to tell other than by checking out how long things take. If you were able to tell, the JVM is buggy: Unlike C, optimizations are strictly defined and a JVM is not allowed to inline stuff 'just cuz', unless it can prove that the code cannot possibly observe that the JVM is doing this. Java has no 'hints' about unrolling or inlining nor does it need them (the JVM keeps track of this at runtime and recompiles only the hot paths). Given that you can't tell, you shouldn't worry about it. More generally, trying to figure out if some code 'performs well' by using your eyeballs is a terrible idea. Use a profiler instead. Especially for the JVM. The java lang spec has virtually no flexibility in it - every operation is specced out exactingly. Except for thread interaction, where 'a JVM has many options' is all over it. For example, foo() ? bar() : baz() is guaranteed to first evaluate foo, and then only evaluate bar() or baz() depending on the result of evaluating foo(). A JVM is allowed to reorder only if it can guarantee that it not possible for the code to notice that it did this (i.e. it is allowed to evaluate bar() and baz() in parallel whilst waiting for foo() to give a value, only if bar() and baz() have no observable (by code) effects whatsoever. Excluding 'how long does it take'). Do not get into a habit of storing everything into local variables to 'optimize' your java code not to call a stable method more than once. Shaving off literally 0.000000000001% of the runtime is.. ridiculous, and in practice the difference is a flat out 0 or even worse. The JVM hotspot compiler recognizes common patterns far better than uncommon ones. Therefore, 'idiomatic java' is the fastest java.