3

I have the following code in my app:

  public static final boolean DEBUG = true;
  public static final boolean REL = !DEBUG;

  private static final String DEBUG_OR_RELEASE = (REL) ? "RELEASE_VER" : "DEBUG_VER";

I thought that the Java compiler will eliminate the "DEBUG_VER" string completely from the resulting .apk file (when exported via Proguard) but when I examine the .apk file, I see the "DEBUG_VER" string in there.

Why? What am I missing? What did I do wrong?

ateiob
  • 9,016
  • 10
  • 44
  • 55
  • Well, if you don't think you should see "RELEASE_VER" then presumably you're compiling for debug, and generally such optimizations are disabled in debug mode. – Hot Licks Jan 29 '12 at 02:20
  • Besides which, even if the statement is optimized away it's likely that the string literal would be left in the constant pool. It's basically harmless. – Hot Licks Jan 29 '12 at 02:21
  • `DEBUG_OR_RELEASE = (REL) ? "DEBUG_VER" : "DEBUG_VER"`? Really? Post your real code please. – erickson Jan 29 '12 at 03:53
  • `DEBUG_OR_RELEASE = (REL) ? "DEBUG_VER" : "DEBUG_VER" ` gives the same string DEBUG_VER whether REL is true or false. Have you noticed that? – Ravi Bhatt Jan 29 '12 at 04:02
  • @Ravi Bhatt Sorry, I posted this hastily so I had this stupid typo. Corrected now. – ateiob Jan 29 '12 at 04:17
  • @ateiob here your DEBUG is true, hence REL is false, so `DEBUG_OR_RELEASE = (REL) ? "RELEASE_VER" : "DEBUG_VER"` will assign DEBUG_VER to DEBUG_OR_RELEASE string dear. :) – Ravi Bhatt Jan 29 '12 at 05:23

3 Answers3

3

Compilation to java bytecode is not making optimization (except a very few exceptions).

Many books state for simplification that the 'compilation' phase is when optimization occurs, but it is wrong. When the optimization really takes place, is while bytecode files are processed by JVM. So for the clearance: optimization may occur at the time of compilation bytecode to machine native code, which is done by JVM tools.

Sometimes there is no optimization at all (JVM works in interpreting mode). Sometimes there is some optimization made by JIT (Just In Time complier). And sometimes adaptative optimizer takes care of the optimization (not only optimizing but also profiling code execution in case of additional operations to be performed).

So finally, there is nothing wrong with your file. It's just how java world works.

"But why?" -- you may ask. The reason to keep this 'useless' information in bytecode is because you would never be sure how many code can you eliminate so the optimization provided by different JVM could still work efficient. The best way is just to not erase any information and let the optimizers to do their job.

msi
  • 2,609
  • 18
  • 20
  • `When the optimization really takes place, is while bytecode files are loaded to JVM` - that's somewhat misleading and also inconsistent with what you say later. The JIT does not optimize a method as it is loaded, but only after it has been executed a certain number of times in interpreted mode. (horrible simplification that) – Voo Jan 29 '12 at 02:35
  • Made a small edit to make it more correct, but I'm still aware that making any simplifications here may be misleading. – msi Jan 29 '12 at 02:44
  • @msi Thanks. This makes sense but in my case I *do* want to remove the "DEBUG_VER" string from the release APK. How can I accomplish that? – ateiob Jan 29 '12 at 02:48
  • Yeah it's impossible to cover the whole topic in a few hundred words so we'll have to live with simplifications. But the change in words makes it consistent with the rest of the argument and it does touch on the important points so +1 – Voo Jan 29 '12 at 02:48
1

It's still being run even when the variable is set to true. ?: statements are part of executable and operational code, and since Java doesn't have a precompiler, it will be run every time you compile.

Java does not infer and simplify operations automatically, even if logically the operations are the same each iteration.

  • Thanks but according to [this](http://stackoverflow.com/a/1813873) it should be possible. Is that answer incorrect? – ateiob Jan 29 '12 at 02:45
  • I think he meant you would produce the same result, not remove it from the compilation. But if I'm mistaken, then yes, that answer is incorrect. –  Jan 29 '12 at 02:49
  • Even without a preprocessor, Java compilers do (and in some cases must) remove obviously unreachable code, e.g. with a condition based on a final boolean that is false. It is discussed in the Java Language Specification, section 14.21, and it can easily be verified in practice. – Eric Lafortune Jan 29 '12 at 10:13
  • Unreachable code is removed, but I'm not certain about code which is reachable, but produces the same final result each instance. I could very easily be wrong, though. –  Jan 29 '12 at 18:31
1

According to what you posted, DEBUG is true, so REL is false, so (REL) ? "RELEASE_VER" : "DEBUG_VER" should yield "DEBUG_VER".

This is exactly what you are observing so if you are expecting to see "RELEASE_VER" instead, you should set:

public static final boolean DEBUG = false;

Try that and see what happens.

Regex Rookie
  • 10,432
  • 15
  • 54
  • 88
  • Thanks, that worked. Which means I now have to remember to change `boolean DEBUG` to *false* whenever I export a release version. Ouch. – ateiob Jan 29 '12 at 06:12