[英]Does a Java compiler optimize ad hoc instances of `Set.of`, `List.of`, and `Map.of` in loops as constants
给定以下代码片段,其中创建了一个Set
的临时实例,今天的 Java 编译器会看到他们不需要为每个循环传递创建实例并将set
优化为一种最终常量,这样实例就是整个循环都一样吗? 这个问题同样适用于while
和do while
循环。
for (/* a loop that iterates quite often */)
{
var set = Set.of("foo", "blah", "baz");
// Do something with the set.
}
我也很感兴趣这样的优化是否已经在编译时完成(意味着字节码已经被优化)或者是否存在运行时优化(由即时编译器进行)基本上实现相同。
如果编译器没有看到这一点,唯一的选择似乎是在循环外实例化set
以达到最佳效果:
var set = Set.of("foo", "blah", "baz");
for (/* a loop that iterates quite often */)
{
// Do something with the set.
}
旁注,对于那些发现第一个片段相当糟糕的做法并且无论如何都会像第二个片段一样编写它的人:这个片段实际上是我的真实用例的简化变体,出于问题的简单原因而制作。 让我想到这个问题的真正的、稍微复杂一点的用例如下,其中需要检查一个字符串是否是极少数字符串之一:
for (/* a loop that iterates quite often */)
{
// ...
var testString = // some String to check ...
if (Set.of("foo", "blah", "baz").contains(testString))
{
// Do something.
}
// ...
}
假设if
条件被附加代码包围(即循环体相当大),我认为人们希望将集合声明为内联而不是在循环之外更远。
答案将不可避免地取决于您使用的 Java 工具。
javac
字节码编译器(故意)天真,我不希望它对此进行任何优化。 JVM 的 JIT 编译器可能会对此进行优化,但这取决于:
/* do something with the set */
实际上需要。如果这对您真的很重要,我会建议几种方法。
自己重写代码以将Set
声明提升到循环之外。 IMO,这种方法根本没有错,尽管它可能是过早的优化。 (我可能会在你给出的例子中自己这样做。这对我来说“感觉正确”。)
使用 JVM 选项转储 JIT 编译器生成的本机代码,看看它实际上做了什么。 但请注意,结果可能会有所不同:见上文。
但是,即使您非常确定地知道编译器将如何工作,也不清楚您是否应该普遍担心这一点。
注意用javap -c
查看字节码会告诉你java
编译器是否正在做任何优化。 (或者更有可能,确认它不是。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.