每次我必须将int
转换为String
,我选择了""+a
或Integer.toString(a)
。现在我想知道哪种方式更快,所以我编写了一个简单的基准测试,调用function_1,function_2和function_3 10000000次并打印处理函数所需的时间。以下是功能:
public static String i="";
public static String j="";
public static String k="";
public static void function_1()
{
i=Integer.toString(getOne());
}
public static void function_2()
{
j=""+1;
}
public static void function_3()
{
j=""+getOne();
}
public static int getOne()
{
return 1;
}
输出是:
Benchmarking starting...
Executing function_1 10000000 time(s)...
Done executing function_1 in 476 ms.
Executing function_2 10000000 time(s)...
Done executing function_2 in 8 ms.
Executing function_3 10000000 time(s)...
Done executing function_3 in 634 ms.
Benchmarking complete!
我认为function_2太快了,因为它编译为
public static void function_2()
{
j="1";
}
为避免这种情况,我使用了函数getOne()
。但这是有趣的部分(对我来说):function_3
必须在不使用toString
的原始Object
方法的情况下进行编译(在这种情况下为Integer.toString(1)
,因为int
是原始的)。我的问题是:编译器如何实际威胁""+1
,因此它比调用Integer.toString(1)
要慢?
答案 0 :(得分:4)
""
和1
在编译时是已知的。这就是function_2
"" + 1
在转换为字节码时真正被"1"
取代的原因。
getOne()
结果在编译时是未知的,因此连接将在运行时完成。但是因为连接(+)效率不高,编译器可能会将此更改为基于StringBuilder.append()
的实现。
不相信我?尝试:javap -c ClassName.class
,您会看到类似的内容:
public static void function_2();
Code:
0: ldc #39 // String 1
2: putstatic #16 // Field j:Ljava/lang/String;
5: return
public static void function_3();
Code:
0: new #42 // class java/lang/StringBuilder
3: dup
4: invokespecial #44 // Method java/lang/StringBuilder."<init>":()V
7: invokestatic #28 // Method getOne:()I
10: invokevirtual #45 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
13: invokevirtual #49 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
16: putstatic #16 // Field j:Ljava/lang/String;
19: return
function_2()
只有一个字符串“1”,而function_3包含所有这些方法调用,其中包含额外的StringBuilder:)
请记住,某些优化可能在运行时发生,但这种行为是JVM,它依赖于配置。
答案 1 :(得分:1)
我在10,000,000次迭代中测试了以下函数:
public static void no_func_maybe_constant()
{
j= "" + 1;
}
public static void no_func_no_constant()
{
j = "";
j = j + 1;
}
public static void yes_func_maybe_constant()
{
j = "" + getOne();
}
public static void yes_func_no_constant()
{
j = "";
j = j + getOne();
}
我的结果:
no_func_maybe_constant Took 0.028058674s
no_func_no_constant Took 1.449465242s
yes_func_maybe_constant Took 1.275561897s
yes_func_no_constant Took 1.263362257s
不调用函数和调用函数之间的区别确实可以忽略不计,因此在"" + 1
的情况下,它确实在进行一些编译时常量计算。有趣的是,如果没有功能,它有时会花费更少的时间......
答案 2 :(得分:0)
2和3之间的差异可能是由于必须调用方法来获取整数。当你调用一个方法时,它会创建一个新的激活记录,这会使调用堆栈变得复杂,所以除非JVM的JIT能够内联静态函数调用只返回单个返回值(这里几乎肯定不会发生),否则会有更多的事情发生。