简体   繁体   English

Java 编译器是否将循环中的“Set.of”、“List.of”和“Map.of”的临时实例优化为常量

[英]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?给定以下代码片段,其中创建了一个Set的临时实例,今天的 Java 编译器会看到他们不需要为每个循环传递创建实例并将set优化为一种最终常量,这样实例就是整个循环都一样吗? The question applies similarly to while and do while loops.这个问题同样适用于whiledo while循环。

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:如果编译器没有看到这一点,唯一的选择似乎是在循环外实例化set以达到最佳效果:

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.假设if条件被附加代码包围(即循环体相当大),我认为人们希望将集合声明为内联而不是在循环之外更远。

The answer will inevitably depend on the Java tools that you use.答案将不可避免地取决于您使用的 Java 工具。

The javac bytecode compiler is (deliberately) naive, and I would not expect it to do any optimization of this. javac字节码编译器(故意)天真,我不希望它对此进行任何优化。 The JVM's JIT compiler may optimize this, but that will depend on: JVM 的 JIT 编译器可能会对此进行优化,但这取决于:

  • your Java version,你的 Java 版本,
  • the JIT compiler tier used使用的 JIT 编译器层
  • what /* do something with the set */ actually entails.什么/* do something with the set */实际上需要。

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.自己重写代码以将Set声明提升到循环之外。 IMO, there is nothing fundamentally wrong with this approach, though it is potentially a premature optimization. IMO,这种方法根本没有错,尽管它可能是过早的优化。 (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.使用 JVM 选项转储 JIT 编译器生成的本机代码,看看它实际上做了什么。 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.注意用javap -c查看字节码会告诉你java编译器是否正在做任何优化。 (Or more likely, confirm that it isn't.) (或者更有可能,确认它不是。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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