Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Elliotte Rusty Harold explora los modismos, dialectos y acentos nativos del lenguaje y la
comunidad Java™. Al seguir la orientación de este artículo, C/C++ y otros programadores no
nativos pueden mezclarse adecuadamente con los hablantes Java nativos.
Aprender un nuevo lenguaje de programación es más fácil que aprender un nuevo idioma
hablado. Pero, en ambos intentos, requiere esfuerzo extra aprender a hablar el lenguaje nuevo sin
acento. No es tan duro aprender el lenguaje Java cuando ya sabe C o C++. Es similar a aprender
danés cuando ya habla sueco. Los lenguajes son diferentes pero mutuamente comprensibles. Sin
embargo, si no es cuidadoso, su acento lo develará siempre como un hablante no nativo.
Los programadores C++ a menudo ponen ciertas inflexiones en el código Java que los marcan
indudablemente como conversos en lugar de hablantes nativos. Su código todavía funciona pero
suena mal al oído nativo. Como resultado, los nativos pueden menospreciar a los hablantes no
nativos. Cuando se pasa del C o C++ (o Basic o Fortran o Scheme o cualquier otro) al lenguaje
Java, es necesario erradicar ciertos modismos y corregir algunas pronunciaciones que usted
enuncia de manera fluida.
En este artículo, exploro una cantidad de detalles de programación Java que a menudo se pasan
por alto precisamente porque semánticamente no interesan demasiado, si es que interesan. Son
cuestiones puramente de estilo y convención. Algunas de ellas tienen justificaciones plausibles.
Algunas de ellas incluso carecen de eso. Pero todas ellas son fenómenos reales en el código
Java como está escrito actualmente.
Créalo o no, los Listados 1 y 2 están escritos ambos en el lenguaje Java. Son solo códigos Java
escritos en un modismo C (para ser justos, el Listado 1 también podría ser un código C real). Pero
es un código Java de aspecto muy gracioso. Aquí una cantidad de modismos lo marcan como el
trabajo de alguien que piensa en C y está simplemente traduciendo al lenguaje Java:
Convenciones de denominación
Según si viene de C y C++ o C#, usted puede haber internalizado diferentes convenciones
de denominación para las clases. En C#, por ejemplo, los nombres de clase comienzan con
letras minúsculas y los nombres de método y campo comienzan con letras mayúsculas. El estilo
Java es exactamente al revés. No puedo justificar una convención u otro por cualquier motivo
racional pero sí sé que mezclar las convenciones de denominaciones hace que el código se
sienta terriblemente erróneo. También conduce a errores. Cuando sabe que cada nombre en
mayúsculas sostenidas es una constante, lo trata de modo diferente. He encontrado muchos
args, no argv
Este punto es uno de los más triviales, pero esas son las minucias por las que se libran las
guerras de estilo. En la jerga Java, el argumento del método main() se llama args, no
argv:
Las reglas básicas para los nombres en la programación Java son bastante simples y valen la
pena memorizarlas:
• Los nombres de clase e interfaz comienzan con una letra mayúscula, como en Frame.
• Los nombres de método, campo y variable local comienzan con una letra minúscula, como en
read().
• Los nombres de clase, método y campo usan todos bicapitalización, como en InputStream y
readFully().
• Las constantes — campos estáticos finales y ocasionalmente variables locales finales
— se escriben todo en mayúsculas con subrayados que separan las palabras, como en
MAX_CONNECTIONS.
No abrevie
Los nombres como sprintf y nmtkns son reliquias de un tiempo en el que las supercomputadoras
tenían 32 KB de memoria. Los compiladores guardaban memoria al limitar los identificadores a 8
caracteres o menos. Sin embargo, esto no ha sido realmente un problema por más de 30 años.
Hoy no hay excusa para no escribir totalmente nombres de variables y métodos. Nada marca un
programa como el producto de un pirata informático C reformado de manera más evidente que los
incomprensibles nombres de variables sin vocales, como en el Listado 3:
Los nombres sin abreviar en bicapitalización son mucho más legibles, como es posible observar
en el Listado 4:
El código se lee más a menudo de lo que se lo escribe y el lenguaje Java se optimiza para la
lectura. Los programadores C tienen una atracción casi machista por el código ofuscado; los
programadores Java, no. El lenguaje Java prioriza la legibilidad sobre la concisión.
Algunas abreviaciones son tan comunes que es posible usarlas sin culpa.
• max de máximo
• min de mínimo
• in de InputStream
• out de OutputStream
• e o ex para una excepción en una cláusula catch (aunque en ningún otro lado)
• num de número, aunque solo cuando se usa como prefijo como en numTokenso numHits
• tmp para una variable temporal usada muy localmente — por ejemplo, cuando se
intercambian dos valores.
En otros casos, y tal vez en algunos otros, usted debería escribir todas las palabras completas
usadas en los nombres.
Sin embargo, este estilo tiene una cantidad de efectos negativos. Separa la declaración de la
variable de su uso, lo que hace que el código sea un poco difícil de seguir. Además, hace mucho
más probable que una variable local sea reutilizada para varios fines diferentes, posiblemente de
modo involuntario. Esto puede introducir errores inesperados cuando una variable posee un valor
sobrante que una parte del código no estaba esperando. Combine esto con la inclinación de C por
los nombres de variables cortos y crípticos y obtendrá una receta para el desastre.
En el lenguaje Java (y versiones más recientes de C), las variables pueden declararse en o cerca
del punto de primer uso. Haga esto cuando escriba el código Java. Hace que su código sea más
seguro, menos propenso a errores y más fácil de leer.
En una nota relacionada, el código Java normalmente inicializa cada variable cuando y donde se
declara. Los programadores C a veces escriben el código del siguiente modo:
int i; i = 7;
Los programadores Java casi nunca escriben un código de esa forma, aunque sea
sintácticamente correcta. Ellos lo escriben de esta forma:
int i = 7;
Esto ayuda a evitar errores que resultan del uso involuntario de variables sin inicializar. La única
excepción común sucede cuando una sola variable necesita ser registrada en un bloque try y un
bloque catch o finally . Esto muy frecuentemente surge cuando el código trata con corrientes de
entrada y corrientes de salida que necesitan cerrarse en el bloque finally , como se muestra en
el Listado 5:
Finalmente, el último efecto colateral de este estilo es que los programadores Java normalmente
declaran solo una variable por línea. Por ejemplo, inicializan tres variables del siguiente modo:
int i = 3; int j = 8; int k = 9;
Esta sentencia es sintácticamente correcta, pero los programadores Java a tiempo completo
habitualmente no hacen eso, excepto en un caso especial que mencionaré a continuación.
Así, el estilo Java habitual es en realidad un poco más conciso en solo tres líneas porque combina
declaración e inicialización.
Las cuatro variables se declaran fuera del bucle y, por lo tanto, tienen un ámbito excesivo
aunque solo se usan dentro del bucle. Esto está propenso a errores porque las variables pueden
reutilizarse fuera del ámbito en el que se destinó para ser usadas Esto es especialmente cierto
para las variables con nombres comunes tales como i y tmp. Los valores de un uso pueden
perdurar e interferir con el código posterior en maneras inesperadas.
La primera mejoría (que también está respaldada por versiones modernas de C) es mover la
declaración de la variable de bucle i dentro del bucle, como se muestra en el Listado 7:
Sin embargo, no se detenga ahí. Los programadores Java experimentados también moverán la
variable tmp dentro del bucle, como en el Listado 8:
Los estudiantes universitarios sin una obsesión excesiva por la velocidad a veces objetan que
esto reducirá la velocidad del código al realizar más trabajo de lo que es necesario dentro del
bucle. Sin embargo, al tiempo de ejecución, una declaración no realiza absolutamente ningún
trabajo. No hay sanción de rendimiento alguna en la plataforma Java por mover una declaración
dentro de un bucle.
Esto ha pasado ahora más allá del código fluido meramente idiomático a un código
verdaderamente experto. Esta habilidad para limitar rigurosamente el ámbito de las variables
locales es una gran razón por la que usted ve mucho más bucles for y muchos menos bucles
while en código Java que en el código C.
Los programadores Java experimentados reescriben esto con cinco variables locales diferentes,
como se muestra en el Listado 11:
La reutilización de una variable local para varios valores u objetos lógicamente diferentes está
propensa a errores. Esencialmente, las variables locales (aunque no siempre los objetos a los que
señalan) están libres de asuntos de memoria y tiempo. No tenga miedo de usar tantas variables
locales diferentes como sea necesario.
Incluso menos común que los floatsson los shorts.Raras veces he visto una variable short en
el código Java. En el único momento en el que aparece — y esto es extremadamente raro, le
advierto —, es cuando se leen formatos de datos externamente definidos que incluyen un tipo
entero firmado de 16 bits. En esa situación, la mayoría de los programadores solo leen eso como
un int.
Ámbito de privacidad
¿Alguna vez ha visto un método equals() como el ejemplo en el Listado 12?
Este método es técnicamente correcto pero puedo prácticamente garantizarle que esta clase fue
escrita por un programador C++ recalcitrante. La señal delatora es el uso del campo privado x y
el método getter público getX() en el mismo método y efectivamente en la misma línea. En C+
+, esto es necesario porque la privacidad se registra en el ámbito del objeto en lugar de la clase.
Es decir, en C++, los objetos de la misma clase no pueden ver las variables asociadas privadas
de uno y otro. En cambio, deben usar métodos accessor. En el lenguaje Java, la privacidad se
registra en el ámbito de la clase en lugar del objeto. Dos objetos, cada uno de tipo Foo pueden
acceder directamente a los campos privados de uno y otro.
Algunas consideraciones sutiles — y más a menudo irrelevantes — sugieren que usted puede
preferir el acceso de campo directo antes del acceso getter o viceversa dentro del código Java.
El acceso de campo puede ser ligeramente más rápido, pero en raras ocasiones. Algunas
veces, el acceso getter puede brindar un valor un poco diferente del acceso de campo directo,
especialmente cuando las subclases están en juego. Sin embargo, en el lenguaje Java, nunca hay
ninguna excusa para usar ambos, acceso de campo directo y acceso getter, para el mismo campo
de la misma clase en la misma línea.
Sin embargo, el lenguaje Java también ofrece una sintaxis alternativa en la que los delimitadores
de matriz se ubican luego del tipo en lugar de luego del nombre de la variable:
int[] k; double[] temperatures; String[] names;
La mayoría de los programadores Java han adoptado el segundo estilo. Esto dice que k tiene la
matriz de tipo de int, temperatures tiene la matriz de tipo de doublesy names tiene la matriz de
tipo de Strings.
También, como con otras variables locales, los programadores Java tienden a inicializar la matriz
en el punto en el que se declara:
Ubicar el literal en el lado izquierdo hace que esto sea un error de tiempo de compilación. Esta
técnica es una buena práctica de programación en C. Ayuda a prevenir errores reales porque al
ubicar el literal en el lado derecho hace que esto siempre devuelva true.
Sin embargo, el lenguaje Java, a diferencia de C, tiene tipos separados int y boolean . El
operador de asignación devuelve un int, por cuanto el operador de comparación devuelve un
boolean. Por consiguiente, if (x = 7) ya es un error de tiempo de compilación, por lo que no
hay razón para utilizar la forma anormal if (7 == x) para sentencias de comparación y los
programadores Java fluidos no lo hacen.
La variante que usa la concatenación de cadena es más fácil de leer, en especial en casos
simples, y menos propenso a error porque no hay peligro de no coincidencia entre marcadores en
la serie de formato y la cantidad o el tipo de los argumentos variables.
Usted nunca debería escribir un código que dependa de la diferencia entre el incremento previo
y el incremento posterior (y eso también es válido para C). Es simplemente muy difícil de seguir
y muy propenso al error. Si usted está escribiendo un código donde la diferencia sí importa,
entonces reorganice el código en sentencias separadas para que no importe más.
Manejo de errores
El manejo de errores es una de las cuestiones que más se confunden en la programación
Java y una que realmente separa a los diseñadores maestros del lenguaje de los gruñones y
murmuradores. Efectivamente, podría fácilmente ser la base de un artículo en sí mismo. En pocas
palabras, use las excepciones adecuadamente y nunca devolverá códigos de error.
El primer error de los hablantes no nativos es devolver un valor que indica un error, en lugar
de arrojar una excepción. Efectivamente, puede incluso ver esto en algunos de los API propios
del lenguaje Java que se remontan a los primeros días de Java 1.0, antes de que todos los
programadores en Sun hubieran internalizado completamente el lenguaje nuevo. Por ejemplo,
considere el método delete() en java.io.File:
public boolean delete()
Este método devuelve true si el archivo o directorio se suprime con éxito. Si no, devuelve false.
Lo que debería hacer es no devolver nada cuando se finaliza con éxito y arrojar una excepción si
el archivo existe pero no se puede suprimir por alguna razón:
public void delete() throws IOException
Cuando los métodos devuelven valores de error, cada llamada de método está rodeada por un
código de manejo de errores. Esto hace que sea difícil de seguir y entender el flujo normal de
ejecución del método cuando, como normalmente es el caso, no hay problema y todo está bien.
En cambio, cuando las condiciones de error se indican por excepciones, el manejo de errores
puede sacarse del camino en un bloque de código separado más tarde en el archivo. Se lo puede
mover incluso a otros métodos y otras clases si existe un lugar más adecuado para manejar el
problema.
Esto me lleva al segundo antipatrón en el manejo de errores. Los programadores que vienen de
un ambiente C o C++ a veces intentan manejar excepciones tan cerca como sea posible hasta
el punto que se arroja la excepción. Tomado al extremo, puede resultar en un código como el
Listado 13:
Esto es tan difícil de leer e incluso más intricado que las pruebas if (errorCondition) que el
manejo de excepciones fue diseñado para sustituir. El código Java fluido mueve el manejo de
errores fuera del punto de falla. No mezcla el código de manejo de errores con el flujo normal de
ejecución. La versión en el Listado 14 es mucho más fácil de seguir y entender:
Ocasionalmente, usted puede necesitar usar bloques anidados try-catch para separar diferentes
modos de fallas que producen la misma excepción pero esto no es común. La regla general es
que si hay más de un valor de código del bloque tryen un método, entonces el método es muy
grande y probablemente debería dividirse en métodos más pequeños de todos modos.
Finalmente, los programadores nuevos en la programación Java de todos los lenguajes a menudo
cometen el error de asumir que deben obtener excepciones verificadas en el método donde se
arrojan. En muchas ocasiones, el método que arroja la excepción no es el método que debería
obtenerla. Por ejemplo, considere un método que copie secuencias, como en el Listado 15:
de una falla. Lo único razonable para que este método haga es dejar que la IOException burbujee
hasta el interlocutor. El modo correcto para escribir este método se muestra en el Listado 16:
Es más corto. Es más simple. Es más comprensible y transmite la información del error a la parte
del código que es más adecuado para manejarla.
Para bien o para mal, hablar (o escribir un código) sin acento causará que otros lo respeten más,
le presten más atención a lo que dice e incluso le paguen más para que lo diga. Además, hablar
el lenguaje Java sin acento en realidad es mucho más fácil que hablar francés, chino o inglés sin
acento. Una vez que usted haya aprendido el lenguaje, vale la pena hacer el esfuerzo extra para
hablarlo como lo haría un nativo.
Recursos
• Code Conventions for the Java Programming Language: Aunque es un poco anticuada, esta
referencia todavía sirve como la base para el estilo Java moderno.
• The Java Language Specification (James Gosling et al., Addison Wesley, 2005): Ahora en
su tercera edición, esta fue tal vez la primera especificación de lenguaje para reconocer que
se necesitaba debatir el estilo, así como también la sintaxis y la semántica. Es una razón
importante que el lenguaje Java tenga un estilo mucho más estándar a través de grupos y
proyectos que el que tienen los primeros lenguajes, como C++ y Basic.
• Effective Java, 2.º ed. (Joshua Bloch, Prentice Hall, 2008): El libro de Bloch cubre muchos de
los aspectos más semánticos del estilo Java.
• "Java programming for C/C++ developers" (James Stricker, developerWorks, mayo del
2002): Este tutorial está diseñado para programadores C o C++ que quieren aprender cómo
programar en el lenguaje Java.
• Lo nuevo en la programación Java: Lea una visión general de los conceptos básicos de la
tecnología Java y descubra cómo la tecnología se integra en el contexto del desarrollo de
software contemporáneo.
• Explore la technology bookstore para encontrar libros sobre estos y otros temas técnicos.
• Libreria Java en developerWorks: Encuentre cientos de artículos acerca de cada aspecto de
la programación Java.
• Participe en My developerWorks community.
Sobre el autor
Elliotte Rusty Harold