先说结论:忽略其它因素,仅从消耗时间上对比,利用List拼接最快。
JAVA拼接数组的方法有很多种:
1、纯用数组的形式 - byte[]
2、转成16进制字符串,用字符串拼接 - String
3、转成16进制字符串,用StringBuffer拼接 - StringBuffer
4、用集合的形式 - ArrayList<Byte>
测试代码如下:
package com.zzztest;
import java.util.ArrayList;
import java.util.List;
import com._tool.Hex;
import com._tool.Time;
import com._tool.z;
public class Test {
public static void main(String[] args){
byte[] bs = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
,31,32,33,34,35,36,37,38,39,40,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
z.print("0-beg:", Time.getNowTime("0"));
byte[] rs1 = {};
for(int a=0; a<10000; a++) {
byte[] bsTemp = new byte[rs1.length + bs.length];
for(int i=0; i< rs1.length ; i++) {
bsTemp[i] = rs1[i];
}
for(int i=rs1.length; i<bsTemp.length; i++) {
bsTemp[i] = bs[i-rs1.length];
}
rs1 = bsTemp;
}
// z.print("rs1.length:", rs1.length); // -> rs1.length:500000
z.print("1-arr:", Time.getNowTime("0"));
String ss="";
for(int a=0; a<10000; a++) {
ss += Hex.bytesToHexString(bs); // 这里不能用new String(bs)和下面的ss.getBytes(),发现当byte是负值时会出错。
}
byte[] rs2 = Hex.hexStringToBytes(ss); //ss.getBytes();
// z.print("rs2.length:", rs2.length); // -> rs2.length:500000
z.print("2-str:", Time.getNowTime("0"));
StringBuffer sb = new StringBuffer();
for(int a=0; a<10000; a++) {
sb.append(Hex.bytesToHexString(bs));
}
byte[] rs3 = Hex.hexStringToBytes(sb.toString());
// z.print("rs3.length:", rs3.length); // -> rs3.length:500000
z.print("3-buf:", Time.getNowTime("0"));
List<Byte> lb = new ArrayList<>();
for(int a=0; a<10000; a++) {
for(int i=0; i<bs.length; i++) {
lb.add(bs[i]);
}
}
z.print("4-000:", Time.getNowTime("0"));
byte[] rs4 = new byte[lb.size()];
for(int i=0; i<lb.size(); i++) {
rs4[i] = lb.get(i);
}
z.print("4-lst:", Time.getNowTime("0"));
// z.print("rs4.length:",rs4.length); // -> rs4.length:500000
}
首先我们把每一组循环10000次的for注掉,在方法最后加上以下代码打印一下这四种的结果:
z.print("rs1:", rs1);
z.print("rs2:", rs2);
z.print("rs3:", rs3);
z.print("rs4:", rs4);
// 打印结果:
// 2023-10-11 16:24:41.414/com.zzztest.Test/55 -> rs1:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
// 2023-10-11 16:24:41.414/com.zzztest.Test/56 -> rs2:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
// 2023-10-11 16:24:41.414/com.zzztest.Test/57 -> rs3:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
// 2023-10-11 16:24:41.415/com.zzztest.Test/58 -> rs4:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
我们发现打印出来的rs1 - rs4完全相同与原数组bs完全相同,说明这四种方式都可行,都能得到正确的结果。
注:在测试时发现不能使用new String(bs)和ss.getBytes(),因为这样得到的结果是错误的:
打印语句:z.print("rs2.length:", rs2.length, ",rs2:", rs2);
打印结果:2023-10-11 16:47:58.722/com.zzztest.Test/35 -> rs2.length:70,rs2:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,-17,-65,-67,-17,-65,-67,-17,-65,-67,-17,-65,-67,-17,-65,-67,-17,-65,-67,-17,-65,-67,-17,-65,-67,-17,-65,-67,-17,-65,-67]
这里 rs2的长度是70,与原数组bs长度50不相符,其结果不正确。
执行上述代码测试4种方法的耗时如下:
//2023-10-11 16:52:38.837/com.zzztest.Test/15 -> 0-beg:2023-10-11 16:52:38.746
//2023-10-11 16:52:39.599/com.zzztest.Test/28 -> 1-arr:2023-10-11 16:52:39.599
//2023-10-11 16:52:48.484/com.zzztest.Test/35 -> 2-str:2023-10-11 16:52:48.484
//2023-10-11 16:52:48.526/com.zzztest.Test/42 -> 3-buf:2023-10-11 16:52:48.526
//2023-10-11 16:52:48.533/com.zzztest.Test/49 -> 4-000:2023-10-11 16:52:48.532
//2023-10-11 16:52:48.539/com.zzztest.Test/54 -> 4-lst:2023-10-11 16:52:48.539
从结果可见,
方法1(纯数组拼接)耗时:39599 - 38746 = 853ms
方法2(String拼接)耗时:48484 - 39599 = 8885ms
方法3(StringBuffer拼接)耗时:48526 - 48484 = 42ms
方法4(List集合add)耗时:48539 - 48526 = 13ms
反复测试了几次,方法4耗时波动在13-16ms,这中间多打印了一次4-000,是因为如果最终结果需要转化为byte数组,则一共耗时13-16ms,如果不需要转化成byte数组,直接拿这个ArrayList也可以使用,则只需耗时6-8ms。
附加:
以上测试只是单纯测试每种方法执行时所消耗的时间,这里并未考虑其它因素,例如方法执行时CPU的消耗,内存的消耗,以及方法执行之后所产生的垃圾多少等问题。
关于工具类Hex的两个方法如下:
// byte数组转成16进制字符串
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return "";
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString().toUpperCase();
}
// 16进制字符串转成byte数组
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || "".equals(hexString)) {
byte[] bs = {};
return bs;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}