Java性能中的十六进制到字符串太慢



我的android程序有以下方法,用Java编写。

该方法接收一个十六进制字符串,并返回一个用ascii编写的相同文本的字符串。

public static String hexToString(String hex)
{
    StringBuilder sb = new StringBuilder();
    for (int count = 0; count < hex.length() - 1; count += 2)
    {
        String output = hex.substring(count, (count + 2));    //grab the hex in pairs
        int decimal = Integer.parseInt(output, 16);    //convert hex to decimal
        sb.append((char)decimal);    //convert the decimal to character
    }
    return sb.toString();
}

该方法运行良好,但我的程序非常耗时,并且该方法可能被调用数万次。当分析我的程序的慢比特时,这种方法占用了太多时间,因为:

Integer.parseInt(output, 16);

hex.substring(count, (count + 2));

按最慢优先的顺序。

有人知道实现同样目标的更快方法吗?

不要在每次迭代中创建新的String。提高性能的一种方法是使用char数组并对每个字符应用数学运算。

public static String hexToString(String hex) {
    StringBuilder sb = new StringBuilder();
    char[] hexData = hex.toCharArray();
    for (int count = 0; count < hexData.length - 1; count += 2) {
        int firstDigit = Character.digit(hexData[count], 16);
        int lastDigit = Character.digit(hexData[count + 1], 16);
        int decimal = firstDigit * 16 + lastDigit;
        sb.append((char)decimal);
    }
    return sb.toString();
}

有关此方法的更多信息:

  • Character#digit

此外,如果您成对解析十六进制字符串,您可以使用@L7ColWinters建议的查找表:

private static final Map<String, Character> lookupHex = new HashMap<String, Character>();
static {
    for(int i = 0; i < 256; i++) {
        String key = Integer.toHexString(i);
        Character value = (char)(Integer.parseInt(key, 16));
        lookupHex.put(key, value);
    }
}
public static String hexToString(String hex) {
    StringBuilder sb = new StringBuilder();
    for (int count = 0; count < hex.length() - 1; count += 2) {
        String output = hex.substring(count, (count + 2));
        sb.append((char)lookupHex.get(output));
    }
    return sb.toString();
}

这个怎么样。。。

public static String hexToString(final String str) {
 return new String(new BigInteger(str, 16).toByteArray());
}

另一种选择是只做一些简单的算法:

public static int hexCharToInt(char c)
{
    int result = 0;
    if(c >= 'A' && c <= 'F')
    {
        result += (c - 'A' + 10);
    }
    else if( c >= '0' && c <= '9')
    {
            result += (c - '0');
    }
        return result;
    }
public static String hexToString(String hex)
{
    StringBuilder sb = new StringBuilder();
    for (int count = 0; count < hex.length() - 1; count += 2)
    {
        char c1 = hex.charAt(count);
        char c2 = hex.charAt(count + 1);
        int decimal = hexCharToInt(c1) * 16 + hexCharToInt(c2);
        sb.append((char)decimal);    //convert the decimal to character
    }
    return sb.toString();
}

试试看哪种解决方案在您的系统上效果最好!

此代码取自Apache Commons Codec的Hex类,并进行了一些简化。(删除了一些范围检查等,这对理解这里来说是不必要的。在实践中,你想使用原始实现。)

/**
 * Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The
 * returned array will be half the length of the passed array, as it takes two characters to represent any given
 * byte. An exception is thrown if the passed char array has an odd number of elements.
 * 
 * @param data
 *            An array of characters containing hexadecimal digits
 * @return A byte array containing binary data decoded from the supplied char array.
 * @throws DecoderException
 *             Thrown if an odd number or illegal of characters is supplied
 */
public static byte[] decodeHex(char[] data) throws DecoderException {
    int len = data.length;
    byte[] out = new byte[len >> 1];
    // two characters form the hex value.
    for (int i = 0, j = 0; j < len; i++) {
        int f = Character.digit(data[j], 16) << 4;
        j++;
        f = f | Character.digit(data[j], 16);
        j++;
        out[i] = (byte) (f & 0xFF);
    }
    return out;
}

之后可以使用返回的byte[]来构造String对象。

因此,当使用Apache Commons编解码器时,您的方法如下所示:

public static String hexToString(String hex) throws UnsupportedEncodingException, DecoderException {
    return new String(Hex.decodeHex(hex.toCharArray()), "US-ASCII");
  }

最新更新