鲁迅先生的名文孔乙己中,孔乙己纠结于茴香豆的茴字有多种写法,可惜小孩子不愿意学,可惜了孔乙己的一片良苦用心。
一个功能,不同的程序员的实现,基于各种因素,可能是千差万别的。即使是同一个程序员,一般也会有多种方式来完成该程序的编写。面对各种不同的可能实现方式,挑选出适合当前场景的实现,就变成了程序员责无旁贷的任务。
/**
* 这个是最早的程序版本,把一个字符串转换成一个16进制编码的字符串。
* 看到这段代码的时候,第一反应是怎么不用StringBuilder。而是字符串相加。
* 其次,这个是一个常用的工具类,每天的调用量很大,性能看上去不怎么好。
* */
public static String str2HexString_0(String str) {
String ret = "";
byte[] b = str.getBytes();
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
}
return ret;
}
/**
* 第一次尝试修改。核心思想是用StringBuilder代替String。展开数字对String的转换,避免调用toUpperCase方法。
* */
public static String str2HexString_1(String str) {
StringBuilder sb = new StringBuilder(str.length() << 1);
byte[] data = str.getBytes();
for (int i = 0; i < data.length; i++) {
int left = (data[i] & 0xF0) >> 4;
append(sb, left);
int right = data[i] & 0x0F;
append(sb, right);
}
return sb.toString();
}
private static void append(StringBuilder sb, int i) {
switch (i) {
case 0:
sb.append("0");
break;
case 1:
sb.append("1");
break;
case 2:
sb.append("2");
break;
case 3:
sb.append("3");
break;
case 4:
sb.append("4");
break;
case 5:
sb.append("5");
break;
case 6:
sb.append("6");
break;
case 7:
sb.append("7");
break;
case 8:
sb.append("8");
break;
case 9:
sb.append("9");
break;
case 10:
sb.append("A");
break;
case 11:
sb.append("B");
break;
case 12:
sb.append("C");
break;
case 13:
sb.append("D");
break;
case 14:
sb.append("E");
break;
case 15:
sb.append("F");
break;
default:
break;
}
}
/**
* 测试发现,第一次的修改速度提高了。但是code变长了,看起来不是很舒服。 想了想不用switch是可以提高code的简洁程度的。
* 于是有了第2次修改。
* */
public static String str2HexString_2(String str) {
StringBuilder sb = new StringBuilder(str.length() << 1);
byte[] data = str.getBytes();
for (int i = 0; i < data.length; i++) {
int left = (data[i] & 0xF0) >> 4;
sb.append("0123456789ABCDEF".charAt(left));
int right = data[i] & 0x0F;
sb.append("0123456789ABCDEF".charAt(right));
}
return sb.toString();
}
/** 想了想用数组不用charAt会不会更快呢。于是有了下面的版本。 */
public static String str2HexString_3(String str) {
StringBuilder sb = new StringBuilder(str.length() << 1);
byte[] data = str.getBytes();
for (int i = 0; i < data.length; i++) {
int left = (data[i] & 0xF0) >> 4;
sb.append(digit2string[left]);
int right = data[i] & 0x0F;
sb.append(digit2string[right]);
}
return sb.toString();
}
private static final String[] digit2string = { "0", "1", "2", "3", "4",
"5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", };
/**
* 测试发现第3次修改的性能不怎么样。而且code不易读了。算是一个失败的修改。
* 出去抽了一根烟,突然醒悟到为什么一定要用StringBuilder呢,
* 这个程序实质上就是一个对数据的操作。既然是对数据的操作,那就直接操作数据好了。干嘛要多绕一圈呢。 于是有了下面的版本。
* */
public static String str2HexString_4(String str) {
byte[] oldData = str.getBytes();
char[] tmpData = new char[oldData.length << 1];
for (int i = 0; i < oldData.length; i++) {
int left = (oldData[i] & 0xF0) >> 4;
tmpData[i << 1] = "0123456789ABCDEF".charAt(left);
int right = oldData[i] & 0x0F;
tmpData[(i << 1) + 1] = "0123456789ABCDEF".charAt(right);
}
return new String(tmpData);
}
/** 网友gdpglc的思路.*/
public static String str2HexString_5(String str) {
byte[] oldData = str.getBytes();
char[] tmpData = new char[oldData.length << 1];
for (int i = 0; i < oldData.length; i++) {
int left = (oldData[i] & 0xF0) >> 4;
tmpData[i << 1] = digit2char[left];
int right = oldData[i] & 0x0F;
tmpData[(i << 1) + 1] = digit2char[right];
}
return new String(tmpData);
}
private static final char[] digit2char = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', };
/**
* 返回一个随机的字符串。150是基于该程序使用场景的抽样得到的长度。
* */
private static String getRandomString() {
StringBuilder sb = new StringBuilder();
Random r = new Random();
int length = 150 + r.nextInt(50);
for (int i = 0; i < length; i++) {
sb.append('a' + r.nextInt(26));
}
return sb.toString();
}
/**
* 随机单元测试。 结果见perfResult.txt。
*
* */
@Test
public void test() {
for (int i = 0; i < 100; i++) {
String inputString = getRandomString();
String result_0 = str2HexString_0(inputString);
String result_1 = str2HexString_1(inputString);
String result_2 = str2HexString_2(inputString);
String result_3 = str2HexString_3(inputString);
String result_4 = str2HexString_4(inputString);
String result_5 = str2HexString_5(inputString);
Assert.assertEquals(result_0, result_1);
Assert.assertEquals(result_1, result_2);
Assert.assertEquals(result_2, result_3);
Assert.assertEquals(result_3, result_4);
Assert.assertEquals(result_4, result_5);
Assert.assertEquals(result_5, result_0);
}
}
性能结果报告:
100000次执行的性能结果。
单位ms。
str2HexString_0 132016
str2HexString_1 8906
str2HexString_2 5297
str2HexString_3 7859
str2HexString_4 4203
str2HexString_5 3985