简体   繁体   中英

Does a Java compiler optimize ad hoc instances of `Set.of`, `List.of`, and `Map.of` in loops as constants

Given the following code snippet in which an ad hoc instance of a Set is created, will todays Java compiler see that they do not need to create the instance for each loop pass and optimize set as a kind of final constant such that the instance is the same for the entire loop? The question applies similarly to while and do while loops.

for (/* a loop that iterates quite often */)
{
   var set = Set.of("foo", "blah", "baz");
   // Do something with the set.
}

I would also be interested whether such an optimization is done already at compile-time (meaning that the byte code is already optimized) or whether there exist runtime optimizations (made by the just-in-time compiler) that essentially achieve the same.

If a compiler does not see this, the only option seems to instantiate the set outside the loop in order to be optimal:

var set = Set.of("foo", "blah", "baz");
for (/* a loop that iterates quite often */)
{
   // Do something with the set.
}

Side note , for those finding the first snippet rather bad practice and that would write it like the second snippet anyway: This snippet is actually a simplified variant of my real use case, made for simplicity reasons of the question. The real, slightly more complex use case that brought me to this question is the following, where a string needs to be checked whether it is one of a very few strings:

for (/* a loop that iterates quite often */)
{

   // ...

   var testString = // some String to check ...
   if (Set.of("foo", "blah", "baz").contains(testString))
   {
      // Do something.
   }

   // ...

}

Assuming that the if condition is surrounded by additional code (ie, the loop body is rather large), I think one wants to declare the set inline rather than further away outside the loop.

The answer will inevitably depend on the Java tools that you use.

The javac bytecode compiler is (deliberately) naive, and I would not expect it to do any optimization of this. The JVM's JIT compiler may optimize this, but that will depend on:

  • your Java version,
  • the JIT compiler tier used
  • what /* do something with the set */ actually entails.

If this really matters to you, I would advise a couple of approaches.

  1. Rewrite the code yourself to hoist the Set declaration out of the loop. IMO, there is nothing fundamentally wrong with this approach, though it is potentially a premature optimization. (I'd probably do this myself in the examples you gave. It just "feels right" to me.)

  2. Use the JVM options for dumping out the native code produced by the JIT compiler and see what it actually does. But beware that the results are liable to vary: see above.

But even if you know with a good degree of certainty how the compilers will do, it is not clear that you should be worrying about this in general .


Note looking at the bytecodes with javap -c will tell you if the java compiler is doing any optimization. (Or more likely, confirm that it isn't.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM