JDK里那些有趣的代码(1)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/JavaZWT/article/details/82731545

前言

今天我们来看一下JDK里一些好玩的代码。我们来分析下。

在Integer源码里,我们可以看到这样一段代码:

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,99999999, 999999999, Integer.MAX_VALUE };

// Requires positive x
static int stringSize1(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

这段代码是在干啥???

我们仔细读下,其实就会发现他其实是计算传入的int型x的位数,要求x为正数。

嗯,不难理解。

他为什么要这么写呢?

思考

对于我们来讲,当拿到一个int型正整数,如何用程序算出它的位数呢?

一般不假思索的可能想到String的length方法计算。如下:

static int myStringSize1(int x){
    return String.valueOf(x).length();
}

嗯,代码量很少。。。。。。

还有吗?

对,还可以用除法,除以10,计算位数。

static int myStringSize2(int x){
   int num=1;
   while(x>10){
        x=x/10;
        num++;
   }
    return num;
}

嗯。。。。不错不错~

当然能用除法解决的基本上也可以用乘法解决,int的最大位数为10位,所以可以乘以10,判断大小。

// Requires positive x
static int stringSize2(int x) {
    int p = 10;
    for (int i=1; i<11; i++) {
        if (x < p)
            return i;
        p = 10*p;
    }
    return 10;
}

好吧,目前我就想到了除JDK以外的这三种方法。

我们测试一下我们的代码正确性。

public static void main(String[] args) {
    int [] x=new int[]{5,10,333,6666,77777,123456,1234567,87654321,999999999,1111111111,Integer.MAX_VALUE};
    for(int i=0;i<x.length;i++){
       int a1=Test.stringSize1(x[i]);
       int a2=Test.stringSize2(x[i]);
       int a3=Test.myStringSize1(x[i]);
       int a4=Test.myStringSize2(x[i]);
       System.out.println(a1+"---"+a2+"---"+a3+"---"+a4);
    }
}

运行结果:

这里写图片描述

结果还是木有问题哒。

提升

JDK的这种写法有什么好处呢???

可以看到,JDK的方法把一部分数据计算变成了数据比较,相当于优化吧。

那它的执行效率怎么样呢?

我们写的方法的效率又如何呢?

我们来测试下吧!

实践

我们可以制造一个随机的定长int数组,看看它们执行耗时,同时统计若干组数据,进行比较。

话不多说,直接写代码并记录到Excel里供分析。

public static void main(String[] args) throws  Exception{

        List<List<Long>> rowList= Lists.newArrayList();

        List<String> titleList=Lists.newArrayList();
        titleList.add("JDK方法");
        titleList.add("乘法");
        titleList.add("String方法");
        titleList.add("除法");


        for(int s=0;s<50;s++){

            List<Long> cellList=Lists.newArrayList();

            int [] xArrays=new int [10000];
            for(int i=0;i<xArrays.length;i++){
                xArrays[i]=1 + (int)(Math.random()*Integer.MAX_VALUE);
            }
            //System.out.println("当前S值为"+s);

            long start1=System.nanoTime();
            for(int i=0;i<xArrays.length;i++) {
                stringSize1(xArrays[i]);
            }
            long end1=System.nanoTime();
            long time1=(end1-start1)/1000;
            System.out.println("JDK方法耗时---》"+time1+"ms");
            cellList.add(time1);


            long start4=System.nanoTime();
            for(int i=0;i<xArrays.length;i++) {
                stringSize2(xArrays[i]);
            }
            long end4=System.nanoTime();
            long time4=(end4-start4)/1000;
            System.out.println("乘法耗时---》"+time4+"ms");
            cellList.add(time4);


            long start2=System.nanoTime();
            for(int i=0;i<xArrays.length;i++) {
                myStringSize1(xArrays[i]);
            }
            long end2=System.nanoTime();
            long time2=(end2-start2)/1000;
            System.out.println("String方法耗时---》"+time2+"ms");
            cellList.add(time2);


            long start3=System.nanoTime();
            for(int i=0;i<xArrays.length;i++) {
                myStringSize2(xArrays[i]);
            }
            long end3=System.nanoTime();
            long time3=(end3-start3)/1000;
            System.out.println("除法耗时---》"+time3+"ms");
            cellList.add(time3);

            rowList.add(cellList);
        }

        WriteExcelUtil.writeExecl(titleList,rowList,"/Users/zhangwentong/Desktop/workbook.xlsx");
    }

我记录了50组数据,每组里面每个计算位数的方法执行10000次,得到如下结果。

这里写图片描述

把它绘制成折线图。

这里写图片描述

可以看到,String的length方法效率是最差的。。。。

我们其实看一下String.valueOf(x).length()这个源码,就知道为什么这么慢了。

然后除法也稍微逊色一点。。。

乘法和JDK的效率都可以说不错。。。。。但JDK方法其实要好一点。。。。

而且开始创建的sizeTable是占据较少空间,但却降低了CPU的计算次数(乘法需要每次乘以十在比较计算)。

当然,因为int的位数只有10位,可以写一个sizeTable,当数据量大时,比如long,最大19位,写一个19个数的sizeTable? 一堆9???

哈哈,我们可以看看Long里面的计算位数的方法。

    // Requires positive x
    static int stringSize(long x) {
        long p = 10;
        for (int i=1; i<19; i++) {
            if (x < p)
                return i;
            p = 10*p;
        }
        return 19;
    }

人家当然用的乘法啦。。。。。

结论

我们可以看到,我们最容易想到的String.length方法确是效率最低的。。。。

JDK源码里一些方法会被大量调用,当然要做到最好的优化啦。。。

多读些源码,深入思考,多加练习,有助于提升自己。

今天就到这儿吧。

猜你喜欢

转载自blog.csdn.net/JavaZWT/article/details/82731545