Java中List轉換爲byte[]方法比較

    在工做中,遇到了對byte數組的一些處理。目的是根據已有的信息編輯成一組數組併發送給設備。在整個處理過程當中,發現直接處理byte數組十分麻煩,須要屢次用到數組copy之類的操做,數組的下標操做也比較噁心。後來通過多方查找,發現先利用List<Byte>構建數組內容,無需在意下標位置,也不用數組copy,只須要無腦Add就能夠很方便的構建整個數組,再把List轉換爲byte[]就能夠了。在探索了整個過程以後,發現一篇博文推薦了三種List<Byte>轉換爲byte[]的方法,並簡要說了一句三者的速度差別。我對這個過程比較好奇,所以本身作了一些小小的比較,算是對工做遇到的問題的一個總結。但願對你們有所幫助。java

    日誌原連接以下:windows

    http://blog.csdn.net/jenlyser/article/details/17024875數組

    文中提到了三種方法,分別是1——使用for循環。2——使用Apache Commons Lang庫的ArrayUtils.toPrimitive()方法。3——google guava中的Bytes.toArray()方法。並說起這三種方法中第一種最慢,第二種稍快,第三種最快。我這裏第二種方法始終報錯,彷佛是ArrayUtils.toPrimitive()方法並不支持List<>類型的參數。所以只是簡單比較了第1、三種方法的速度。代碼以下:併發

    

/**
     * 方法1,使用for循環
     * @param list
     * 將被轉換爲byte[]的List<Byte>
     * @return
     * 轉換成的byte數組
     */
    private static byte[] listTobyte1(List<Byte> list) {
        if (list == null || list.size() < 0)
            return null;
        byte[] bytes = new byte[list.size()];
        int i = 0;
        Iterator<Byte> iterator = list.iterator();
        while (iterator.hasNext()) {
            bytes[i] = iterator.next();
            i++;
        }
        return bytes;
    }

    /**
     * 方法3,使用guaba的Bytes.toArray()方法
     * @param list
     * 將被轉換爲byte[]的List<Byte>
     * @return
     * 轉換成的byte數組
     */
    private static byte[] listTobyte2(List<Byte> list) {
        byte[] bytes= Bytes.toArray(list);
        return bytes;
    }

主函數以下:dom

public static void main(String[] args) {

        List<Byte> bytesList= new ArrayList<Byte>();
        Random rand = new Random(128);
        for (int i = 0; i < 10000000 ; i ++){//測試數量
            bytesList.add((byte)rand.nextInt());
        }

        long startTime1=System.currentTimeMillis();   //獲取開始時間
        listTobyte1(bytesList);
        long endTime1=System.currentTimeMillis(); //獲取結束時間
        System.out.println("方法1運行時間: "+(endTime1-startTime1)+"ms");

        long startTime2=System.currentTimeMillis();   //獲取開始時間
        listTobyte2(bytesList);
        long endTime2=System.currentTimeMillis(); //獲取結束時間
        System.out.println("方法2運行時間: "+(endTime2-startTime2)+"ms");

    }

    接下來將分別測試長度爲1000 / 10000 / 50000 / 100000 / 1000000 / 10000000 / 50000000的List轉換耗時:函數

  1000  10000 50000 100000 1000000 10000000 50000000
for循環 1ms 2ms 8ms 13ms 17ms 111ms 132ms
guava 5ms 6ms 7ms 10ms 16ms 35ms 183ms

    通過測試,能夠很明顯的發現,在List容量小於10W個的時候,使用for循環明顯快於guava庫中的Bytes.toArray()方法。數量越小差距越大。當List容量在10W~1000W個的時候,for循環方法被反超,速度大幅度落後於guava。而數據量超過5000W時,guava方法又大幅度落後了。總體形式十分交錯糾結。我又加測了容量爲1億時兩者的速度,for循環耗時277ms,guava耗時320ms。結果與以前趨勢相符。學習

    爲了進一步比較兩者速度反超時候的狀況,我又加測了1000W~5000W容量的數據。以1000W爲起點,500W爲一個節點進行遞增。結果以下:測試

  1000W 1500W 2000W 2500W 3000W 3500W 4000W 4500W 5000W
for循環 116ms 168ms 205ms 260ms 300ms 111ms 117ms 154ms 137ms
guava 37ms 49ms 64ms 10823ms 120ms 158ms 163ms 162ms 179ms

    結果然的好詭異,尤爲是2500W這一組,guava方法時間異常的多。爲了防止出錯我反覆檢查了list的大小和執行的結果,然而每次guava耗時都在10~11秒左右。而過了這個區間之後在3000W容量下兩者耗時恢復正常,3500W以後for循環方法耗時不增反降,guava方法的耗時也趨於平緩。呈現出一個十分奇怪的趨勢。這個趨勢我目前還沒法給出結論。只是在List長度爲5W之內,for循環方法耗時更小,5W~2000W,能夠選擇guava提供的Bytes.toArray()方法以節約時間。而到了2000W以上,仍是用for循環更爲實惠。在考慮平常的應用場景,普通的for循環方法應該是足夠覆蓋大多數使用場景了。而guava方法詭異的時間趨勢的祕密,只有之後經過對源碼和JVM的進一步學習纔有可能解開了。google

    感謝上文提到的列出三個方法的做者。spa

    測試環境:

    JDK:1.8.0_101

    CPU:core i7 3630QM

    RAM:16G

    IDE:Intellij IDEA 2016.2.5(64bit)

    OS:windows10

相關文章
相關標籤/搜索