java - tipos - ¿Usando literales de cadena idénticos en lugar de una variable final?
tipos de variables en java (6)
En los casos que está proporcionando, creo que la principal razón para declararlo como FINAL_STRING
algún lugar es asegurarse de que permanezca en una ubicación centralizada. Solo habrá una instancia de esa cadena constante, pero el primer ejemplo es mucho más fácil de mantener.
Me he encontrado con una clase que incluye múltiples usos de una cadena literal, "foo".
Lo que me gustaría saber es cuáles son los beneficios y el impacto (en términos de creación de objetos, uso de memoria y velocidad) de usar este enfoque en lugar de declarar la Cadena como definitiva y reemplazar todos los literales con la variable final.
Por ejemplo (aunque obviamente no es un uso de palabra real):
private static final String FINAL_STRING = "foo";
public void stringPrinter(){
for(int i=0;i<10;i++){
System.out.println(FINAL_STRING);
}
}
Versus:
public void stringPrinter(){
for(int i=0;i<10;i++){
System.out.println("foo");
}
}
¿Cuál es preferible y por qué (suponiendo que el valor de la cadena se mantendrá constante)?
El resultado anterior (segundo) resultaría en la creación de 10 objetos String o la JVM se daría cuenta de que solo se usa un único literal, y crearía una sola referencia. Si es así, ¿hay alguna ventaja para declarar la cadena como final (como en el primer ejemplo)?
Si el código interpretado reemplaza el literal de cadena con una sola referencia, ¿se aplica eso si ocurre el mismo literal en más de un lugar?
public void stringPrinter(){
for(int i=0;i<5;i++){
System.out.println("foo"); // first occurence
System.out.println("foo"); // second occurence
}
}
Esos literales de cadena se internalizan, por lo que no se crean nuevos objetos de cadena en el bucle. Sin embargo, usar el mismo literal dos veces podría ser un signo para el olor del código; pero no en términos de velocidad o uso de memoria.
La ventaja no está en el rendimiento, sino en la facilidad de mantenimiento y la fiabilidad.
Permítanme tomar un ejemplo real que encontré recientemente. Un programador creó una función que tomó un parámetro String que identificó el tipo de transacción. Luego en el programa hizo comparaciones de cuerdas con este tipo. Me gusta:
if (type.equals("stock"))
{ ... do whatever ... }
Luego llamó a esta función, pasándole el valor "Stock".
¿Notan la diferencia en la capitalización? Tampoco el programador original. Resultó ser un error bastante sutil de descifrar, porque incluso al mirar ambos listados, la diferencia en el uso de mayúsculas no me sorprendió.
Si por el contrario hubiera declarado una estática final, digamos
final static String stock="stock";
Luego, la primera vez que intentó pasar "Stock" en lugar de "stock", habría recibido un error en tiempo de compilación.
Mejor aún, en este ejemplo habría sido hacer una enumeración, pero supongamos que en realidad tuvo que escribir la cadena en un archivo de salida o algo así que tenía que ser una cadena.
El uso de estadísticas estáticas da al menos x ventajas:
(1) Si lo escribe mal, obtendrá un error en tiempo de compilación, en lugar de un posible error en tiempo de ejecución.
(2) Una estática puede asignar un nombre mezquino a un valor. Que es más comprensible:
if (employeeType.equals("R")) ...
o
if (employeeType.equals(EmployeeType.RETIRED)) ...
(3) Cuando hay varios valores relacionados, puede colocar un grupo de estadísticas finales en la parte superior del programa, informando así a los futuros lectores cuáles son todos los valores posibles. He tenido muchas ocasiones en las que he visto una función comparar un valor con dos o tres literales. Y eso me deja preguntándome: ¿Hay otros valores posibles, o es esto? (Mejor aún, a menudo es tener una enumeración, pero esa es otra historia).
Serán exactamente los mismos. El literal está internado (cualquier expresión constante de tiempo de compilación que resulte en esa cadena comparte la misma instancia que todas las demás constantes / literales) en ambos casos y un compilador inteligente + tiempo de ejecución no debería tener problemas para reducir ambos al ejemplo más optimizado.
La ventaja viene más en mantenibilidad. Si desea cambiar el literal, solo necesitaría cambiar una aparición con una constante, pero tendría que buscar y cambiar cada instancia si se incluyeran en línea.
Todos los literales de cadena se guardan en un caché de cadena (esto es en todas las clases)
El uso de una constante puede hacer que el código sea más claro, darle un poco de contexto a la cadena y facilitar el mantenimiento del código si la misma cadena aparece en varios lugares.
Desde el JLS
Las constantes de tiempo de compilación de tipo String siempre se "internan" para compartir instancias únicas, utilizando el método String.intern.
Entonces, no, solo habrá un objeto de cadena.
Como señala Mark, esta es estrictamente la cuestión de la capacidad de mantenimiento y no del rendimiento.