在工做中,遇到了對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