Durante la fase de desarrollo, hay ciertas variables que deben corregirse en la misma ejecución, pero que pueden modificarse con el tiempo. Por ejemplo, boolean
para señalar el modo de depuración, por lo que hacemos cosas en el programa que normalmente no haríamos.
¿Es un mal estilo contener estos valores en una constante, es decir, final static int CONSTANT = 0
en Java? Sé que una constante se mantiene igual durante el tiempo de ejecución, pero ¿también se supone que es la misma durante todo el desarrollo, excepto los cambios no planificados, por supuesto?
Busqué preguntas similares, pero no encontré nada que coincidiera exactamente con el mío.
final
le da una garantía forzada por el compilador de que el programa no modificará el valor. No prescindiría de eso solo porque el programador podría querer modificar el valor asignado en el código fuente.gravity
mitad del juego / carrera. No significan necesariamente,gravity
es lo mismo en todos los planetas ... Dicho esto, la solución saludable es hacergravity
una constante, pero extraerla de unplanet
archivo o base de datos al comienzo del alcance relevante.Respuestas:
En Java, el compilador puede copiar las constantes finales estáticas, como sus valores, en el código que las utiliza . Como resultado de esto, si libera una nueva versión de su código, y hay alguna dependencia descendente que ha utilizado la constante, la constante en ese código no se actualizará a menos que se recompile el código descendente. Esto puede ser un problema si luego hacen uso de esa constante con el código que espera el nuevo valor, ya que aunque el código fuente es correcto, el código binario no lo es.
Esta es una verruga en el diseño de Java, ya que es uno de los pocos casos (tal vez el único caso) donde la compatibilidad de origen y la compatibilidad binaria no son las mismas. Excepto en este caso, puede intercambiar una dependencia con una nueva versión compatible con API sin que los usuarios de la dependencia tengan que volver a compilar. Obviamente, esto es extremadamente importante dada la forma en que generalmente se gestionan las dependencias de Java.
Para empeorar las cosas, el código hará silenciosamente lo incorrecto en lugar de producir errores útiles. Si reemplazara una dependencia con una versión con definiciones de clase o método incompatibles, obtendría errores de invocación o cargador de clases, que al menos proporcionan buenas pistas sobre cuál es el problema. A menos que haya cambiado el tipo de valor, este problema solo aparecerá como un misterioso mal comportamiento en tiempo de ejecución.
Más molesto es que las JVM de hoy podrían alinear fácilmente todas las constantes en tiempo de ejecución sin penalización de rendimiento (aparte de la necesidad de cargar la clase que define la constante, que probablemente se está cargando de todos modos), desafortunadamente la semántica de la fecha del idioma de los días anteriores a los JIT . Y no pueden cambiar el idioma porque el código compilado con compiladores anteriores no será correcto. La compatibilidad con errores ataca de nuevo.
Debido a todo esto, algunas personas aconsejan no cambiar nunca un valor final estático. Para las bibliotecas que pueden distribuirse ampliamente y actualizarse de manera desconocida en momentos desconocidos, esta es una buena práctica.
En su propio código, especialmente en la parte superior de la jerarquía de dependencia, probablemente saldrá con la suya. Pero en estos casos, considere si realmente necesita que la constante sea pública (o protegida). Si la constante es solo visibilidad del paquete, es razonable, dependiendo de sus circunstancias y estándares de código, que todo el paquete siempre se recompilará de una vez, y el problema desaparecerá. Si la constante es privada, no tiene ningún problema y puede cambiarla cuando lo desee.
fuente
Cualquier cosa en su código fuente, incluidas
const
las constantes globales declaradas, puede estar sujeta a cambios con una nueva versión de su software.Las palabras clave
const
(ofinal
en Java) están ahí para indicarle al compilador que esta variable no cambiará mientras se ejecuta esta instancia del programa . Nada mas. Si desea enviar mensajes al próximo responsable de mantenimiento, use un comentario en la fuente, para eso están allí.Es una manera mucho mejor de comunicarse con su futuro yo.
fuente
TaxRate
serpublic
me pone nervioso. Me gustaría saber con certeza que solo el departamento de ventas se ve afectado por este cambio y no también nuestros proveedores que nos cobran un impuesto. Quién sabe lo que pasó en la base del código desde que se escribió ese comentariopublic const
campos solo deben usarse para cosas que nunca cambiarán, como Math.pi. Si está creando una biblioteca, las cosas que podrían cambiar durante el desarrollo o con una nueva versión deberían serlopublic static readonly
, para no causar problemas con los usuarios de su biblioteca.Necesitamos distinguir dos aspectos de las constantes:
Y luego hay un tercer tipo relacionado: variables cuyo valor no cambia, es decir, nombres para un valor. La diferencia entre estas variables inmutables y una constante es cuando se determina / asigna / inicializa el valor: una variable se inicializa en tiempo de ejecución, pero el valor de una constante se conoce durante el desarrollo. Esta distinción es un poco confusa ya que un valor puede ser conocido durante el desarrollo, pero en realidad solo se crea durante la inicialización.
Pero si el valor de una constante se conoce en tiempo de compilación, entonces el compilador puede realizar cálculos con ese valor. Por ejemplo, el lenguaje Java tiene el concepto de expresiones constantes . Una expresión constante es cualquier expresión que consiste solo en literales de primitivas o cadenas, operaciones en expresiones constantes (como conversión, suma, concatenación de cadenas) y variables constantes. [ JLS §15.28 ] Una variable constante es una
final
variable que se inicializa con una expresión constante. [JLS §4.12.4] Entonces, para Java, esta es una constante de tiempo de compilación:Esto se vuelve interesante cuando se usa una variable constante en múltiples unidades de compilación, y luego se cambia la declaración. Considerar:
A.java
:B.java
:Ahora, cuando compilamos estos archivos, el
B.class
bytecode declarará un campoY = 9
porqueB.Y
es una variable constante.Pero cuando cambiamos la
A.X
variable a un valor diferente (digamosX = 0
) y volvemos a compilar solo elA.java
archivo,B.Y
aún se refiere al valor anterior. Este estadoA.X = 0, B.Y = 9
es inconsistente con las declaraciones en el código fuente. ¡Feliz depuración!Esto no significa que las constantes nunca deban cambiarse. Las constantes son definitivamente mejores que los números mágicos que aparecen sin explicación en el código fuente. Sin embargo, el valor de las constantes públicas es parte de su API pública . Esto no es específico de Java, pero también ocurre en C ++ y otros lenguajes que cuentan con unidades de compilación separadas. Si cambia estos valores, deberá volver a compilar todo el código dependiente, es decir, realizar una compilación limpia.
Dependiendo de la naturaleza de las constantes, podrían haber llevado a suposiciones incorrectas por parte de los desarrolladores. Si se cambian estos valores, podrían desencadenar un error. Por ejemplo, se puede elegir un conjunto de constantes para que formen ciertos patrones de bits, por ejemplo
public static final int R = 4, W = 2, X = 1
. Si se cambian para formar una estructura diferente, como elR = 0, W = 1, X = 2
código existente, como seboolean canRead = perms & R
vuelve incorrecto. ¡Y solo piense en la diversión que se produciría siInteger.MAX_VALUE
cambiaran! Aquí no hay una solución, es importante recordar que el valor de algunas constantes es realmente importante y no se puede cambiar simplemente.Pero para la mayoría de las constantes, cambiarlas estará bien siempre que se tengan en cuenta las restricciones anteriores. Es seguro cambiar una constante cuando el significado, no el valor específico, es importante. Este es, por ejemplo, el caso de los sintonizables como
BORDER_WIDTH = 2
oTIMEOUT = 60; // seconds
plantillas comoAPI_ENDPOINT = "https://api.example.com/v2/"
, aunque podría decirse que algunos o todos deberían especificarse en los archivos de configuración en lugar de en el código.fuente
Una constante solo se garantiza que sea constante durante la vida útil del tiempo de ejecución de la aplicación . Mientras eso sea cierto, no hay razón para no aprovechar la función del lenguaje. Solo necesita saber cuáles son las consecuencias de usar un indicador constante frente a un compilador para el mismo propósito:
Habiendo mantenido una aplicación que activaría el dibujo de cuadros delimitadores para formas para que pudiéramos depurar cómo fueron dibujados, nos encontramos con un problema. Después de refactorizar, todo el código que fue desactivado por los indicadores del compilador no se compilaría. Después de eso, cambiamos intencionalmente nuestros indicadores de compilación a constantes de aplicación.
Lo digo para demostrar que hay compensaciones. El peso de unos pocos booleanos no iba a hacer que la aplicación se quedara sin memoria o ocupara demasiado espacio. Eso podría no ser cierto si su constante es realmente un objeto grande que esencialmente tiene un identificador para todo en su código. Si no tiene cuidado de eliminar todas las referencias que contiene a un objeto después de que ya no sea necesario, entonces su objeto puede ser la fuente de una pérdida de memoria.
No soy fanático de las simples declaraciones generales, pero en general su colega principal es correcto. Si algo va a cambiar con frecuencia, es posible que deba ser un elemento configurable. Por ejemplo, probablemente podría convencer a su colega de una constante
IsInDebugMode = true
cuando desee proteger algún código para que no se rompa. Sin embargo, es posible que algunas cosas necesiten cambiar con más frecuencia de lo que publica una aplicación. Si ese es el caso, necesita una forma de cambiar ese valor en el momento adecuado. Puedes tomar el ejemplo de aTaxRate = .065
. Eso puede ser cierto en el momento en que compila su código, pero debido a las nuevas leyes, puede cambiar antes de lanzar la próxima versión de su aplicación. Eso es algo que debe actualizarse desde algún mecanismo de almacenamiento (como un archivo o una base de datos)fuente
#ifdef
s? Dado que estos se basan en la sustitución textual del código fuente, no forman parte de la semántica del lenguaje de programación. Tenga en cuenta que Java no tiene un preprocesador.#ifdef
banderas. Si bien no son parte de la semántica de C, son parte de C #. Estaba escribiendo para el contexto más amplio del agnosticismo lingüístico.El
const
,#define
ofinal
es una pista del compilador (tenga en cuenta que#define
no es realmente una pista, es una macro y significativamente más potente). Indica que el valor no cambiará durante la ejecución de un programa y que se pueden realizar varias optimizaciones.Sin embargo, como sugerencia del compilador, el compilador hace cosas que el programador no siempre puede esperar. En particular, javac incluirá una línea
static final int FOO = 42;
para que, en cualquier lugar queFOO
se utilice, se lea el código de bytes compilado real42
.Esto no es una gran sorpresa hasta que alguien cambie el valor sin volver a compilar la otra unidad de compilación (archivo .java) y los
42
restos en el código de bytes (¿ es posible deshabilitar la inclusión de variables finales estáticas en javac? ).Hacer algo
static final
significa que es eso y para siempre será eso, y cambiarlo es realmente una gran cosa, especialmente si es algo diferenteprivate
.Las constantes para cosas como
final static int ZERO = 0
no son un problema.final static double TAX_RATE = 0.55
(aparte de ser dinero y doble es malo y debería usar BigDecimal, pero no es primitivo y, por lo tanto, no está en línea) es un problema y debe examinarse con mucho cuidado para saber dónde se usa.fuente
is a problem and should be examined with great care for where it is used.
Por qué es un problema?Como su nombre lo indica, las constantes no deberían cambiar durante el tiempo de ejecución y, en mi opinión, las constantes están definidas para que no cambien a largo plazo (puede consultar esta pregunta SO para obtener más información.
Cuando se trata de la necesidad de indicadores (por ejemplo, para el modo de desarrollo), en su lugar, debe usar un archivo de configuración o un parámetro de inicio (muchos IDE admiten la configuración del parámetro de inicio en una base por proyecto; consulte la documentación relevante) para habilitar este modo: De esta forma, mantiene la flexibilidad de utilizar dicho modo y no puede olvidarse de cambiarlo cada vez que el código se vuelve productivo.
fuente
¡Ser capaz de cambiar entre ejecuciones es uno de los puntos más importantes para definir una constante en su código fuente!
La constante le brinda una ubicación bien definida y documentada (en cierto sentido) para cambiar el valor siempre que lo necesite durante la vida útil de su código fuente. También es una promesa de que cambiar la constante en esta ubicación realmente cambiará todas las ocurrencias de lo que representa.
A modo de ejemplo adversa: sería no tener sentido para tener una constante
TRUE
, que dé como resultadotrue
en un idioma que en realidad tiene latrue
palabra clave. Nunca, nunca, ni una sola vez, declararíasTRUE=false
excepto como una broma cruel.Por supuesto, hay otros usos de las constantes, por ejemplo, acortar el código (
CO_NAME = 'My Great World Unique ACME Company'
), evitar la duplicación (PI=3.141
), establecer convenciones (TRUE=1
) o lo que sea, pero tener una posición definida para cambiar la constante es sin duda uno de los más destacados.fuente