Java 中的字符串与长性能

String vs long performance in Java

正如我在另一个问题中读到的,int 的性能比 long 好得多,比 string 的性能好一点。

假设我有一个大于 int 的数字,我想用它来与类似的数字进行比较:对于这种情况,哪种类型的变量具有更好的性能?长还是字符串?

例如比较 111.222.333.444 和 555.666.777.888:

long x = 111222333444;
long y = 555666777888;
if(x == y){ /*code*/ }

VS

string x = "111222333444";
string y = "555666777888";
if(x.equals(y)){ /*code*/ }

哪种情况下表现最好?差异显着?

long 会更快——在 64 位平台上,它会和 int 一样快。但除非这是一个非常紧密的循环,否则它可能不会对您的应用程序整体产生任何重大影响。微优化的第一条规则是:不要。

我写了一个快速的 JMH 基准来测试 int、long 和 String 比较,下面是我笔记本电脑上的结果:

EqualityComparisons.cInt     avgt  100  0.004 ±  0.001  us/op
EqualityComparisons.cLong    avgt  100  0.006 ±  0.001  us/op
EqualityComparisons.cString  avgt  100  0.011 ±  0.001  us/op

基准测试的相关位是:

@Setup
public void setup() {
  one = (int) System.nanoTime();
  two = QuickRand.next(one);
  oneS = String.format("%11d", one);
  twoS = String.format("%11d", two);
  oneL = one;
  twoL = two;
}

@Benchmark
public boolean cInt() { return one == two; }

@Benchmark
public boolean cLong() { return oneL == twoL; }

@Benchmark
public boolean cString() { return oneS.equals(twoS); }

注意几点:

  • long 和 int 差不多快 -- 在误差范围内
  • 字符串速度大约慢 2.75 倍
  • 即使是那些慢速字符串,每次比较也需要大约 0.011 微秒,这意味着您每秒可以执行大约 1 亿个字符串。换句话说,这并不重要。

As I read in another questions, int has a much better performance than a long ...

嗯,你读到的可能是错误的。或者更有可能的是,您从阅读的内容中理解的内容是错误的。

的确,在某些机器上 long 的算术运算可能 比类似的 int 运算花费更长的时间。但是在现代机器上,可能没有区别(对于算术本身),即使有区别也只有 1 或 2 个时钟周期;即纳秒。

所以“好多了”是夸张。

... and a little better performance than a string.

这也是错误的。事实上,对 int 值的操作将比对 String 对象的操作快很多。例如,考虑

String x = "111222333444";
String y = "555666777888";
if (x.equals(y)) { /*code*/ }

equals 方法将执行以下操作:

  1. 测试是否 x == y 和 return true 如果是。
  2. 测试 y 是否为字符串,如果不是 return false
  3. 测试 2 个字符串的长度是否相同,如果不相同,return false
  4. 遍历字符串中的字符,比较相同位置的字符,如果不相等则returning false
  5. Return true 如果循环结束但没有找到不相等的字符。

加上方法调用的开销(太大而无法内联)。

我们正在谈论(我估计)至少 20 到 30 条机器指令,如果两个字符串相等,或者在开始时相等,则更多。

相比之下,x == y 使用 intlong 只是一条指令1.


不过,这里还有一个更大的问题。

很可能您实际上是在这里浪费时间。除非您对 数百万 个数字执行这些操作,否则性能差异可能不会很明显。

我的建议是:

  • 除非必须,否则不要优化。
  • 除非万不得已,否则不要这种事情。
  • 如果您确实必须这样做(即您有真实的、硬性的性能数据表明您的代码太慢),那么请科学地进行。编写一些涉及 运行 >>真实<< 代码的基准测试 >>真实<< 数据,并使用配置文件找出代码实际花费大部分时间的地方。然后只优化那部分代码。

1 - 我不是指令级性能方面的专家,但 this document 似乎是说英特尔 CMP 指令需要 1、2 或 3 个时钟周期。