字符串到int或int到String:哪个更快?

时间:2015-05-28 13:08:32

标签: java performance

我需要将String(有效整数)与int值进行比较。

对于String strint integer,我的选项是:

  1. Integer.parseInt(str) == integer

  2. str.equals(Integer.toString(integer))

  3. 哪一个更快,有没有更好的方法?

    以下是受到atlaste的回答的EqualsIntString的启发

     private static boolean checkEquality(final String string, final long value) {
    
        if (string == null) {
            return false;
        }
        final int length = string.length();
        if (length == 0) {
            return false;
        }
    
        long absValue;
        final byte minIndex;
        if (string.charAt(0) == '-') {
            if (value > 0) {
                return false;
            }
            absValue = -value;
            minIndex = 1;
        } else {
            if (value < 0) {
                return false;
            }
            absValue = value;
            if (string.charAt(0) == '+') {
                minIndex = 1;
            } else {
                minIndex = 0;
            }
        }
    
        for (int idx = length - 1; idx >= minIndex; idx--) {
            final byte rem = (byte) (absValue % 10);
            absValue /= 10;
            final int diff = string.charAt(idx) - rem - 48;
            if (diff != 0) {
                return false;
            }
        }
    
        return absValue == 0;
    }
    

4 个答案:

答案 0 :(得分:4)

只有一种方法可以知道:衡量。

快速JMH基准测试显示Integer.parseInt更快,无论整数的大小如何。但我们谈论的是大约10纳秒左右,并且它不太可能在您的应用程序级别上产生太大的影响。

如果你 100% 确定你的字符串是一个有效的整数,你也可以手动解析它,这会更快(参见{{1}以及下面代码中的parseManual方法。使用哪种方法还取决于您是否期望值通常相等或经常不同(如果它们通常相等,equalsIntString效果更好,如果您希望它们平均不同,parseManual是快)。

因此,数据集的特征在决策中也很重要。

完整结果(得分为每个操作的纳秒数:越小越好) - equalsIntString列是要比较的整数。第一部分是相等的值,第二部分是不等的值。

(n)

代码:

Benchmark                                       (n)  Mode  Samples   Score   Error  Units
c.a.p.SO30507506.manual                           1  avgt       10   6.579 ± 0.131  ns/op
c.a.p.SO30507506.manual                       12345  avgt       10  10.017 ± 0.401  ns/op
c.a.p.SO30507506.manual                   123456789  avgt       10  12.490 ± 0.243  ns/op
c.a.p.SO30507506.manualAtlaste                    1  avgt       10   7.914 ± 0.144  ns/op
c.a.p.SO30507506.manualAtlaste                12345  avgt       10  15.902 ± 0.593  ns/op
c.a.p.SO30507506.manualAtlaste            123456789  avgt       10  28.117 ± 0.463  ns/op
c.a.p.SO30507506.parse                            1  avgt       10   8.495 ± 0.325  ns/op
c.a.p.SO30507506.parse                        12345  avgt       10  21.614 ± 0.564  ns/op
c.a.p.SO30507506.parse                    123456789  avgt       10  34.692 ± 0.572  ns/op
c.a.p.SO30507506.stringEquals                     1  avgt       10  21.597 ± 0.594  ns/op
c.a.p.SO30507506.stringEquals                 12345  avgt       10  36.948 ± 1.144  ns/op
c.a.p.SO30507506.stringEquals             123456789  avgt       10  44.444 ± 1.011  ns/op

c.a.p.SO30507506.manual_unequal                   1  avgt       10   7.011 ± 0.149  ns/op
c.a.p.SO30507506.manual_unequal               12345  avgt       10  10.244 ± 0.350  ns/op
c.a.p.SO30507506.manual_unequal           123456789  avgt       10  13.135 ± 0.797  ns/op
c.a.p.SO30507506.manualAtlaste_unequal            1  avgt       10   4.328 ± 0.111  ns/op
c.a.p.SO30507506.manualAtlaste_unequal        12345  avgt       10   4.359 ± 0.115  ns/op
c.a.p.SO30507506.manualAtlaste_unequal    123456789  avgt       10   4.339 ± 0.103  ns/op
c.a.p.SO30507506.parse_unequal                    1  avgt       10   8.304 ± 0.251  ns/op
c.a.p.SO30507506.parse_unequal                12345  avgt       10  21.514 ± 0.405  ns/op
c.a.p.SO30507506.parse_unequal            123456789  avgt       10  35.257 ± 1.043  ns/op
c.a.p.SO30507506.stringEquals_unequal             1  avgt       10  19.060 ± 0.162  ns/op
c.a.p.SO30507506.stringEquals_unequal         12345  avgt       10  31.829 ± 0.427  ns/op
c.a.p.SO30507506.stringEquals_unequal     123456789  avgt       10  41.870 ± 0.252  ns/op

答案 1 :(得分:1)

有趣的问题。为清楚起见,测试这个问题可能会有很多错误,因为Java会使用可能影响结果的字符串。因此,让我们开始构建一个合适的测试。

构建测试

具体来说:正确的测试并不依赖于loadstring,因为这会影响内存分配。您想使用动态构造的字符串进行测试。

整数的10-log(例如字符串的长度)将影响测试结果。字符串越长,Integer.tryParse将越长。如果你有一个更长的字符串,它将需要计算更多的div / mul并需要更长的时间。影响性能的另一个因素是&#39; - &#39;标志。如果您有无符号整数,则应将其考虑在内。

基本上测量意味着:

  • 创建具有适当长度的字符串(取决于您的数据!!!)。更多字符串=更好
  • 创建失败/传递与字符串数组匹配(或不与之匹配)的整数数组。
  • 垃圾收集。
  • 使用这两个阵列进行测试。

确保在测试期间为此制作一个巨大的数组,以便您的测试不会受到影响。还要确保你使用的整数/随机数与你的数据具有相同的特征......因此,我不能为你执行测试,所以我只是坚持理论。

字符串到整数相等

了解字符串到整数转换的工作方式很有帮助,所以让我们从一个直接的解决方案开始,然后继续努力。我目前在笔记本电脑上没有Java,所以我很抱歉C#语法:-)你应该能够轻松解决它... ...

public int ConvertStringToInt(string s)
{
    int val = 0;
    if (s[0] == '-') // 1
    {
        for (int i = 1; i < s.Length; ++i )
        {
            if (s[i] >= '0' && s[i] <= '9') // 2
            {
                throw new Exception();
            }
            val = val * 10 + s[i] - '0';
        }
        return -val;
    }
    else
    {
        for (int i = 0; i < s.Length; ++i)
        {
            if (s[i] >= '0' && s[i] <= '9')
            {
                throw new Exception();
            }
            val = val * 10 + s[i] - '0';
        }
        return val;
    }
}

如果您知道字符串中的数字永远不会为负数,那么您当然可以放弃条件 1 。此外,如果您知道该字符串始终是一个数字(在您的问题中隐含的是IMO),您可以优化 2 。我通常使用的一个小技巧是使用算术溢出来生成大的无符号数,从而从 2 中删除一个附加条件。你最终会得到:

public int ConvertStringToInt(string s)
{
    int val = 0;
    if (s[0] == '-')
    {
        for (int i = 1; i < s.Length; ++i )
        {
            val = val * 10 + s[i] - '0';
        }
        return -val;
    }
    else
    {
        for (int i = 0; i < s.Length; ++i)
        {
            val = val * 10 + s[i] - '0';
        }
        return val;
    }
}

接下来,你想要平等而不是转换。那么,我们对这个有多懒惰呢?好吧,在我们进行检查之前,我们需要解析几乎所有的字符串。我们唯一知道的是,如果我们遇到一个&#39; - &#39; char,我们还需要一个负整数。我最终得到了这个:

public bool EqualsStringInt(string s, int value)
{
    int val = 0;
    if (s[0] == '-')
    {
        if (value >= 0) { return false; } // otherwise we expected another char

        for (int i = 1; i < s.Length; ++i )
        {
            val = val * 10 + s[i] - '0'; // s[i] must be a char between '0'-'9' as implied by the question.
        }
        return (-val) == value;
    }
    else
    {
        if (value < 0) { return false; } // otherwise we expected another char

        for (int i = 0; i < s.Length; ++i)
        {
            val = val * 10 + s[i] - '0';
        }
        return val == value;
    }
}

字符串相等的整数

我过去为C ++编写了一些代码,它将整数转换为字符串:C++ performance challenge: integer to std::string conversion。如果您真的在寻找性能,那么这里也有一些很好的解决方案可能值得考虑。

只是检查平等比这更容易。如果仔细查看算法,您会注意到:

  • 缓冲区分配。你不需要那个。如果你不等待GC和/或使用静态字符串为这个过程播种,你的测试就会出错!
  • 缓冲区重新分配。如果您已按顺序填充缓冲区,则还需要将其反转。如果您不想要GC,这将影响测试结果!

从长远来看,这两者都应该耗费时间,而且它们都会影响你的测试。

在这一点上,有趣的是你注意到你并不需要完整的字符串 - 你只需要一个字符。所以,让我们使用它:

  • 如果标志不匹配,则平等失败
  • 如果第一个字符不匹配,则平等失败
  • 如果生成的所有字符都相同,则等同成功。

或者,在代码中:

public bool EqualsIntString(int value, string s)
{
    if (s.Length == 0) { return false; } // This is never good.
    if ((s[0] == '-' && value >= 0) || (s[0] != '-' && value < 0)) { return false; } // positive/negative check

    // Define the limit. This is basically the end of the string to check.
    int limit = 0;
    if (value < 0) // 1
    {
        limit = 1;
        value = -value;
    }

    for (int i=s.Length-1; i>=limit; --i)
    {
        char expected = (char)('0' + (value % 10)); // the modulo will be optimized by the JIT because 10 is a constant
        value /= 10; // same story.

        if (s[i] != expected) { return false; }
    }
    return true;
}

同样,如果您没有负数,请进行明显的优化。删除 1

你能做得更快吗?是的......那就是我首先发布C ++链接的原因。大多数这些算法都可以轻松调整,以实现这种平等。情况下。

上一个解决方案的可选优化

您可以使用10log来确定字符串的长度。这意味着整数的下限值和上限值。一个简单的查找表可以为您完成此操作。但是,如果没有正确实现,10log很慢,所以一定要测试一下!

哪一个更快

构建一个合适的测试,并测试它。我试图在这里进行测试,但不具备您的数据特征,我希望这些特性会有所作为。

当然,如果你不需要这么直率的表现,请使用标准的实现和等号,并测试它。

答案 2 :(得分:0)

我敢打赌

Integer.parseInt(str) == integer

更快。所需要的只是一个乘法和每个数字一个加法,而Integer.toString需要除法和每个数字的模数 - 最慢的算术运算。

实际上,有一些优化可以减少Integer.toString中的操作次数,但速度比太大了。

此外,还有新字符串的内存分配。

OTOH,Integer.parseInt接受所有的Unicode数字,而不仅仅是0到9,这会大大减慢它的速度。我猜,番石榴的Ints.parseInt速度更快。

如果无法解析字符串,那么您将获得NumberFormatException。你可以捕获它,但它需要花费很多时间,然后Integer.toString才是赢家。

答案 3 :(得分:-1)

我会选择Interger.Parse(),面对不同的本地化文化等,它可能比其他方法更具弹性......

速度不是真正的问题 - 有效的结果是。