我想从表示十六进制值(大写或小写)的字符转换为字节,如
'0'->0, '1' -> 1, 'A' -> 10, 'a' -> 10, 'f' -> 15 etc...
我会经常调用这种方法,所以性能很重要.有没有比使用预先初始化HashMap
从中获取值更快的方法?
回答
看起来这是使用switch-case和Jon Skeet的直接计算解决方案之间的一个折腾 - 尽管如此,交换机案例解决方案似乎有点微不足道.Greg的阵列方法胜出.以下是各种方法的200,000,000次运行的性能结果(以ms为单位):
Character.getNumericValue: 8360 Character.digit: 8453 HashMap: 15109 Greg's Array Method: 6656 JonSkeet's Direct Method: 7344 Switch: 7281
多谢你们!
基准方法代码
你好,JonSkeet,你是老竞争对手.;-)
public class ScratchPad { private static final int NUMBER_OF_RUNS = 200000000; static byte res; static HashMapmap = new HashMap () {{ put( Character.valueOf( '0' ), Byte.valueOf( (byte )0 )); put( Character.valueOf( '1' ), Byte.valueOf( (byte )1 )); put( Character.valueOf( '2' ), Byte.valueOf( (byte )2 )); put( Character.valueOf( '3' ), Byte.valueOf( (byte )3 )); put( Character.valueOf( '4' ), Byte.valueOf( (byte )4 )); put( Character.valueOf( '5' ), Byte.valueOf( (byte )5 )); put( Character.valueOf( '6' ), Byte.valueOf( (byte )6 )); put( Character.valueOf( '7' ), Byte.valueOf( (byte )7 )); put( Character.valueOf( '8' ), Byte.valueOf( (byte )8 )); put( Character.valueOf( '9' ), Byte.valueOf( (byte )9 )); put( Character.valueOf( 'a' ), Byte.valueOf( (byte )10 )); put( Character.valueOf( 'b' ), Byte.valueOf( (byte )11 )); put( Character.valueOf( 'c' ), Byte.valueOf( (byte )12 )); put( Character.valueOf( 'd' ), Byte.valueOf( (byte )13 )); put( Character.valueOf( 'e' ), Byte.valueOf( (byte )14 )); put( Character.valueOf( 'f' ), Byte.valueOf( (byte )15 )); put( Character.valueOf( 'A' ), Byte.valueOf( (byte )10 )); put( Character.valueOf( 'B' ), Byte.valueOf( (byte )11 )); put( Character.valueOf( 'C' ), Byte.valueOf( (byte )12 )); put( Character.valueOf( 'D' ), Byte.valueOf( (byte )13 )); put( Character.valueOf( 'E' ), Byte.valueOf( (byte )14 )); put( Character.valueOf( 'F' ), Byte.valueOf( (byte )15 )); }}; static int[] charValues = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10, 11, 12, 13,14,15}; static char[] cs = new char[]{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F'}; public static void main(String args[]) throws Exception { long time = System.currentTimeMillis(); for( int i = 0; i < NUMBER_OF_RUNS; i++ ) { res = getNumericValue( i ); } System.out.println( "Character.getNumericValue:" ); System.out.println( System.currentTimeMillis()-time ); time = System.currentTimeMillis(); for( int i = 0; i < NUMBER_OF_RUNS; i++ ) { res = getDigit( i ); } System.out.println( "Character.digit:" ); System.out.println( System.currentTimeMillis()-time ); time = System.currentTimeMillis(); for( int i = 0; i < NUMBER_OF_RUNS; i++ ) { try { res = getValueFromArray( i ); } catch (IllegalArgumentException e) { } } System.out.println( "Array:" ); System.out.println( System.currentTimeMillis()-time ); time = System.currentTimeMillis(); for( int i = 0; i < NUMBER_OF_RUNS; i++ ) { res = getValueFromHashMap( i ); } System.out.println( "HashMap :" ); System.out.println( System.currentTimeMillis()-time ); time = System.currentTimeMillis(); for( int i = 0; i < NUMBER_OF_RUNS; i++ ) { char c = cs[i%cs.length]; res = getValueFromComputeMethod( c ); } System.out.println( "JonSkeet's Direct Method:" ); System.out.println( System.currentTimeMillis()-time ); time = System.currentTimeMillis(); for( int i = 0; i < NUMBER_OF_RUNS; i++ ) { res = getValueFromSwitch( i ); } System.out.println( "Switch:" ); System.out.println( System.currentTimeMillis()-time ); } private static byte getValueFromSwitch( int i ) { byte res; char ch = cs[i%cs.length]; switch( ch ) { case '0': res = 0; break; case '1': res = 1; break; case '2': res = 2; break; case '3': res = 3; break; case '4': res = 4; break; case '5': res = 5; break; case '6': res = 6; break; case '7': res = 7; break; case '8': res = 8; break; case '9': res = 9; break; case 'a': case 'A': res = 10; break; case 'b': case 'B': res = 11; break; case 'c': case 'C': res = 12; break; case 'd': case 'D': res = 13; break; case 'e': case 'E': res = 14; break; case 'f': case 'F': res = 15; break; default: throw new RuntimeException("unknown hex character: " + ch ); } return res; } private static byte getValueFromComputeMethod( char c ) { byte result = 0; if (c >= '0' && c <= '9') { result = (byte)(c - '0'); } if (c >= 'a' && c <= 'f') { result = (byte)(c - 'a' + 10); } if (c >= 'A' && c <= 'F') { result = (byte)(c - 'A' + 10); } return result; } private static byte getValueFromHashMap( int i ) { return map.get( Character.valueOf( cs[i%cs.length] ) ).byteValue(); } private static byte getValueFromArray( int i ) { char c = cs[i%cs.length]; if (c < '0' || c > 'f') { throw new IllegalArgumentException(); } byte result = (byte)charValues[c-'0']; if (res < 0) { throw new IllegalArgumentException(); } return result; } private static byte getDigit( int i ) { return (byte)Character.digit( cs[i%cs.length], 16 ); } private static byte getNumericValue( int i ) { return (byte)Character.getNumericValue( cs[i%cs.length] ); } }
Greg Hewgill.. 16
预初始化的数组比HashMap快.像这样的东西:
int CharValues['f'-'0'+1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, ... -1, 10, 11, 12, ...}; if (c < '0' || c > 'f') { throw new IllegalArgumentException(); } int n = CharValues[c-'0']; if (n < 0) { throw new IllegalArgumentException(); } // n contains the digit value
您应该将此方法与其他方法(例如Jon Skeet的直接方法)进行基准测试,以确定哪种方法对您的应用程序来说最快.
预初始化的数组比HashMap快.像这样的东西:
int CharValues['f'-'0'+1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, ... -1, 10, 11, 12, ...}; if (c < '0' || c > 'f') { throw new IllegalArgumentException(); } int n = CharValues[c-'0']; if (n < 0) { throw new IllegalArgumentException(); } // n contains the digit value
您应该将此方法与其他方法(例如Jon Skeet的直接方法)进行基准测试,以确定哪种方法对您的应用程序来说最快.
哈希表会相对较慢.这很快:
if (c >= '0' && c <= '9') { return c - '0'; } if (c >= 'a' && c <= 'f') { return c - 'a' + 10; } if (c >= 'A' && c <= 'F') { return c - 'A' + 10; } throw new IllegalArgumentException();
另一种选择是尝试切换/ case语句.如果数组在缓存中,则数组可能没问题,但是错过可能很昂贵.