2009-06-29 12 views
0

Ich muss oft aus dem String-Code in seinen Enum Typ übersetzen. Siehe Ausschnitt unten. Ich denke, das ist sehr ineffizient. Wie kann ich verbessern das Verfahren deref so dass:Wie verbessert man diesen Aufzählungstyp?

  • Es wird THREAD sein.
  • Es ist schneller.

Code:

public enum SigninErrorCodes 
{ 
    InvalidUser("a0"), InvalidPassword("b5"), NoServerResponse("s2"); 

    SigninErrorCodes(String code) { _code = code; } 

    public String code() { return _code; } 

    public static SigninErrorCodes deref(String code) 
    { 
     SigninErrorCodes[] verbs = values(); 
     Map<String, SigninErrorCodes> m = new HashMap<String,SigninErrorCodes>(3); 
     for(int i=0; i<verbs.length; i++) 
     m.put(verbs[i].code(), verbs[i]); 

     return m.get(code); 
    } 

    private final String _code; 
} 

Antwort

1

Wenn die Liste der möglichen Werte wirklich so klein ist, dann von Hand die Methode schreiben . Der Leistungsvorteil einer Hashtabelle wird im Vergleich zu einem Vergleich mit nur 3 Strings nicht wahrgenommen.

Aber wenn, wie ich vermute, die Anzahl der Werte ist viel größer als Sie geschrieben haben, dann macht eine Karte Sinn, in diesem Fall sollten Sie die Karte zwischenspeichern, wenn die Aufzählung erstellt wird.

public enum SigninErrorCodes { 
    InvalidUser("a0"), InvalidPassword("b5"), NoServerResponse("s2"); 

    private final String _code; 
    SigninErrorCodes(String code) { _code = code; } 
    public String code() { return _code; } 

    private static final Map<String, SigninErrorCodes> m; 

    static { 
    SigninErrorCodes[] verbs = values(); 
    m = new HashMap<String,SigninErrorCodes>(verbs.length * 2); 
    for(int i=0; i<verbs.length; i++) 
     m.put(verbs[i].code(), verbs[i]); 
    } 


    public static SigninErrorCodes deref(String code) { 
    return m.get(code); 
    } 
} 

Beachten Sie, dass die beste Größe einer Hash-Karte zu geben, ist nicht die Anzahl der Elemente, sondern um das Doppelte. Eine niedrigere Zahl führt zu Schlüsselkonflikten.

+0

Marcus, das ist interessant. Können Sie mich auf eine Quelle verweisen, die sagt, HashMaps sollten initialisiert werden, um ihre erwarteten Schlüssel zu verdoppeln? – Yishai

+1

Wenn Sie die JavaDoc für HashMap betrachten, achten Sie genau auf die initialCapacity: http://java.sun.com/javase/6/docs/api/java/util/HashMap.html. 2 mal könnte es dehnen, aber es tut nicht weh hier. – akf

+0

Ich glaube, 0,70-0,75 ist der übliche Bereich für den Ladefaktor (siehe Wikipedia, IIRC). Niedrige Ladefaktoren machen die Dinge durch Cache-Misses langsamer. –

2

Enum hat eine statische Methode namens [valueOf] [1] zu handhaben. Sie würden folgendes tun:

Beachten Sie, dass die Fehlerbehandlung hier versucht, die gleichen Ergebnisse wie Ihre ursprüngliche Methode zu imitieren. Das ist möglicherweise nicht so, wie Sie mit einem ungültigen Code umgehen möchten, oder Sie gehen davon aus, dass zur Laufzeit keine ungültigen Codes vorhanden sind, sodass Sie die Ausnahmen einfach weitergeben würden.

Das oben genannte gilt, wenn Sie Ihre Enums nach dem Code benennen können (etwas, das in diesem Fall sehr wünschenswert wäre, es scheint).

Wenn das aus irgendeinem Grund nicht möglich ist, können Sie ganz einfach eine Hashtabelle (die synchronisiert ist) als Mapimplementierung in einem statischen Feld speichern und im Konstruktor der Enumeration (map) auffüllen. put (_code, this.getClass());).

Wenn die übermäßige Synchronisation zu leistungsmäßig ist, dann sehen Sie sich die Karte in einem ThreadLocal an.

[1]: http://java.sun.com/javase/6/docs/api/java/lang/Enum.html#valueOf(java.lang.Class, java.lang.String)

+1

Sie können auch einfach anrufen valueOf als statisches Element: SigninErrorCodes.valueOf (Code); Abhängig von dem Programm können jedoch die Kosten einer Ausnahme für jeden verpassten Anruf hoch sein. –

1

Eine Sache, die es schneller machen wird, ist die Karte in einer statischen Variablen halten, so dass Sie es nicht neu berechnen müssen, um jedes Mal; weiß nicht über den Thread sicher Teil.

public enum SigninErrorCodes { 
    InvalidUser("a0"), InvalidPassword("b5"), NoServerResponse("s2"); 

    private static Map<String, SigninErrorCodes> m = new HashMap<String,SigninErrorCodes>(3); 

    SigninErrorCodes(String code) { _code = code; m.put(code, this); } 

    public String code() { return _code; } 

    public static SigninErrorCodes deref(String code) 
    { 
     return m.get(code); 
    } 
} 

Wenn die Code-Strings gültige Bezeichner sind, können Sie einfach direkt solche, die als Aufzählungen Werte verwenden:

public enum SigninErrorCodes { a0, b5, s2; } 

// and then when you need to look it up, use: 
SigninErrorCodes.valueOf("b5"); 
Verwandte Themen