Wir implementieren einen Adapter für Jaxen (eine XPath-Bibliothek für Java), mit dem wir über XPath auf das Datenmodell unserer Anwendung zugreifen können.
Dies geschieht durch die Implementierung von Klassen, die Zeichenfolgen (die uns von Jaxen übergeben wurden) in Elemente unseres Datenmodells abbilden. Wir schätzen, dass wir ungefähr 100 Klassen mit insgesamt über 1000 Zeichenfolgenvergleichen benötigen.
Ich denke, dass der beste Weg, dies zu tun, einfach ist, wenn / else-Anweisungen mit den Zeichenfolgen direkt in den Code geschrieben - anstatt jede Zeichenfolge als Konstante zu definieren. Beispielsweise:
public Object getNode(String name) {
if ("name".equals(name)) {
return contact.getFullName();
} else if ("title".equals(name)) {
return contact.getTitle();
} else if ("first_name".equals(name)) {
return contact.getFirstName();
} else if ("last_name".equals(name)) {
return contact.getLastName();
...
Es wurde mir jedoch immer beigebracht, dass wir keine Zeichenfolgenwerte direkt in Code einbetten sollten, sondern stattdessen Zeichenfolgenkonstanten erstellen sollten. Das würde ungefähr so aussehen:
private static final String NAME = "name";
private static final String TITLE = "title";
private static final String FIRST_NAME = "first_name";
private static final String LAST_NAME = "last_name";
public Object getNode(String name) {
if (NAME.equals(name)) {
return contact.getFullName();
} else if (TITLE.equals(name)) {
return contact.getTitle();
} else if (FIRST_NAME.equals(name)) {
return contact.getFirstName();
} else if (LAST_NAME.equals(name)) {
return contact.getLastName();
...
In diesem Fall halte ich es für eine schlechte Idee. Die Konstante wird in der getNode()
Methode immer nur einmal verwendet. Die direkte Verwendung der Zeichenfolgen ist genauso einfach zu lesen und zu verstehen wie die Verwendung von Konstanten und erspart uns das Schreiben von mindestens tausend Codezeilen.
Gibt es also einen Grund, String-Konstanten für eine einmalige Verwendung zu definieren? Oder ist es akzeptabel, Zeichenfolgen direkt zu verwenden?
PS. Bevor jemand vorschlägt, stattdessen Aufzählungen zu verwenden, haben wir dies als Prototyp erstellt, aber die Aufzählungskonvertierung ist 15-mal langsamer als ein einfacher Zeichenfolgenvergleich, sodass dies nicht berücksichtigt wird.
Schlussfolgerung: Die folgenden Antworten haben den Umfang dieser Frage über reine String-Konstanten hinaus erweitert, sodass ich zwei Schlussfolgerungen ziehen kann:
- In diesem Szenario ist es wahrscheinlich in Ordnung, die Zeichenfolgen direkt anstelle von Zeichenfolgenkonstanten zu verwenden
- Es gibt Möglichkeiten, die Verwendung von Zeichenfolgen zu vermeiden, was möglicherweise besser ist.
Also werde ich die Wrapper-Technik ausprobieren, die Strings komplett vermeidet. Leider können wir die Anweisung string switch nicht verwenden, da wir noch nicht mit Java 7 arbeiten. Letztendlich denke ich jedoch, dass die beste Antwort für uns darin besteht, jede Technik auszuprobieren und ihre Leistung zu bewerten. Die Realität ist, dass wenn eine Technik deutlich schneller ist, wir sie wahrscheinlich unabhängig von ihrer Schönheit oder Konvention wählen werden.
quelle
switch
Labels. Verwenden Sie einen Schalter anstelle vonif
Kaskaden.Antworten:
Versuche dies. Das anfängliche Nachdenken ist sicherlich teuer, aber wenn Sie es, wie ich denke, viele Male verwenden werden, ist dies mit Sicherheit eine bessere Lösung für Ihre Vorschläge. Ich benutze Reflexion nicht gern, aber ich benutze sie, wenn mir die Alternative zur Reflexion nicht gefällt. Ich denke, dass dies Ihrem Team viel Kopfzerbrechen erspart, aber Sie müssen den Namen der Methode (in Kleinbuchstaben) übergeben.
Mit anderen Worten, anstatt "name" zu übergeben, würden Sie "fullname" übergeben, da der Name der get-Methode "getFullName ()" lautet.
Wenn Sie auf Daten zugreifen müssen, die in Kontaktmitgliedern enthalten sind, können Sie eine Wrapper-Klasse für contact erstellen, die über alle Methoden verfügt, um auf alle erforderlichen Informationen zuzugreifen. Dies ist auch nützlich, um sicherzustellen, dass die Namen der Zugriffsfelder immer gleich bleiben (dh wenn die Wrapper-Klasse getFullName () hat und Sie mit fullname aufrufen, funktioniert dies immer, auch wenn getFullName () des Kontakts umbenannt wurde - it würde einen Kompilierungsfehler verursachen, bevor Sie das tun könnten.
Diese Lösung hat mich mehrere Male gerettet, nämlich als ich eine einzige Datendarstellung zur Verwendung in jsf-Datentabellen haben wollte und als diese Daten mit Jasper in einen Bericht exportiert werden mussten (was meiner Erfahrung nach mit komplizierten Objektzugriffen nicht gut zurechtkommt). .
quelle
.invoke()
, weil es ganz auf String-Konstanten verzichtet. Ich bin nicht so begeistert von der Laufzeitreflexion, um die Map einzurichten, obwohl die AusführunggetMethodMapping()
in einemstatic
Block möglicherweise in Ordnung wäre, damit sie beim Start ausgeführt wird und nicht erst, wenn das System ausgeführt wird.Verwenden Sie nach Möglichkeit Java 7, mit dem Sie Strings in
switch
Anweisungen verwenden können.Von http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
Ich habe nicht gemessen, aber ich glaube, dass die switch-Anweisungen zu einer Sprungtabelle kompiliert werden, anstatt zu einer langen Liste von Vergleichen. Dies sollte noch schneller sein.
Zu Ihrer eigentlichen Frage: Wenn Sie sie nur einmal verwenden, müssen Sie sie nicht zu einer Konstanten machen. Beachten Sie jedoch, dass eine Konstante dokumentiert werden kann und in Javadoc angezeigt wird. Dies kann für nicht triviale Zeichenfolgenwerte wichtig sein.
quelle
Wenn Sie dies beibehalten möchten (und niemals irgendwelche nicht trivialen Änderungen vornehmen möchten), könnte ich in Betracht ziehen, entweder eine auf Anmerkungen basierende Codegenerierung (möglicherweise über CGLib ) oder sogar nur ein Skript zu verwenden, das den gesamten Code für Sie schreibt. Stellen Sie sich die Anzahl der Tippfehler und Fehler vor, die sich bei dem von Ihnen in Betracht gezogenen Ansatz einschleichen könnten ...
quelle
object.getAddress().getCountry()
), die mit Anmerkungen nur schwer darstellbar sind. Die if / else-Zeichenfolgenvergleiche sind nicht besonders hübsch, aber sie sind schnell, flexibel, leicht zu verstehen und einfach zu testen.Ich würde immer noch Konstanten verwenden, die oben in Ihren Klassen definiert sind. Dies macht Ihren Code wartungsfreundlicher, da leichter erkennbar ist, was zu einem späteren Zeitpunkt geändert werden kann (falls erforderlich). Könnte zum Beispiel
"first_name"
zu"firstName"
einem späteren Zeitpunkt werden.quelle
Wenn Ihre Benennung konsistent ist (auch bekannt
"some_whatever"
als immer zugeordnetgetSomeWhatever()
), können Sie mithilfe der Reflektion die get-Methode ermitteln und ausführen.quelle
Ich denke, Annotation Processing könnte die Lösung sein, auch ohne Annotationen. Es ist die Sache, die den ganzen langweiligen Code für Sie erzeugen kann. Der Nachteil ist, dass Sie N generierte Klassen für N Modellklassen erhalten. Sie können einer vorhandenen Klasse auch nichts hinzufügen, sondern nur so etwas schreiben
einmal pro klasse sollte kein problem sein. Alternativ könnte man so etwas schreiben
in einer gemeinsamen Oberklasse.
Sie können Reflection anstelle der Annotation-Verarbeitung für die Codegenerierung verwenden. Der Nachteil ist, dass Sie Ihren Code erst kompilieren müssen, bevor Sie ihn reflektieren können. Dies bedeutet, dass Sie sich nicht auf den generierten Code in Ihren Modellklassen verlassen können, es sei denn, Sie generieren einige Stubs.
Ich würde auch die direkte Verwendung von Reflexion in Betracht ziehen. Klar, Reflexion ist langsam, aber warum ist es langsam? Es ist, weil es alle Dinge tun muss, die Sie tun müssen, z. B. den Feldnamen einschalten.
quelle