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