在我们的代码中,我们经常使用Preconditions
检查参数:
Preconditions.checkArgument(expression, "1" + var + "3");
但有时,这段代码经常被调用。这会对性能产生显着的负面影响吗?我们应该切换到
Preconditions.checkArgument(expression, "%s%s%s", 1, var, 3);
(我希望大多数时候情况都是正确的。虚假意味着错误。)
答案 0 :(得分:5)
如果您希望检查在大多数情况下不抛出任何异常,则没有理由使用字符串连接。在您调用该方法之前,您将失去更多时间连接(使用.concat
或StringBuilder
),而不是在您确定要引发异常之后进行连接。
相反,如果您要抛出异常,那么您已经在慢分支中。
值得一提的是,Guava使用的是自定义且速度更快的格式化程序,仅接受%s
。因此,时间损失实际上更类似于标准记录器{}
句柄(在slf4j或log4j 2中)。但如上所述,这就是你已经处于慢速分支的情况。
无论如何,我强烈建议您反对任何建议,但我会改用此建议:
Preconditions.checkArgument(expression, "1%s3", var);
你应该只在%s
中放置变量,而不是常数来获得边际速度。
答案 1 :(得分:1)
在String
字面串联的情况下,编译器应该在编译时执行此操作,因此不会发生运行时性能损失。至少标准JDK这样做,它不是每个规范(所以一些编译器可能不优化这个)。
在变量的情况下,常量折叠不起作用,因此将在运行时工作。但是,较新的Java编译器会将字符串连接替换为StringBuilder
,这应该更有效,因为它不是不可变的,与String
不同。
如果调用格式化程序,这应该比使用格式化程序更快。但是,如果你不经常调用它,那么这可能会变慢,因为连接总是发生,即使参数为真,并且该方法什么都不做。
无论如何,要把它包起来:我不认为重写现有的电话是值得的。但是,在新代码中,您可以毫无疑问地使用格式化程序。
答案 2 :(得分:0)
Here is one sample result:
started with 10000000 calls and 100 runs
formatter: 0.94 (mean per run)
string: 181.11 (mean per run)
Formatter is 192.67021 times faster. (this difference grows with number of calls)
这是代码(Java 8,Guava 18):
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
public class App {
public static void main(String[] args) {
int count = 10000000;
int runs = 100;
System.out.println("started with " + count + " calls and " + runs + "runs");
Stopwatch stopwatch = Stopwatch.createStarted();
run(count, runs, i->fast(i));
stopwatch.stop();
float fastTime = (float)stopwatch.elapsed(TimeUnit.MILLISECONDS)/ runs;
System.out.println("fast: " + fastTime + " (mean per run)");
//
stopwatch.reset();
System.out.println("reseted: "+stopwatch.elapsed(TimeUnit.MILLISECONDS));
stopwatch.start();
run(count, runs, i->slow(i));
stopwatch.stop();
float slowTime = (float)stopwatch.elapsed(TimeUnit.MILLISECONDS)/ runs;
System.out.println("slow: " + slowTime + " (mean per run)");
float times = slowTime/fastTime;
System.out.println("Formatter is " + times + " times faster." );
}
private static void run(int count, int runs, Consumer<Integer> function) {
for(int c=0;c<count;c++){
for(int r=0;r<runs;r++){
function.accept(r);
}
}
}
private static void slow(int i) {
Preconditions.checkArgument(true, "var was " + i);
}
private static void fast(int i) {
Preconditions.checkArgument(true, "var was %s", i);
}
}