practicas - Convención de nomenclatura Java para variables finales estáticas
nomenclatura del lenguaje de programación java (9)
Esta pregunta ya tiene una respuesta aquí:
hay una regla que dice:
Los nombres que representan las constantes (variables finales) deben estar en mayúsculas con un guión bajo para separar palabras (tomadas de http://geosoft.no/development/javastyle.html )
que funciona bien para tipos primitivos como int o cadenas:
private static final int MAX_COUNT = 10;
Pero, ¿qué pasa con los tipos no primitivos? En la mayoría de los casos, he visto lo siguiente:
private static final Logger log = Logger.getLogger(MyClass.class);
o en singletons, donde la variable de instancia no está en mayúsculas.
La pregunta es: ¿cuál es la forma correcta de declarar esos tipos de variables (como el registro y la instancia)?
Bueno, esa es una pregunta muy interesante. Yo dividiría las dos constantes en tu pregunta de acuerdo a su tipo. int MAX_COUNT
es una constante de tipo primitivo, mientras que Logger log
es un tipo no primitivo.
Cuando hacemos uso de una constante de un tipo primitivo, estamos mutando la constante solo en nuestro código public static final in MAX_COUNT = 10
y solo estamos accediendo al valor de la constante en otro lugar for(int i = 0; i<MAX_COUNT; i++)
. Esta es la razón por la que nos sentimos cómodos con el uso de esta convención.
Mientras que en el caso de los tipos no primitivos, aunque, inicializamos la constante en un solo lugar, private static final Logger log = Logger.getLogger(MyClass.class);
, se espera que mutemos o llamemos a un método en esta constante en otro lugar, log.debug("Problem")
. A nosotros no nos gusta poner un operador de punto después de los caracteres capitales. Después de todo, tenemos que poner un nombre de función después del operador de punto, que seguramente será el nombre de un camello. Es por eso que LOG.debug("Problem")
se vería incómodo.
Lo mismo es el caso con los tipos de String
. Generalmente no estamos mutando o llamando a un método en una constante de String
en nuestro código y es por eso que usamos la convención de nomenclatura de capital para un objeto tipo String
.
El diálogo sobre esto parece ser la antítesis de la conversación sobre la interface
nombres y las clases abstract
. Encuentro esto alarmante, y creo que la decisión es mucho más profunda que simplemente elegir una convención de nomenclatura y usarla siempre con static final
.
Resumen e interfaz
Al nombrar las interfaces y las clases abstractas, la convención aceptada se ha convertido en no prefijar o ponerle un sufijo a su abstract class
o interface
con cualquier información de identificación que indique que no es una clase.
public interface Reader {}
public abstract class FileReader implements Reader {}
public class XmlFileReader extends FileReader {}
Se dice que el desarrollador no necesita saber que las clases anteriores son abstract
o una interface
.
Static Final
Mi preferencia y creencia personal es que debemos seguir una lógica similar cuando nos referimos a variables static final
. En cambio, evaluamos su uso al determinar cómo nombrarlo. Parece que todo el argumento en mayúsculas es algo que ha sido adoptada ciegamente de los lenguajes C y C ++. En mi opinión, esa no es una justificación para continuar la tradición en Java.
Cuestión de intención
Deberíamos preguntarnos cuál es la función de la static final
en nuestro propio contexto. Aquí hay tres ejemplos de cómo static final
se puede usar en diferentes contextos :
public class ChatMessage {
//Used like a private variable
private static final Logger logger = LoggerFactory.getLogger(XmlFileReader.class);
//Used like an Enum
public class Error {
public static final int Success = 0;
public static final int TooLong = 1;
public static final int IllegalCharacters = 2;
}
//Used to define some static, constant, publicly visible property
public static final int MAX_SIZE = Integer.MAX_VALUE;
}
¿Podrías usar mayúsculas en los tres escenarios? Absolutamente, pero creo que se puede argumentar que sería perjudicial para el propósito de cada uno. Entonces, examinemos cada caso individualmente.
Propósito: Variable privada
En el caso del ejemplo de Logger
anterior, el registrador se declara como privado, y solo se usará dentro de la clase, o posiblemente una clase interna. Incluso si se declaró en visibilidad protected
o de , su uso es el mismo: package
public void send(final String message) {
logger.info("Sending the following message: ''" + message + "''.");
//Send the message
}
Aquí, no nos importa que el logger
sea una variable de miembro static final
. Simplemente podría ser una variable de instancia final
. No lo sabemos No necesitamos saber Todo lo que necesitamos saber es que estamos registrando el mensaje al registrador que la instancia de clase nos ha proporcionado.
public class ChatMessage {
private final Logger logger = LoggerFactory.getLogger(getClass());
}
No lo llamarías LOGGER
en este escenario, entonces ¿por qué deberías ponerlo en mayúsculas si fuera static final
? Su contexto o intención es el mismo en ambas circunstancias.
Nota: Invertí mi posición en la visibilidad del package
porque se parece más a una forma de acceso public
, restringido al nivel del package
.
Propósito: Enum
Ahora puedes decir, ¿por qué estás usando enteros static final
como una enum
? Esa es una discusión que aún está evolucionando e incluso diría que es algo controvertido, por lo que trataré de no descarrilar esta discusión por mucho tiempo al aventurarme en ella. Sin embargo, se sugiere que podría implementar el siguiente patrón de enumeración aceptado:
public enum Error {
Success(0),
TooLong(1),
IllegalCharacters(2);
private final int value;
private Error(final int value) {
this.value = value;
}
public int value() {
return value;
}
public static Error fromValue(final int value) {
switch (value) {
case 0:
return Error.Success;
case 1:
return Error.TooLong;
case 2:
return Error.IllegalCharacters;
default:
throw new IllegalArgumentException("Unknown Error value.");
}
}
}
Hay variaciones de lo anterior que logran el mismo propósito de permitir la conversión explícita de una enum->int
e int->enum
. En el ámbito de la transmisión de esta información a través de una red, la serialización nativa de Java es simplemente demasiado detallada. Un simple int
, short
o byte
podría ahorrar un gran ancho de banda. Pude ahondar en una comparación y un contraste prolongados acerca de los pros y los contras de enum
vs static final int
implican seguridad de tipo, legibilidad, mantenibilidad, etc .; afortunadamente, eso queda fuera del alcance de esta discusión.
La conclusión es esto, a veces
static final int
se utilizará como una estructura de estiloenum
.
Si puede convencerse de que la declaración anterior es verdadera , podemos seguir con una discusión sobre el estilo. Al declarar una enum
, el estilo aceptado dice que no hacemos lo siguiente:
public enum Error {
SUCCESS(0),
TOOLONG(1),
ILLEGALCHARACTERS(2);
}
En cambio, hacemos lo siguiente:
public enum Error {
Success(0),
TooLong(1),
IllegalCharacters(2);
}
Si su bloque static final
de enteros sirve como una enum
suelta, ¿por qué debería usar una convención de nomenclatura diferente para ello? Su contexto o intención es el mismo en ambas circunstancias.
Propósito: Propiedad estática, constante, pública
Este caso de uso es quizás el más turbio y discutible de todos. El ejemplo de uso de tamaño de constante estática es donde más se encuentra. Java elimina la necesidad de sizeof()
, pero a veces es importante saber cuántos bytes ocupará una estructura de datos.
Por ejemplo, considere que está escribiendo o leyendo una lista de estructuras de datos en un archivo binario, y el formato de ese archivo binario requiere que el tamaño total del fragmento de datos se inserte antes de los datos reales. Esto es común para que un lector sepa cuándo se detienen los datos en el escenario de que hay más datos, no relacionados, que siguen. Considere el siguiente formato de archivo inventado:
File Format: MyFormat (MYFM) for example purposes only
[int filetype: MYFM]
[int version: 0] //0 - Version of MyFormat file format
[int dataSize: 325] //The data section occupies the next 325 bytes
[int checksumSize: 400] //The checksum section occupies 400 bytes after the data section (16 bytes each)
[byte[] data]
[byte[] checksum]
Este archivo contiene una lista de objetos MyObject
serializados en una secuencia de bytes y escritos en este archivo. Este archivo tiene 325 bytes de objetos MyObject
, pero sin conocer el tamaño de cada objeto MyObject
no tiene forma de saber qué bytes pertenecen a cada uno de MyObject
. Por lo tanto, define el tamaño de MyObject
en MyObject
:
public class MyObject {
private final long id; //It has a 64bit identifier (+8 bytes)
private final int value; //It has a 32bit integer value (+4 bytes)
private final boolean special; //Is it special? (+1 byte)
public static final int SIZE = 13; //8 + 4 + 1 = 13 bytes
}
La estructura de datos de MyObject
ocupará 13 bytes cuando se escriba en el archivo como se define arriba. Sabiendo esto, al leer nuestro archivo binario, podemos deducir dinámicamente cuántos objetos MyObject
siguen en el archivo:
int dataSize = buffer.getInt();
int totalObjects = dataSize / MyObject.SIZE;
Este parece ser el típico caso de uso y argumento para todas las constantes static final
mayúsculas, y estoy de acuerdo en que en este contexto, todo en mayúsculas tiene sentido. Este es el por qué:
Java no tiene una clase de struct
como el lenguaje C, pero una struct
es simplemente una clase con todos los miembros públicos y sin constructor. Es simplemente una struct
datos. Entonces, puedes declarar una class
en struct
misma manera:
public class MyFile {
public static final int MYFM = 0x4D59464D; //''MYFM'' another use of all uppercase!
//The struct
public static class MyFileHeader {
public int fileType = MYFM;
public int version = 0;
public int dataSize = 0;
public int checksumSize = 0;
}
}
Permítanme comenzar este ejemplo diciendo que personalmente no analizaría de esta manera. Sugeriría una clase inmutable que maneje el análisis internamente aceptando un ByteBuffer
o las 4 variables como argumentos de constructor. Dicho esto, accediendo (estableciendo en este caso) a los miembros de esta struct
se vería algo así como:
MyFileHeader header = new MyFileHeader();
header.fileType = buffer.getInt();
header.version = buffer.getInt();
header.dataSize = buffer.getInt();
header.checksumSize = buffer.getInt();
Estos no son static
o final
, sin embargo, son miembros expuestos públicamente que se pueden establecer directamente. Por esta razón, creo que cuando un miembro static final
está expuesto públicamente, tiene sentido mayúsculo por completo. Esta es la única vez en que es importante distinguirla de las variables públicas no estáticas.
Nota: Incluso en este caso, si un desarrollador intenta establecer una variable final
, se encontrarían con un error IDE o compilador.
Resumen
En conclusión, la convención que elija para las variables static final
será su preferencia, pero creo firmemente que el contexto de uso debe pesar mucho en su decisión de diseño. Mi recomendación personal sería seguir una de las dos metodologías:
Metodología 1: evaluar el contexto y la intención [highly subjective; logical]
[highly subjective; logical]
- Si se trata de una variable
private
que no se puede distinguir de una variable de instanciaprivate
, asígneles el mismo nombre. todo en minúsculas - Si su intención es servir como un tipo de bloque de valores
static
de estiloenum
, entonces nómbrelo como lo haría con unaenum
. caso Pascal: inicial-tapa cada palabra - Si su intención es definir alguna propiedad pública, constante y estática, permita que se destaque haciéndola mayúscula
Metodología 2: privado vs público [objective; logical]
[objective; logical]
La Metodología 2 básicamente condensa su contexto en visibilidad y no deja lugar a la interpretación.
- Si es
private
oprotected
, debe ser todo en minúsculas . - Si es
public
opackage
entonces debería ser todo en mayúsculas .
Conclusión
Así es como veo la convención de nomenclatura de variables static final
. No creo que sea algo que pueda o deba encajonarse en una única trampa. Creo que debes evaluar su intención antes de decidir cómo nombrarla.
Sin embargo, el objetivo principal debe ser tratar de mantenerse constante a lo largo del alcance de su proyecto / paquete. Al final, eso es todo sobre lo que tienes control.
(Espero ser encontrado con resistencia, pero también espero obtener algún apoyo de la comunidad sobre este enfoque. Cualquiera que sea su postura, por favor manténgalo civilizado al reprochar, criticar o aclamar esta elección de estilo).
El lenguaje no le importa Lo importante es seguir los estilos establecidos y las convenciones del proyecto en el que está trabajando, de modo que otros mantenedores (o usted dentro de cinco meses) tengan la mejor posibilidad de no confundirse.
Creo que un nombre mayúsculo para un objeto mutable me confundiría, incluso si la referencia a ese objeto se almacenara en una variable static final
.
En mi opinión, una variable que es "constante" a menudo es un detalle de implementación y no justifica necesariamente las diferentes convenciones de denominación. Puede ayudar a la legibilidad, pero también puede dañarlo en algunos casos.
Eso sigue siendo una constante . Consulte el JLS para obtener más información sobre la convención de nomenclatura para constantes. Pero en realidad, todo es una cuestión de preferencia.
Los nombres de las constantes en los tipos de interfaz deben ser, y las variables
final
de los tipos de clase pueden ser convencionalmente, una secuencia de una o más palabras, acrónimos o abreviaturas, todos en mayúscula, con componentes separados por caracteres"_"
subrayado. Los nombres constantes deben ser descriptivos y no deben abreviarse innecesariamente. Convencionalmente, pueden ser una parte apropiada del discurso. Los ejemplos de nombres para constantes incluyenMIN_VALUE
,MAX_VALUE
,MIN_RADIX
yMAX_RADIX
de la claseCharacter
.Un grupo de constantes que representan valores alternativos de un conjunto, o, con menor frecuencia, bits de enmascaramiento en un valor entero, a veces se especifican de manera útil con un acrónimo común como un prefijo de nombre, como en:
interface ProcessStates { int PS_RUNNING = 0; int PS_SUSPENDED = 1; }
El ocultamiento que involucra nombres constantes es raro:
- Los nombres constantes normalmente no tienen letras minúsculas, por lo que normalmente no oscurecerán los nombres de los paquetes o tipos, ni sombrearán normalmente los campos, cuyos nombres suelen contener al menos una letra minúscula.
- Los nombres constantes no pueden ocultar los nombres de los métodos, porque se distinguen sintácticamente.
Estas variables son constantes, es decir, private static final
ya sea que se mencionen con mayúsculas o no. La convención de mayúsculas simplemente hace que sea más obvio que estas variables están destinadas a ser constantes, pero no es necesario. He visto
private static final Logger log = Logger.getLogger(MyClass.class);
en minúsculas antes, y estoy de acuerdo porque sé que solo uso el registrador para registrar mensajes, pero viola la convención. Se podría argumentar que nombrar log
es una subconvención, supongo. Pero, en general, nombrar constantes en mayúsculas no es One Right Way, pero es The Best Way.
No hay una manera "correcta", solo hay convenciones. Has declarado la convención más común, y la que sigo en mi propio código: todas las finales estáticas deberían ser con mayúsculas. Me imagino que otros equipos siguen otras convenciones.
No viva fanáticamente con las convenciones que SUN ha meditado, haga lo que le parezca correcto a usted y su equipo.
Por ejemplo, así es como lo hace el eclipse, rompiendo la convención. Prueba agregar implements Serializable
y eclipse te pedirá que generes esta línea por ti.
Actualización: Hubo casos especiales que se excluyeron, no lo sabía. Sin embargo, me niego a hacer lo que usted y su equipo parecen adecuados.
Una referencia constante a un objeto no es una constante, es solo una referencia constante a un objeto.
private static final
no es lo que define algo como constante o no. Es solo la forma de Java para definir una constante, pero no significa que cada declaración private static final
se puso allí para definir una constante.
Cuando escribo private static final Logger
no intento definir una constante, solo intento definir una referencia a un objeto que es private
(que no es accesible desde otras clases), static
(que es una clase) variable de nivel, no se necesita instancia) y final
(que solo se puede asignar una vez). Si coincide con la forma en que Java espera que declare una mala suerte constante, bueno, pero no lo convierte en una constante. No me importa lo que diga el compilador, el sonar o cualquier gurú de Java. Un valor constante, como MILLISECONDS_IN_A_SECOND = 1000
es una cosa, y una referencia constante a un objeto es otra.
Se sabe que el oro brilla, pero no todo lo que brilla es oro.