java int转String所有方式的效率对比与深入解析

  在java中,大家肯定都会遇到int类型转String类型的情形,知其然知其所以然,总结加分析一下,int类型转String类型有以下几种方式:  

  1. a+”“
  2. String.valueOf(a)
  3. Integer.toString(a)

  以上三种方法在实际使用过程中都是没有问题的,但是效率上还是有些许差别的,所以写个小程序来对比一下他们的效率:

  

int a = 123456789;
long start = System.currentTimeMillis();
for (int i=0; i<100000; i++){
    String m = a+"";
}
long end = System.currentTimeMillis();
Log.e("time", "a+\"\" = " + (end - start));

start = System.currentTimeMillis();
for (int i=0; i<100000; i++){
    String n = String.valueOf(a);
}
end = System.currentTimeMillis();
Log.e("time", "String.valueOf(a) = " +(end-start));

start = System.currentTimeMillis();
for (int i=0; i<100000; i++){
    String n = Integer.toString(a);
}
end = System.currentTimeMillis();
Log.e("time", "Integer.toString(a) = " +(end-start));

最后打印出来的执行时间:

E/time: a+"" = 257
E/time: String.valueOf(a) = 140
E/time: Integer.toString(a) = 159

可以看到在效率上除了a+”“这种方式之外,其他两种方式的效率差不多,为什么呢?看源码!

  先看看后两种方式的源码:

String.valueOf(a)->Integer.toString(a)->IntegralToString.intToString(a)->convertInt(null, a)

Integer.toString(a)->IntegralToString.intToString(a)->convertInt(null, a)

可以看到String.valueOf是通过调用Integer.toString实现的,也难怪他们的效率如此接近。他们最后都会调用到convertInt函数中:

private static String convertInt(AbstractStringBuilder sb, int i) {
    boolean negative = false;
    String quickResult = null;
    if (i < 0) {
        negative = true;
        i = -i;
        if (i < 100) {
            if (i < 0) {
                // If -n is still negative, n is Integer.MIN_VALUE
                quickResult = "-2147483648";
            } else {
                quickResult = SMALL_NEGATIVE_VALUES[i];
                if (quickResult == null) {
                    SMALL_NEGATIVE_VALUES[i] = quickResult =
                            i < 10 ? stringOf(‘-‘, ONES[i]) : stringOf(‘-‘, TENS[i], ONES[i]);
                }
            }
        }
    } else {
        if (i < 100) {
            quickResult = SMALL_NONNEGATIVE_VALUES[i];
            if (quickResult == null) {
                SMALL_NONNEGATIVE_VALUES[i] = quickResult =
                        i < 10 ? stringOf(ONES[i]) : stringOf(TENS[i], ONES[i]);
            }
        }
    }
    if (quickResult != null) {
        if (sb != null) {
            sb.append0(quickResult);
            return null;
        }
        return quickResult;
    }

    int bufLen = 11; // Max number of chars in result
    char[] buf = (sb != null) ? BUFFER.get() : new char[bufLen];
    int cursor = bufLen;

    // Calculate digits two-at-a-time till remaining digits fit in 16 bits
    while (i >= (1 << 16)) {
        // Compute q = n/100 and r = n % 100 as per "Hacker‘s Delight" 10-8
        int q = (int) ((0x51EB851FL * i) >>> 37);
        int r = i - 100*q;
        buf[--cursor] = ONES[r];
        buf[--cursor] = TENS[r];
        i = q;
    }

    // Calculate remaining digits one-at-a-time for performance
    while (i != 0) {
        // Compute q = n/10 and r = n % 10 as per "Hacker‘s Delight" 10-8
        int q = (0xCCCD * i) >>> 19;
        int r = i - 10*q;
        buf[--cursor] = DIGITS[r];
        i = q;
    }

    if (negative) {
        buf[--cursor] = ‘-‘;
    }

    if (sb != null) {
        sb.append0(buf, cursor, bufLen - cursor);
        return null;
    } else {
        return new String(cursor, bufLen - cursor, buf);
    }
}

分析一下,这个函数的工作主要可以分为这几步:

  1. 如果a为负数,将a变成正数,如果a还小于0,直接置为Integer.MIN_VALUE;如果a小于100,则直接使用TENS和ONES数组进行快速计算得出结果,加上’-‘号,直接返回该结果。
  2. 如果a为正数并且小于100,直接使用TENS和ONES数组进行快速计算得出结果返回。
  3. 如果上面两步没有处理完,说明a是大于100的数字,无法直接使用TENS和ONES数组进行快速计算,处理方式就是2位为一步循环处理,每次将这两位使用TENS和ONES数组进行快速计算得出这两位的结果存在数组的相应位置,直到只剩一位;最后剩下的一位使用DIGITS数组得出16进制的结果放在最后,返回结果。

  那么问题来了,当a>=100的时候,那两次while循环为什么会使用0x51EB851FL和0xCCCD这两个数字呢?这个问题不要问我,我也不知道,不过源码作者注释写的很明白了:

// Compute q = n/100 and r = n % 100 as per "Hacker‘s Delight" 10-8

// Compute q = n/10 and r = n % 10 as per "Hacker‘s Delight" 10-8

去看《Hacker’s Delight》的10-8章。

  接着还有一个问题是TENS和ONES数组,直接看代码,一目了然:

/** TENS[i] contains the tens digit of the number i, 0 <= i <= 99. */
private static final char[] TENS = {
        ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘,
        ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘,
        ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘,
        ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘,
        ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘,
        ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘,
        ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘,
        ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘,
        ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘,
        ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘
};

/** Ones [i] contains the tens digit of the number i, 0 <= i <= 99. */
private static final char[] ONES = {
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
};

每个数组都是100的长度,都是用来处理0~99这100个数字,个位和十位的处理方式也很清楚。

  从代码角度来看,这个算法在数字小于100的和大于100的处理方式是不一样的,小于100的快速计算法执行时间会远远短于大于100的方式,验证一下,将a变量修改为10:

E/time: i+"" = 199
E/time: String.valueOf() = 7
E/time: Integer.toString() = 6

确实短了很多!!!

  再来看看a+”“的方式,我承认这种方式我用的最多了,因为太简单了,java源码对’+’运算符进行了重载,源码我找不到啊,不过从网上找一些资料:

The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method. String conversions are implemented through the method toString, defined by Object and inherited by all classes in Java. For additional information on string concatenation and conversion, see Gosling, Joy, and Steele, The Java Language Specification.

地址:http://docs.oracle.com/javase/6/docs/api/java/lang/String.html

可以看到,’+’运算符的主要方式是使用StringBuilder或者StringBuffer来实现的,类似于:

StringBuilder sb = new StringBuilder();
sb.append("");
sb.append(i);
String strI = sb.toString();

再来看看append的源码:

StringBuffer.append->IntegralToString.appendInt(this, a)->convertInt(sb, i)

可以看到’+’运算符最后也是调用到了同一个函数,只不过第一个参数的sb不为null而已,所以已经很清楚了,’+’运算符的执行效率不高的原因应该就在之前的new StringBuilder等操作和之后的StringBuilder.toString等操作,反编译class文件也可以得出一样的结论:

http://stackoverflow.com/a/4105406

  所以a+”“的方式以后就少用一点了,效率不高,也显得不太专业。

  经过几个星期的面试,发现自己的 java 基础确实很弱,所以以后要多多加强 java 基础,从这开始,加油~

时间: 2024-11-10 09:37:41

java int转String所有方式的效率对比与深入解析的相关文章

java int转String全部方式的效率对照与深入解析

在java中,大家肯定都会遇到int类型转String类型的情形,知其然知其所以然.总结加分析一下,int类型转String类型有下面几种方式: a+"" String.valueOf(a) Integer.toString(a) 以上三种方法在实际使用过程中都是没有问题的,可是效率上还是有些许区别的,所以写个小程序来对照一下他们的效率: int a = 123456789; long start = System.currentTimeMillis(); for (int i=0;

List集合去重方式及效率对比

List集合相信大家在开发过程中几乎都会用到.有时候难免会遇到集合里的数据是重复的,需要进行去除.然而,去重方式有好几种方式,你用的是哪种方式呢?去重方式效率是否是最高效.最优的呢?今天就给大家讲解一下List集合去重的常见及常用的四种方式. 01 实现思路:使用两个for循环遍历集合所有元素,然后进行判断是否有相同元素,如果有,则去除.这种方式是大部分最先想到的,也是最简单的实现方式.其中,这种方式可以保证List集合原来的顺序不变. 代码实现: /*** notes:使用两个for循环实现L

java List去重方式及效率对比

对List去重并保证添加顺序主要有三种方式: 方式一,利用HashSet不能添加重复数据的特性 由于HashSet不能保证添加顺序,所以只能作为判断条件: private static void removeDuplicate(List<String> list) { HashSet<String> set = new HashSet<String>(list.size()); List<String> result = new ArrayList<S

java int和String类型之间的相互转换

String --> int 第一种方法:int i = Integer.parseInt(s); 第二种方法:int i = Integer.valueOf(s).intValue(); 两种方法的区别:Integer.valueOf(s) 相当于 new Integer(Integer.parseInt(s)),所以第二种方法会产生多余的一个对象,而第一种方法不会. int --> String 第一种方法:String s = i + ""; 第二种方法:String

java中int-&gt;String 3种方式效率分析

1.0 int转String方式 java中,int转String共有如下3种方式 (1) 字符串拼接(即num+"") (2) String.valueof(num) (3) Integer.toString(num) 其中,方法(2)内部直接调用了方法(3),效率相差无几 2.0 效率测试 1 int[] intArr = new int[1000000]; 2 String[] strArr1 = new String[1000000]; 3 4 Long s0 = System

java StringBuffer,StringBuilder,String自身连接效率对比

当我们仅仅需要a+b 的时候,两个字符串链接任何方法的效率基本一样,都在0.0001毫秒内就可以完成.不过如果需要1万次,10000万次,就会发现string自身的join速度显著下降 package com.java.lang; public class StringTest { int MAX = 10000; //1万次累加 public String Buffer(){ StringBuffer sb = new StringBuffer(); for(int i = 0; i < MA

JAVA中int、String的类型转换

int -> String int i=12345;String s="";第一种方法:s=i+"";第二种方法:s=String.valueOf(i);这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢? String -> int s="12345";int i;第一种方法:i=Integer.parseInt(s);第二种方法:i=Integer.valueOf(s).intValue();这两种方法有什么区别

java中字符串String 转 int(转)

java中字符串String 转 int String -> int s="12345"; int i; 第一种方法:i=Integer.parseInt(s); 第二种方法:i=Integer.valueOf(s).intValue(); 这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢? int -> String int i=12345; String s=""; 第一种方法:s=i+""; 第二种方法:s=

Java中int与String间的类型转换

int -> String int i=12345;String s=""; 除了直接调用i.toString();还有以下两种方法第一种方法:s=i+"";第二种方法:s=String.valueOf(i);这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢? String -> int s="12345";int i;第一种方法:i=Integer.parseInt(s);第二种方法:i=Integer.valu