我有一段代码与a)我用b)代替纯粹是为了易读......
A)
if ( WORD[ INDEX ] == 'A' ) branch = BRANCH.A;
/* B through to Y */
if ( WORD[ INDEX ] == 'Z' ) branch = BRANCH.Z;
b)中
switch ( WORD[ INDEX ] ) {
case 'A' : branch = BRANCH.A; break;
/* B through to Y */
case 'Z' : branch = BRANCH.Z; break;
}
编辑:
下面的一些答案涉及上述方法的替代方法。
我已提供以下内容以提供其使用的背景信息。
我问的问题,上面的问题是因为增加词语的速度在经验上有所改善。
这不是生产代码,而是作为PoC快速入侵。
以下似乎是对思想实验失败的确认。
我可能需要比我目前使用的词语更大的词汇。
失败的原因是我没有考虑到仍需要内存的空引用。(doh!)
public class Dictionary {
private static Dictionary ROOT;
private boolean terminus;
private Dictionary A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z;
private static Dictionary instantiate( final Dictionary DICTIONARY ) {
return ( DICTIONARY == null ) ? new Dictionary() : DICTIONARY;
}
private Dictionary() {
this.terminus = false;
this.A = this.B = this.C = this.D = this.E = this.F = this.G = this.H = this.I = this.J = this.K = this.L = this.M = this.N = this.O = this.P = this.Q = this.R = this.S = this.T = this.U = this.V = this.W = this.X = this.Y = this.Z = null;
}
public static void add( final String...STRINGS ) {
Dictionary.ROOT = Dictionary.instantiate( Dictionary.ROOT );
for ( final String STRING : STRINGS ) Dictionary.add( STRING.toUpperCase().toCharArray(), Dictionary.ROOT , 0, STRING.length() - 1 );
}
private static void add( final char[] WORD, final Dictionary BRANCH, final int INDEX, final int INDEX_LIMIT ) {
Dictionary branch = null;
switch ( WORD[ INDEX ] ) {
case 'A' : branch = BRANCH.A = Dictionary.instantiate( BRANCH.A ); break;
case 'B' : branch = BRANCH.B = Dictionary.instantiate( BRANCH.B ); break;
case 'C' : branch = BRANCH.C = Dictionary.instantiate( BRANCH.C ); break;
case 'D' : branch = BRANCH.D = Dictionary.instantiate( BRANCH.D ); break;
case 'E' : branch = BRANCH.E = Dictionary.instantiate( BRANCH.E ); break;
case 'F' : branch = BRANCH.F = Dictionary.instantiate( BRANCH.F ); break;
case 'G' : branch = BRANCH.G = Dictionary.instantiate( BRANCH.G ); break;
case 'H' : branch = BRANCH.H = Dictionary.instantiate( BRANCH.H ); break;
case 'I' : branch = BRANCH.I = Dictionary.instantiate( BRANCH.I ); break;
case 'J' : branch = BRANCH.J = Dictionary.instantiate( BRANCH.J ); break;
case 'K' : branch = BRANCH.K = Dictionary.instantiate( BRANCH.K ); break;
case 'L' : branch = BRANCH.L = Dictionary.instantiate( BRANCH.L ); break;
case 'M' : branch = BRANCH.M = Dictionary.instantiate( BRANCH.M ); break;
case 'N' : branch = BRANCH.N = Dictionary.instantiate( BRANCH.N ); break;
case 'O' : branch = BRANCH.O = Dictionary.instantiate( BRANCH.O ); break;
case 'P' : branch = BRANCH.P = Dictionary.instantiate( BRANCH.P ); break;
case 'Q' : branch = BRANCH.Q = Dictionary.instantiate( BRANCH.Q ); break;
case 'R' : branch = BRANCH.R = Dictionary.instantiate( BRANCH.R ); break;
case 'S' : branch = BRANCH.S = Dictionary.instantiate( BRANCH.S ); break;
case 'T' : branch = BRANCH.T = Dictionary.instantiate( BRANCH.T ); break;
case 'U' : branch = BRANCH.U = Dictionary.instantiate( BRANCH.U ); break;
case 'V' : branch = BRANCH.V = Dictionary.instantiate( BRANCH.V ); break;
case 'W' : branch = BRANCH.W = Dictionary.instantiate( BRANCH.W ); break;
case 'X' : branch = BRANCH.X = Dictionary.instantiate( BRANCH.X ); break;
case 'Y' : branch = BRANCH.Y = Dictionary.instantiate( BRANCH.Y ); break;
case 'Z' : branch = BRANCH.Z = Dictionary.instantiate( BRANCH.Z ); break;
}
if ( INDEX == INDEX_LIMIT ) branch.terminus = true;
else Dictionary.add( WORD, branch, INDEX + 1, INDEX_LIMIT );
}
public static boolean is( final String STRING ) {
Dictionary.ROOT = Dictionary.instantiate( Dictionary.ROOT );
return Dictionary.is( STRING.toUpperCase().toCharArray(), Dictionary.ROOT, 0, STRING.length() - 1 );
}
private static boolean is( final char[] WORD, final Dictionary BRANCH, final int INDEX, final int INDEX_LIMIT ) {
Dictionary branch = null;
switch ( WORD[ INDEX ] ) {
case 'A' : branch = BRANCH.A; break;
case 'B' : branch = BRANCH.B; break;
case 'C' : branch = BRANCH.C; break;
case 'D' : branch = BRANCH.D; break;
case 'E' : branch = BRANCH.E; break;
case 'F' : branch = BRANCH.F; break;
case 'G' : branch = BRANCH.G; break;
case 'H' : branch = BRANCH.H; break;
case 'I' : branch = BRANCH.I; break;
case 'J' : branch = BRANCH.J; break;
case 'K' : branch = BRANCH.K; break;
case 'L' : branch = BRANCH.L; break;
case 'M' : branch = BRANCH.M; break;
case 'N' : branch = BRANCH.N; break;
case 'O' : branch = BRANCH.O; break;
case 'P' : branch = BRANCH.P; break;
case 'Q' : branch = BRANCH.Q; break;
case 'R' : branch = BRANCH.R; break;
case 'S' : branch = BRANCH.S; break;
case 'T' : branch = BRANCH.T; break;
case 'U' : branch = BRANCH.U; break;
case 'V' : branch = BRANCH.V; break;
case 'W' : branch = BRANCH.W; break;
case 'X' : branch = BRANCH.X; break;
case 'Y' : branch = BRANCH.Y; break;
case 'Z' : branch = BRANCH.Z; break;
}
if ( branch == null ) return false;
if ( INDEX == INDEX_LIMIT ) return branch.terminus;
else return Dictionary.is( WORD, branch, INDEX + 1, INDEX_LIMIT );
}
}
答案 0 :(得分:24)
不要担心性能;使用最能表达您正在做的事情的语法。只有在你(a)表现出性能不足之后; (b)将其本地化为相关例程,只有这样你才应该担心表现。对于我的钱,案例语法在这里更合适。
答案 1 :(得分:21)
在字节码中有两种形式的切换:tableswitch
和lookupswitch
。一个假设密集的密钥,另一个密集。请参阅compiling switch in the JVM spec的说明。对于枚举,找到序号,然后代码继续作为int
案例。我不完全确定如何实现JDK7中提议的switch
String
小功能。
但是,大量使用的代码通常在任何合理的JVM中编译。优化者并非完全愚蠢。不要担心,并按照通常的启发式方法进行优化。
答案 2 :(得分:7)
看起来你已经枚举了这些值,所以也许枚举是按顺序的?
enum BRANCH {
A,B, ... Y,Z;
}
然后在你的代码中:
BRANCH branch = BRANCH.valueOf( WORD[ INDEX ] );
此外,根据“A”的对象标识,您的代码中可能存在"A" == "A"
可能为false的错误。
答案 3 :(得分:4)
对你的问题不是一个完全的答案,但你的代码中确实存在一个错误,你应该在每个案例后休息一下:
switch ( WORD[ INDEX ] ) {
case 'A' : branch = BRANCH.A; break;
/* B through to Y */
case 'Z' : branch = BRANCH.Z; break;
}
我不认为这里的性能差异太大,但如果你真的关心性能,如果这个代码经常执行,那么这是另一种选择:
// Warning, untested code.
BRANCH[] branchLookUp = {BRANCH.A, BRANCH.B, ..., BRANCH.Z};
branch = branchLookUp[WORD[INDEX] - 'A'];
请务必将其封装并记录下来。
答案 4 :(得分:3)
老实说,在这种情况下,我认为表现并不重要。这完全取决于编译器及其优化。
答案 5 :(得分:3)
如果你有一个带有连续积分值的switch语句,这取决于语言,它可以优化到分支表,这非常快。反正它并不慢!
此外,使用if / else if对于诸如此类案例互相排斥的情况是否会有所改进。在匹配A之后再做25次检查是没有意义的。
但基本上,任何性能差异都可以忽略不计,你应该使用最正确的语法,在本例中是switch语句。确保将您的案件与休息分开。
答案 6 :(得分:3)
这是一种避免所有案例陈述的方法。
import java.util.HashMap;
public class Dictionary {
private static Dictionary ROOT;
private boolean terminus;
private final HashMap<Character, Dictionary> dictionaries = new HashMap<Character, Dictionary>();
private void ensureBranch(char c) {
if (getBranch(c) != null)
return;
dictionaries.put(c, new Dictionary());
}
private Dictionary getBranch(char c) {
return dictionaries.get(c);
}
public static boolean is(final String string) {
ensureRoot();
return is(chars(string), ROOT, 0, string.length() - 1);
}
public static void add(final String... strings) {
ensureRoot();
for (final String string : strings)
add(chars(string), ROOT, 0, string.length() - 1);
}
private static void ensureRoot() {
if (ROOT == null)
ROOT = new Dictionary();
}
private static char[] chars(final String string) {
return string.toUpperCase().toCharArray();
}
private Dictionary() {
this.terminus = false;
}
private static void add(final char[] word, final Dictionary dictionary, final int index, final int limit) {
Dictionary branch = getBranch(word, dictionary, index);
if (index == limit)
branch.terminus = true;
else
add(word, branch, index + 1, limit);
}
private static Dictionary getBranch(final char[] word, final Dictionary dictionary, final int index) {
final char c = word[index];
dictionary.ensureBranch(c);
return dictionary.getBranch(c);
}
private static boolean is(final char[] word, final Dictionary dictionary, final int index, final int limit) {
Dictionary branch = dictionary.getBranch(word[index]);
if (branch == null)
return false;
if (index == limit)
return branch.terminus;
return is(word, branch, index + 1, limit);
}
}
答案 7 :(得分:2)
我知道这不是你要求的,但你不是这样做的吗?
public class Dictionary {
private static final Set<String> WORDS = new HashSet<String>();
public static void add(final String... STRINGS) {
for (String str : STRINGS) {
WORDS.add(str.toUpperCase());
}
}
public static boolean is(final String STRING) {
return WORDS.contains(STRING.toUpperCase());
}
}
您只是在寻找更高效的内存吗?
答案 8 :(得分:1)
switch
语句应使用哈希来选择要转到的大小写。从那里开始,如果没有break
语句,也会运行每个后续案例。例如,使用您的代码,如果您打开X,它将立即转到X,然后是Y,然后转到Z.请参阅Java Tutorial。
答案 9 :(得分:1)
假设编译器找不到任何聪明的东西,switch
应该是对数的并且if
是线性的。但是长switch
es很难阅读并且容易出错 - 如上所述,你上面的开关没有任何中断,并且它会在所有情况下失败。
为什么不预先填充Map
,而只使用Map.get()
?
private static final Map<Char, Whatever> BRANCHES = Collections.unmodifiableMap(new HashMap<Char, Whatever>() {{
put('A', BRANCH.A);
...
put('Z', BRANCH.Z);
}}
public void getBranch(char[] WORD, int INDEX) {
return BRANCHES.get(WORD[INDEX]);
}
如上所述,如果BRANCH
是Enum
,则此行为应该恰好位于Enum
。
(这里有什么WORD
,INDEX
和BRANCH
?从名称来看,它们应该是常量,但你不能真正拥有常量数组 - 内容是alwyas modifiable;创建一个常量“struct”没有多大意义;并且基于常量的iffing或切换肯定没有多大意义....)
答案 10 :(得分:0)
我认为这更像是一个关于风格而不是表现的问题。我认为在这种情况下,switch语句比if更合适。我不确定性能有多大差异。