【问题标题】:Most efficient way of converting String to Integer in java在java中将String转换为Integer的最有效方法
【发布时间】:2010-11-05 01:17:31
【问题描述】:

有很多方法可以将 String 转换为 Integer 对象。以下哪个是最有效的:

Integer.valueOf()
Integer.parseInt()
org.apache.commons.beanutils.converters.IntegerConverter

我的用例需要创建包装整数对象...意味着没有原始 int...并且转换后的数据用于只读。

【问题讨论】:

  • 我做了一些小测试,惊讶地发现 Integer.valueOf 花了很多时间......任何想法...... [code] for (int i = 1; i

标签: java optimization performance


【解决方案1】:

我知道这不在您的上述选项之列。 IntegerConverter 没问题,但你需要创建它的一个实例。看看 Commons Lang 中的 NumberUtils:

Commons Lang NumberUtils

这提供了toInt的方法:

static int toInt(java.lang.String str, int defaultValue) 

允许您在失败的情况下指定默认值。

NumberUtils.toInt("1", 0)  = 1

这是迄今为止我找到的最佳解决方案。

【讨论】:

    【解决方案2】:

    甚至不要浪费时间去想它。只需选择一个似乎适合其余代码的代码(其他转换是否使用 .parse__() 或 .valueOf() 方法?使用它来保持一致)。

    试图决定哪个是“最好的”会分散您解决业务问题或实施功能的注意力。

    不要因为琐碎的细节而陷入困境。 :-)

    附带说明,如果您的“用例”正在为您的代码指定 java 对象数据类型 - 您的 BA 需要退出您的域。 BA 需要定义“业务问题”,以及用户在解决问题时希望如何与应用程序交互。 开发人员确定如何最好地使用代码将该功能构建到应用程序中 - 包括处理数据的正确数据类型/对象。

    【讨论】:

    • 这太糟糕了,因为我最不喜欢这种方法,因为有“内置”更简单的方法可以做到这一点。 :-) 但是我无法想象它会导致任何类型的性能问题 - 所以我会坚持“如果它没有坏,就不要修复它”的规则。
    • 完全同意 BA 的观点,但总体上是 -1,因为没有回答实际问题并假设当问题明确与效率有关时性能并不重要。
    • @mikera 我同意。这不应该是公认的答案,或者根本不应该赞成。 “答案”完全是主观的和基于意见的,甚至没有尝试回答所提出的问题。
    • 有时业务问题是系统不够快,因为开发人员认为细节无关紧要。我有一些系统,其中我们的瓶颈是解析整数,并且加速它使系统更具响应性和可用性。在旁注中,我不确定 BA 与这个问题有何关联。 OP 没有提到 BA 试图设计那里的系统。
    • 这个问题是谷歌搜索结果,让拥有数十亿数字的人尽快解析,而接受的答案在任何方面都没有用处。
    【解决方案3】:

    ParseInt 返回一个 int,而不是 java.lang.Integer,所以如果你使用 tat 方法,你将不得不这样做

    new Integer (Integer.parseInt(number));
    

    我多次听说调用 Integer.valueOf() 而不是 new Integer() 更好,因为内存原因(这将用于 pmd)

    在 JDK 1.5 中,调用 new Integer() 导致内存分配。 Integer.valueOf() 是更多内存 友好。

    http://pmd.sourceforge.net/rules/migrating.html

    除此之外,Integer.valueOf 允许缓存,因为值 -127 到 128 保证有缓存的实例。 (从 java 1.5 开始)

    【讨论】:

    • Java 现在支持自动装箱,即装箱类型和原始类型之间的自动转换。所以“整数 i = new Integer (Integer.parseInt(number));”最好写成“Integer i = Integer.parseInt(number);”
    【解决方案4】:

    如果您关心效率,请使用 int:它比 Integer快得多

    否则,Integer 类至少为您提供了一些清晰、干净的方法:

    Integer myInteger = new Integer(someString);
    Integer anotherInteger = Integer.valueOf(someOtherString);
    

    【讨论】:

    • 我同意。使用 Integer 类似乎与效率问题背道而驰。除非效率当然是关于字符串转换,而不是整数存储或操作。
    • 使用 Integer.valueOf(someOtherString),它更智能,可以使用缓存的 Integer 实例。
    【解决方案5】:

    最好的办法是使用 Integer.parseInt。这将返回一个 int,但这可以自动装箱为整数。这比 valueOf 稍快,因为当您的数字介于 -128 和 127 之间时,它将使用整数缓存而不创建新对象。最慢的是 Apache 方法。

    private String data = "99";
    
    public void testParseInt() throws Exception {
        long start = System.currentTimeMillis();
        long count = 0;
        for (int i = 0; i < 100000000; i++) {
            Integer o = Integer.parseInt(data);
            count += o.hashCode();
        }
        long diff = System.currentTimeMillis() - start;
        System.out.println("parseInt completed in " + diff + "ms");
        assert 9900000000L == count;
    }
    
    public void testValueOf() throws Exception {
        long start = System.currentTimeMillis();
        long count = 0;
        for (int i = 0; i < 100000000; i++) {
            Integer o = Integer.valueOf(data);
            count += o.hashCode();
        }
        long diff = System.currentTimeMillis() - start;
        System.out.println("valueOf completed in " + diff + "ms");
        assert 9900000000L == count;
    }
    
    
    public void testIntegerConverter() throws Exception {
        long start = System.currentTimeMillis();
        IntegerConverter c = new IntegerConverter();
        long count = 0;
        for (int i = 0; i < 100000000; i++) {
            Integer o = (Integer) c.convert(Integer.class, data);
            count += o.hashCode();
        }
        long diff = System.currentTimeMillis() - start;
        System.out.println("IntegerConverter completed in " + diff + "ms");
        assert 9900000000L == count;
    }
    
    parseInt completed in 5906ms
    valueOf completed in 7047ms
    IntegerConverter completed in 7906ms
    

    【讨论】:

    • +1 用于实际测试!! FWIW,我认为如果您没有将结果装箱,您可以从 Integer.parseInt() 获得更快的结果......这在我的机器上值得额外 10% 左右
    • 能否提供基准?确切地添加您试图得出的结论是有帮助的,但我认为将您的实际结果与您曾经得出此结论的实际代码结合起来会更有意义。例如,像这样nadeausoftware.com/articles/2009/08/…
    【解决方案6】:

    如果您关心的是效率,那么创建一个 Integer 对象比解析它要昂贵得多。如果你必须创建一个 Integer 对象,我不会太担心它是如何解析的。

    注意:Java 6u14 允许您使用命令行选项 -Djava.lang.Integer.IntegerCache.high=1024 来增加整数池的大小。

    注意 2:如果您正在读取原始数据,例如来自文件或网络的字节,将这些字节转换为字符串也相对昂贵。如果您要编写自定义解析器,我建议绕过转换为字符串并解析原始源数据的步骤。

    注意 3:如果您正在创建一个 Integer 以便将其放入一个集合中,您可以使用 GNU Trove (trove4j) 来避免这种情况,它允许您将原语存储在集合中,也允许您删除 Integer 创建.

    理想情况下,为了获得最佳性能,您应该完全避免创建任何对象。

    【讨论】:

    • +1 for -Djava.lang.Integer.IntegerCache.high Long 也有开关吗?
    【解决方案7】:

    我总是很惊讶这里有多少人会如此迅速地驳回对性能问题的一些调查。在许多程序中,解析一个以 10 为底的 int 是一项非常常见的任务。加快这一速度可能会在许多环境中产生显着的积极影响。

    由于解析和 int 实际上是一项相当琐碎的任务,因此我尝试实现一种比 JDK 实现中使用的具有可变基数的方法更直接的方法。结果证明它比 Integer.parseInt() 快两倍多,否则行为应该与 Integer.parseInt() 完全相同。

    public static int intValueOf( String str )
    {
        int ival = 0, idx = 0, end;
        boolean sign = false;
        char ch;
    
        if( str == null || ( end = str.length() ) == 0 ||
           ( ( ch = str.charAt( 0 ) ) < '0' || ch > '9' )
              && ( !( sign = ch == '-' ) || ++idx == end || ( ( ch = str.charAt( idx ) ) < '0' || ch > '9' ) ) )
            throw new NumberFormatException( str );
    
        for(;; ival *= 10 )
        {
            ival += '0'- ch;
            if( ++idx == end )
                return sign ? ival : -ival;
            if( ( ch = str.charAt( idx ) ) < '0' || ch > '9' )
                throw new NumberFormatException( str );
        }
    }
    

    要获取它的 Integer 对象,请使用自动装箱或显式

    Interger.valueOf( intValueOf( str ) ).

    【讨论】:

    • 人们忽略它的原因是因为在需要 1/1,000,000 执行时间的事情上获得 50% 的改进是一种浪费。而对于任何非平凡的程序,尤其是那些涉及数据库的程序,字符串到整数的转换应该远远少于执行时间的百万分之一。
    • @kdgregory:在当今普遍存在的基于文本的格式(如 XML、JSON 和 HTTP)中,从字符串中解析数字实际上是许多非平凡程序中非常常见的任务。我宁愿说,如果您的程序仍然只在这种代码上花费很少的时间,那么它们在其他地方的效率可能非常低。
    • 我不同意你使用“低效”:一个简单的网络请求将需要 100 毫秒左右的时间来执行。解析请求可能需要 100 微秒。前者远远超过后者,并且不涉及“高效”或“低效”。你也无能为力。
    • 如果您希望提高程序的整体吞吐量,自我 25 多年前开始工作以来,规则并没有改变:您创建一个实际的工作负载,使用该工作负载分析您的应用程序,然后优化实际消耗大量时间的部分。其他任何事情都是白费力气。
    • 我完全同意你的看法。分析是了解什么值得优化的唯一方法。但是,如果这表明您的请求处理比处理请求花费的时间多 1000 倍,那么您要么在那里做一些严肃的工作,要么在这段代码中浪费时间。 IE。在大多数情况下,对于高负载服务器,我认为在请求处理程序中使用未缓存的数据库访问是不可接受的低效。
    【解决方案8】:

    Herro - 对 Java 有点陌生,所以请原谅我的无知。

    我正在寻找一种将混合字符串(字母和数字)解析为 INT 的方法(有点像 javascript)。在 JAVADOC 文件中找不到任何东西,所以经过大量搜索后,我只写了一个函数:

    // This function takes a string mixed with numbers and letters and returns an INT with
    // the first occurrence of a number (INT) in said string, ignoring the rest;
    // -- Basically, loop checks if char is a digit, if yes, puts digit back into new array, if no, puts a whitespace in its place
    // this creates an array with only digits; By converting it to a string and then trimming whitespaces, it gets parsed into an INT
    
    
    public static int mixedStringToInt (String str) {
    
        boolean flag = true;
        boolean isNumber = false;
        final String refNumbers = "0123456789";
    
        int strlen = str.length();
        char[] numberArray = new char[strlen];
        char[] stringArray = str.toCharArray();
    
        for (int i = 0; i < strlen;i++){
            if(refNumbers.indexOf(stringArray[i]) > 0 && flag){
                // if current char is a digit
                isNumber = true;
                while (flag){
                    numberArray[i] = stringArray[i];
                    if(i+1 >= strlen || refNumbers.indexOf(stringArray[i+1]) < 0) flag = false;
                    i++;
                }
            } else {
                // if current char is not a digit
                numberArray[i] = ' ';
            }
        }
        if (isNumber){
            return Integer.valueOf(new String(numberArray).trim());
        } else return 0;
    }
    





    这对我以外的任何人有用吗?我是不是在浪费时间写这篇文章,因为已经有一种方法可以做我想做的事?

    【讨论】:

      【解决方案9】:

      另一种方法是这种方法:

      public class stringtoInteger {
      
          private static int stringtoInteger(String x) {
              String value = "";
              for (int i = 0; i < x.length(); i++) {
                  char character = x.charAt(i);
                  if (Character.isDigit(character)) {
                      value = value + character;
                  }
              }
              return Integer.parseInt(value);
          }
      }  
      

      希望对你有帮助!

      【讨论】:

        【解决方案10】:

        我尝试将 valueOf、parseInt、Ints.tryParse、NumberUtils.createInteger 和 NumberUtils.toInt 与下面的程序进行比较。我在 jdk 1.8.0

        正如预期的那样,不需要创建 Integer 对象的方法是最快的。我的结果是:

        valueOf took: 77
        parseInt took: 61
        Ints.tryParse took: 117
        numberUtils.createInteger took: 169
        numberUtils.toInt took: 63 
        

        所以总结是:

        如果可以通过使用 int 获取,请使用 Integer.parseInt。

        如果您绝对需要整数,请使用 Integer.valueOf

        如果您需要在解析时不处理异常的便利,或者如果您不确定输入的格式(即它不需要是数字的字符串),请使用 Ints.tryParse

        我使用的代码是:

        public class HelloWorld {
        
        public static int limit = 1000000;
        public static String sint = "9999";
        
        public static void main(String[] args) {
        
            long start = System.currentTimeMillis();
            for (int i = 0; i < limit; i++) {
               Integer integer = Integer.valueOf(sint);
            }
            long end = System.currentTimeMillis();
        
            System.out.println("valueOf took: " + (end - start));
        
        
            start = System.currentTimeMillis();
            for (int i = 0; i < limit; i++) {
                int integer = Integer.parseInt(sint);
            }
            end = System.currentTimeMillis();
        
            System.out.println("parseInt took: " + (end - start));
        
        
            start = System.currentTimeMillis();
            for (int i = 0; i < limit; i++) {
                int integer = Ints.tryParse(sint);
            }
            end = System.currentTimeMillis();
        
            System.out.println("Ints.tryParse took: " + (end - start));
        
        
            start = System.currentTimeMillis();
            for (int i = 0; i < limit; i++) {
                Integer integer = NumberUtils.createInteger(sint);
            }
            end = System.currentTimeMillis();
        
            System.out.println("numberUtils.createInteger took: " + (end - start));
        
            start = System.currentTimeMillis();
            for (int i = 0; i < limit; i++) {
                int integer = NumberUtils.toInt(sint);
            }
            end = System.currentTimeMillis();
        
            System.out.println("numberUtils.toInt took: " + (end - start));
        
        }
        }
        

        【讨论】:

          【解决方案11】:

          Here's a good article comparing the performance of different methods of parsing integers

          这是使用的代码,带有上溢/下溢检查。

          public static int parseInt( final String s )
          {
              if ( string == null )
                  throw new NumberFormatException( "Null string" );
          
              // Check for a sign.
              int num  = 0;
              int sign = -1;
              final int len  = s.length( );
              final char ch  = s.charAt( 0 );
              if ( ch == '-' )
              {
                  if ( len == 1 )
                      throw new NumberFormatException( "Missing digits:  " + s );
                  sign = 1;
              }
              else
              {
                  final int d = ch - '0';
                  if ( d < 0 || d > 9 )
                      throw new NumberFormatException( "Malformed:  " + s );
                  num = -d;
              }
          
              // Build the number.
              final int max = (sign == -1) ?
                  -Integer.MAX_VALUE : Integer.MIN_VALUE;
              final int multmax = max / 10;
              int i = 1;
              while ( i < len )
              {
                  int d = s.charAt(i++) - '0';
                  if ( d < 0 || d > 9 )
                      throw new NumberFormatException( "Malformed:  " + s );
                  if ( num < multmax )
                      throw new NumberFormatException( "Over/underflow:  " + s );
                  num *= 10;
                  if ( num < (max+d) )
                      throw new NumberFormatException( "Over/underflow:  " + s );
                  num -= d;
              }
          
              return sign * num;
          }
          

          甚至更快的实现,无需上溢/下溢检查。

          public static int parseInt( final String s )
          {
              // Check for a sign.
              int num  = 0;
              int sign = -1;
              final int len  = s.length( );
              final char ch  = s.charAt( 0 );
              if ( ch == '-' )
                  sign = 1;
              else
                  num = '0' - ch;
          
              // Build the number.
              int i = 1;
              while ( i < len )
                  num = num*10 + '0' - s.charAt( i++ );
          
              return sign * num;
          } 
          

          【讨论】:

          • 我必须将任意长度的String 数字数组转换为ints,因此效率很重要。我使用了您的更快版本,但删除了符号检查以摆脱多余的if,因为我没有负数。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-22
          • 2014-09-24
          • 2011-10-01
          • 1970-01-01
          • 2012-02-16
          相关资源
          最近更新 更多