Estamos implementando un adaptador para Jaxen (una biblioteca XPath para Java) que nos permite usar XPath para acceder al modelo de datos de nuestra aplicación.
Esto se realiza mediante la implementación de clases que asignan cadenas (que nos pasó de Jaxen) a elementos de nuestro modelo de datos. Estimamos que necesitaremos alrededor de 100 clases con más de 1000 comparaciones de cadenas en total.
Creo que la mejor manera de hacer esto es simple si / otras declaraciones con las cadenas escritas directamente en el código, en lugar de definir cada cadena como una constante. Por ejemplo:
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();
...
Sin embargo, siempre me enseñaron que no debemos incrustar valores de cadena directamente en el código, sino crear constantes de cadena en su lugar. Eso se vería así:
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();
...
En este caso, creo que es una mala idea. La constante solo se usará una vez, en el getNode()
método. Usar las cadenas directamente es tan fácil de leer y entender como usar constantes, y nos ahorra escribir al menos mil líneas de código.
Entonces, ¿hay alguna razón para definir constantes de cadena para un solo uso? ¿O es aceptable usar cadenas directamente?
PD. Antes de que alguien sugiera usar enumeraciones, creamos un prototipo de eso, pero la conversión de enumeración es 15 veces más lenta que la simple comparación de cadenas, por lo que no se está considerando.
Conclusión: las respuestas a continuación ampliaron el alcance de esta pregunta más allá de las constantes de cadena, por lo que tengo dos conclusiones:
- Probablemente esté bien usar las cadenas directamente en lugar de las constantes de cadena en este escenario, pero
- Hay formas de evitar el uso de cadenas, lo que podría ser mejor.
Así que voy a probar la técnica de envoltura que evita las cadenas por completo. Desafortunadamente, no podemos usar la instrucción de cambio de cadena porque todavía no estamos en Java 7. Sin embargo, en última instancia, creo que la mejor respuesta para nosotros es probar cada técnica y evaluar su rendimiento. La realidad es que si una técnica es claramente más rápida, entonces probablemente la elegiremos independientemente de su belleza o adhesión a la convención.
fuente
switch
etiquetas. Use un interruptor en lugar deif
cascadas.Respuestas:
Prueba esto. La reflexión inicial es ciertamente costosa, pero si la va a usar muchas veces, lo cual creo que lo hará, esta es sin duda una mejor solución de lo que está proponiendo. No me gusta usar la reflexión, pero me encuentro usándola cuando no me gusta la alternativa a la reflexión. Creo que esto le ahorrará mucho dolor de cabeza a su equipo, pero debe pasar el nombre del método (en minúsculas).
En otras palabras, en lugar de pasar "nombre", pasaría "nombre completo" porque el nombre del método get es "getFullName ()".
Si necesita acceder a los datos contenidos en los miembros de contacto, puede considerar crear una clase de contenedor para contacto que tenga todos los métodos para acceder a la información requerida. Esto también sería útil para garantizar que los nombres de los campos de acceso siempre serán los mismos (es decir, si la clase contenedora tiene getFullName () y llama con el nombre completo, siempre funcionará incluso si se ha cambiado el nombre del contacto getFullName (). causaría un error de compilación antes de permitirle hacer eso).
Esta solución me ha salvado varias veces, es decir, cuando quería tener una única representación de datos para usar en tablas de datos jsf y cuando esos datos debían exportarse a un informe usando jasper (que en mi experiencia no maneja bien los complicados accesores de objetos) .
fuente
.invoke()
, porque elimina completamente las constantes de cadena. No estoy tan interesado en la reflexión en tiempo de ejecución para configurar el mapa, aunque tal vez ejecutargetMethodMapping()
en unstatic
bloque estaría bien para que suceda al inicio en lugar de una vez que el sistema se está ejecutando.Si es posible, use Java 7, que le permite usar cadenas en las
switch
declaraciones.De http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
No he medido, pero creo que las declaraciones de cambio se compilan en una tabla de salto en lugar de una larga lista de comparaciones. Esto debería ser aún más rápido.
Con respecto a su pregunta real: si solo la usa una vez, no necesita convertirla en una constante. Sin embargo, considere que una constante puede documentarse y aparece en Javadoc. Esto puede ser importante para valores de cadena no triviales.
fuente
Si va a mantener esto (realice algún tipo de cambio no trivial), podría considerar usar algún tipo de generación de código basada en anotaciones (tal vez a través de CGLib ) o incluso solo un script que escriba todo el código para usted. Imagine la cantidad de errores tipográficos y errores que podrían aparecer con el enfoque que está considerando ...
fuente
object.getAddress().getCountry()
) que es difícil de representar con anotaciones. Las comparaciones de cadenas if / else no son bonitas, pero son rápidas, flexibles, fáciles de entender y fáciles de probar.Todavía usaría constantes definidas en la parte superior de sus clases. Hace que su código sea más fácil de mantener, ya que es más fácil ver qué se puede cambiar más adelante (si es necesario). Por ejemplo,
"first_name"
podría convertirse"firstName"
en algún momento posterior.fuente
Si su nomenclatura es coherente (también
"some_whatever"
se asigna agetSomeWhatever()
), puede usar la reflexión para determinar y ejecutar el método get.fuente
Supongo que el procesamiento de anotaciones podría ser la solución, incluso sin anotaciones. Es lo que puede generar todo el código aburrido para usted. La desventaja es que obtendrá N clases generadas para N clases de modelos. Tampoco puede agregar nada a una clase existente, pero escribir algo como
una vez por clase no debería ser un problema. Alternativamente, podrías escribir algo como
en una superclase común
Puede usar la reflexión en lugar del procesamiento de anotaciones para la generación de código. La desventaja es que necesita su código para compilar antes de poder usar la reflexión sobre él. Esto significa que no puede confiar en el código generado en sus clases de modelo, a menos que genere algunos stubs.
También consideraría el uso directo de la reflexión. Claro, la reflexión es lenta, pero ¿por qué es lenta? Es porque tiene que hacer todo lo que necesita hacer, por ejemplo, activar el nombre del campo.
fuente