Convenciones de código para el Lenguaje de Programación Java. 1 - Introducción Este documento describe una serie de estándares, convenciones y guías para escribir código java sólido Estos proveen principios de ingeniería que conducen a código de fácil entendimiento, mantenimiento y mejoramiento. Además, por siguiente estas normas de codificación deben aumentar su productivaza como programador Java .La Experiencia muestra que por tomando el tiempo para escribir el código de alta calidad directamente del principio usted tendrá un tiempo mucho más fácil para modificar durante el proceso de desarrollo. Finalmente, después de un juego común de cifrar normas, estas conducen a una consistencia mayor, haciendo a los equipos de programadores considerablemente más productivos. 2 – Nombres de archivos 2.1 Sufijo de Archivos Java usa los siguientes sufijos Tipo de Archivo Sufijo Java source .java Java bytecode .class Java Server Face .jsp Java Server Face XML .jspx 3 – Organización De Archivos Un archivo consiste en secciones que podrían estar separadas por líneas en blanco y comentarios opcionales identificando cada sección. Archivos de más de 2000 líneas son incómodos y deberían ser evitados. 3.1 Archivos Fuentes Java Cada archivo fuente Java contiene una clase o interface publica. Cuando las clases e interfaces son asociadas con clases públicas, se puede juntar en el mismo archivo como una clase publica. La clase pública puede ser la primera clase o interface en el archivo. Los archivos fuentes de java tienen el siguiente orden. Sentencias de Package e Import. Declaración de clases e interfases. 3.1.1 Comentarios iniciales Todos los archivos de Fuentes pueden empezar con un comentario c-style que lista el nombre de la clase, información de la versión, fecha y mención de propiedad intelectual: /* * Nombre de la clase * * Información de la versión * * Fecha * * Mención de propiedad */ 3.1.2 Sentencias de Package e Import. La primera línea sin comentar de un archivo java es la sentencia del package. Después de esto las sentencias de import continúan. Por ejemplo: package com.smcma; import com.smcma.model.Programacion; 3.1.3 Declaración de Clases e interfaces. La siguiente tabla describe las partes de una declaración de una clase o interface, en el orden que podría aparecer. Parte de una declaración Clase/Interface Comentario de Clase/Interface documentacion (/**...*/) Sentencias de clase o interface Notas Comentario de Implementación Clase/Interface (/*...*/), si fuera necesario de Este comentario debe contener información que no es apropiada para el comentario documentación. Primero Variables (static) de Clase las variables publicas, luego las protegidas, luego las de nivel de paquete y luego las privadas. Primero publicas, luego protegidas, luego de Variables Instanciadas nivel de paquete y luego privadas. Constructores Métodos Este método debe agrupar por funcionalidad más que por lugar o accesibilidad. 4 - Indentacion Cuatro espacios podrían ser usados como la unidad de indentacion. 4.1 Longitud De línea Evite líneas que excedan los 80 caracteres, ya que ellos no son manejados bien por muchos terminales y herramientas. 4.2 Líneas Envolventes Cuando una expresión no cabe sobre una sola línea, se partirá según estos principios generales: Partir después de una coma. Partir antes de un operador. Preferir altos niveles de partición que cortos niveles de partición. Alinear la nueva línea con el inicio de la expresión en el mismo nivel de la línea anterior. Ejemplos de particionamiento de llamadas a métodos. someMethod(longExpression1, longExpression2, longExpression3, longExpression4, longExpression5); var = someMethod1(longExpression1, someMethod2(longExpression2, longExpression3)); Siguiendo estos dos ejemplos de particionamiento de expresiones aritméticas. El primero refiere, a una partición ocurrida fuera de la expression de paréntesis, el cual es de alto nivel. longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longname6; // PREFERIBLE longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longname6; // EVITAR Siguiendo estos dos ejemplos de indentacion en la declaración de métodos. El primero es un caso convencional. El segundo cambiaria la segunda y tercera línea muy a la derecha, en cambio este indenta solo 8 espacios //CONVENTIONAL INDENTATION someMethod(int anArg, Object anotherArg, String yetAnotherArg, Object andStillAnother) { ... } //IDENTACION DE 8 ESPACIOS PARA EVITAR MUY PROFUNDAS IDENTACIONES private static synchronized horkingLongMethodName(int anArg, Object anotherArg, String yetAnotherArg, Object andStillAnother) { ... } Una línea que contiene sentencias If, generalmente podría usar la regla de los 8 espacios, desde la indentacion convencional, se hace difícil ver el cuerpo Por ejemplo. //DON'T USE THIS INDENTATION if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { //MAL FINAL doSomethingAboutIt(); //LINEA FACIL DE FALLAR } //USAR ESTA IDENTACION if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { doSomethingAboutIt(); } //O USAR ESTO if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { doSomethingAboutIt(); } Aquí hay tres opciones para formatear expresiones ternarias. alpha = (aLongBooleanExpression) ? beta : gamma; alpha = (aLongBooleanExpression) ? beta : gamma; alpha = (aLongBooleanExpression) ? beta : gamma; 5 - Comentarios Los Programas en Java tienen dos tipos de comentarios: Comentarios de Implementación y Documentación. Los Comentarios de Implementación son estos que se encuentran en C++, los cuales son definidos por /*...*/, y //. Comentarios de Documentación (conocidos como “comentarios doc”) son solamente java y son delimitados por /**...*/. Estos son extraídos a archivos HTML usando la herramienta javadoc. Los comentarios de Implementación son en la práctica vagos para comentar hacia fuera del código o para comentarios sobre una puesta en práctica. Los comentarios de Documentación se proponen para describir la especificación del código, de una perspectiva sin puesta en práctica. Puede ser leído por los reveladores que no necesariamente podrían tener el código original al alcance de la mano. Los Comentarios pueden ser usados para dar resúmenes de código y proveer información adicional que no esta fácilmente accesible en el código. Los Comentarios contienen solo información que es relevante para leer y entender el programa. Por Ejemplo, información acerca de cómo un correspondiente paquete esta construido o en que directorio este reside no debe ser incluido como comentario. 5.1 Formatos de Comentarios de Implementación Programas pueden tener cuatro estilos de comentarios de implantación: bloque, línea-simple, rastreo y final-de-línea 5.1.1 Comentarios De Bloque Los Comentarios de Bloque son usados para proveer descripción de archivos, métodos, estructura de datos y algoritmos. Esos comentarios son usados para iniciar cada archiva y antes de cada método. Ellos pueden ser usados en otros lugares, como dentro de los métodos. Los Comentarios de Bloque dentro de una función o método pueden ser indentados en el mismo nivel del código que ellos describen. Un comentario en bloque podría preceder por una línea en blanco para ponerlo aparte del resto del código. /* * Aquí son los comentarios en bloque. */ Comentarios en bloque pueden empezar con /*-, el cual es reconocido por indent(1) como el inicio de un comentario en bloque que no es reformateado. Ejemplo: /** Here is a block comment with some very special * formatting that I want indent(1) to ignore. * * one * two * three */ 5.1.2 Comentario de Línea-Simple Los Comentarios cortos pueden aparecer en una línea simple indentada al nivel del código que sigue. Si un comentario no puede ser escrito en una línea, este debe seguir el formato de comentario en bloque. Un comentario de línea-simple pude ser precedido por una línea en blanco. Aquí un ejemplo de un comentario de línea-simple en un código Java. if (condicion) { /* Manejar la condición. */ ... } 5.1.3 Comentarios de Rastreo Comentarios muy cortos pueden aparecer en la misma línea que el código, pero deberían estar situados bastante lejos de las declaraciones. Si más de un comentario corto aparece en un segmento de código, estos deben estar al mismo nivel. Aquí un ejemplo de un comentario de rastreo. if (a == 2) { return TRUE; } else { return isPrime(a); } /* special case */ /* works only for odd a */ 5.1.4 Comentarios Fin-de-Línea El // delimitador de comentario puede comentar fuera de un línea completa o solo de una línea parcial. Estos pueden ser utilizados en líneas consecutivas; además, pueden ser usados para comentar múltiples líneas de una sección de código. Ejemplos de los tres estilos: if (foo > 1) { // Do a double-flip. ... } else { return false; // Explain why here. } //if (bar > 1) { // // // Do a triple-flip. // ... //} //else { // return false; //} 5.2 Comentarios de Documentacion Comentarios Doc describen Clases Java, interfaces, constructores, métodos y campos. Cada comentario Doc es colocado dentro de un delimitador de comentario /**...*/, con un comentario por clase, interface o miembro. Este comentario podría aparecer justo antes de la declaración. /** * La Clase Ejemplo provee ... */ public class Ejemplo { ... 6 - Declaraciones 6.1 Numero por Línea Una declaración por línea es recomendada ya que esto anima a comentar. int level; // nivel de indentacion int size; // tamaño de la tabla es preferable sobre, int level, size; No poner diferentes tipos sobre la misma linea. Ejemplo: Tambien int int Object int foo, fooarray[]; //ERRONEO! se pueden usar tabs entre los tipos y los identificadores. Ejemplo: level; // indentation level size; // size of table currentEntry; // currently selected table entry 6.2 Inicialización Inicializar variables locales donde estas son declaradas. La única razón para no inicializar una variables donde esta declarada es que su valor inicial dependa de alguna ocurrencia computacional. 6.3 Placement Poner declaraciones solo al inicio de bloques. void myMethod() { int int1 = 0; if (condition) { int int2 = 0; } // Empezando un bloque de método // Empezando un bloque ‘if’ } La única excepción de la regla son los índices para los bucles, los cuales en java pueden ser declarados en la misma sentencia. for (int i = 0; i < maxLoops; i++) { ... } Evitar declaraciones locales que ocultan declaraciones de alto nivel. Por Ejemplo, no declarar la misma variable en un mismo bloque. int count; ... myMethod() { if (condition) { } ... int count = 0; ... // EVITAR ! } 6.4 Declaración de Clases e Interfaces Cuando codificas interfaces o clases java, debes seguir las siguientes reglas de formato: No espacios entre un nombre de método y el paréntesis “(”. Al abrir llave “{” este debe aparecer en el fin de la misma línea que declara al sentencia. Al cerrar llave “}” este deber aparecer indentado al mismo nivel que la llave de inicio. Cuando la sentencia es nula el “}” aparece inmediatamente después del “{” . class Sample extends Object { int ivar1; int ivar2; Sample(int i, int j) { ivar1 = i; ivar2 = j; } int emptyMethod() {} ... } Metodos son separados por líneas en blanco. 7 - Expresiones 7.1 Expresiones Simple Cada línea puede contener al menos una sentencia. Ejemplo: argv++; // Correcto argc--; // Correcto argv++; argc--; // AVOID! 7.2 Expresiones Compuestas Sentencias Compuestas son sentencias que contienen listas de sentencias cerradas en llaves “{sentencia}”. Ejemplos: Las declaraciones incluidas deben estar indentadas en un mayor nivel que las sentencias compuestas. El abrir llaves puede ser en el fin de la línea que inicia la sentencia compuesta; el cerrar llaves puede iniciar en una línea y ser indentado al inicio de una sentencia compuesta. Las llaves son usados alrededor de sentencias. Aun si son sentencias simples, cuando ellos son parte de una estructura de control, como un if- else o for. Esto hace fácil agregar sentencias sin introducir accidentalmente errores u olvidar agregar llaves. 7.3 Expresión de retorno. Una sentencia de retorno con un valor no debería usar paréntesis a menos que el valor de retorno sea obvio de alguna forma. Ejemplo: return; return myDisk.size(); return (size ? size : defaultSize); 7.4 Expresiones if, if-else, if else-if else La if-else sentencia debe tener la siguiente forma: if (condition) { expresiones; } if (condition) { expresiones; } else { expresiones; } if (condition) { expresiones; } else if (condition) { expresiones; } else{ expresiones; } Nota: sentencias if siempre usan llaves. Evitar el siguiente error de forma. if (condition) //EVITAR! ESTO OMITE LAS LLAVES. {}! statement; 7.5 Expresion for Una sentencia for debe tener la siguiente forma: for (initialization; condition; update) { expresiones; } Una sentencia vacía debe tener la siguiente forma: for (initialization; condition; update); Cuando uses el operador coma en la inicialización o actualizaciones de cláusulas en una sentencia for, evitar la complejidad de usar mas de tres variables. Si necesitas, usar sentencias separadas antes del bucle for o en el fin del bucle. 7.6 Expresion while Una declaración while debe tener la siguiente forma: while (condition) { statements; } Una sentencia vacía debe tener la siguiente forma: while (condition); 7.7 Expresion do-while Una sentencia do-while debe tener la siguiente forma: do { statements; } while (condition); 7.8 Expresion switch Una sentencia switch debe tener la siguiente forma: switch (condition) { case ABC: statements; /* falls through */ case DEF: statements; break; case XYZ: statements; break; default: statements; break; } 7.9 Expresion try-catch Una declaración try-catch debe tener el siguiente formato: try { statements; } catch (ExceptionClass e) { statements; } Una sentencia try-catch debe seguir de un finally, el cual ejecuta independientemente si el bloque try ha sido completado satisfactoriamente. try { statements; } catch (ExceptionClass e) { statements; } finally { statements; } 8 – Espacio Blanco 8.1 Líneas en Blanco Las Líneas en blanco mejoran la legibilidad al separar secciones de código que son relacionadas lógicamente. Dos líneas en blanco son usadas en las siguientes circunstancias: Entre secciones de un archivo. Entre definiciones de clases e interfaces. Una línea en blanco es siempre usada en las siguientes circunstancias: Entre métodos Entre variables locales en un método y en la primera sentencia. Antes de un bloque o línea siempre de comentario. Entre secciones lógica dentro de un método para mejorar la legibilidad. 8.2 Espacios en Blanco Espacios en blanco se podrían usar en las siguientes circunstancias: Una palabra clave seguido de un paréntesis debe ser separada por un espacio. Ejemplo: while (true) { ... } Un espacio en blanco puede aparecer después de comas en una lista de argumentos. Todos los operadores binarios de excepción. Deben ser separados de sus operadores por espacios. a += c + d; a = (a + b) / (c * d); while (d++ = s++) { n++; } printSize("size is " + foo + "\n"); La expresión dentro de una sentencia for debe ser separada de espacio en blanco. Ejemplo: for (expr1; expr2; expr3) Casts son seguidos de espacios en blanco. Ejemplo: myMethod((byte) aNum, (Object) x); myMethod((int) (cp + 5), ((int) (i + 3)) + 1); 9 – Convención de Nombres Las Convenciones de Nombres hacen los programas más entendibles ya son fáciles de leerlos. Estos pueden dar información acerca de la función del identificador el cual puede ser de ayuda para entender el código. Tipo de Reglas para Nombrado Identificador Ejemplos El prefijo de un único nombre de paquete es siempre escrito en letras ASCII minúsculas y son uno de los más altos niveles de nombres de dominio, actualmente com, edu, gov, mil, net, org. Paquetes Componentes subsiguientes del nombre del paquete varían de acuerdo a las convenciones com.sun.eng com.apple.quicktime.v2 edu.cmu.cs.bovik.cheese de nombre de la propia organización. Como convenciones se especifica que ciertos nombres de directorio componen una división, departamento, proyecto, maquina o nombres de acceso. Nombres de clases son sustantivos, en casos mixtos con la primera letra de cada palabra interna en mayúscula. Tratar de dejar tus Clases nombres de clases simples y descriptivas. Usar palabras completas, evitar acrónimos class class ImageSprite; Raster; y abreviaciones. Interfaces son nombrados iguales que las Interfaces interface RasterDelegate; interface Storing; clases. Métodos son verbos, pueden ser mixtos: con la primera letra en minúscula y la letra de cada Métodos palabra interna en mayúscula. A excepción de las variables, todas las instancias de clase son mixtas con minúscula la Variables correr(); correrRapido(); getBackground(); primera letra. Las palabras internas empiezan con mayúscula. Los nombres de variables no int char float i; c; myWidth; empiezan con carácter underscore _ o signo dolar $. Aun cuando permitan a ambos. Nombres de variables son cortos y significativos. La elección de un nombre de variable es mnemónico. Variables de un solo carácter debería ser evitados, excepto para variables temporales. Nombres comunes de variables temporales son i, j, k, m, y n para integres; c, d y e para caracteres. Los nombres de variables declarados como constantes en una clase son todo en mayúscula Constantes y con underscore ("_") para separar entre palabra. static final int MIN_WIDTH = 4; static final int MAX_WIDTH = 999; static final int GET_THE_CPU = 1; 10 – Prácticas De Programación 10.1 Proveer Acceso A Intancias Y Variables De Clase No hacer ninguna instancia o variable de clase sin una buena razón. A menudo las variables instanciadas no necesitan estar explícitamente obtenidas o puestas a menudo sucede como un efecto secundario de los métodos que llaman. Un ejemplo de una publica instancia de variable apropiada es el caso donde la clase es esencialmente una estructura de datos, sin comportamiento, en otras palabras, si tu has usado una estructura en vez de una clase, entonces es apropiado hacer la instancia de variable de clase publica. 10.2 Referencia a Variables de Clases y Métodos Evitar usar un objeto para acceder a una variable o método de una clase estática. Use en vez de eso el nombre de la clase. Por Ejemplo: classMethod(); //OK AClass.classMethod(); //OK anObject.classMethod(); //EVITAR! 10.3 Constantes Constantes numéricos no son codificadas directamente, excepto de -1, 0 y 1, los cuales pueden aparecer como valor de un contador para una sentencia for. 10.4 Variable Assignments Evitar asignar muchas variables en el mismo valor de una simple sentencia. Es muy difícil de leer. Ejemplo: fooBar.fChar = barFoo.lchar = 'c'; // AVOID! No usar operadores de asignación en lugar donde estos pueden ser fácilmente confundidos con un operador de igualdad. Ejemplo: if (c++ = d++) { // EVITAR! (Java disallows) ... } should be written as if ((c++ = d++) != 0) { ... } No usar asignadores en tentativa de mejorar la performance. Esta es una tarea del compilador. Ejemplo: d = (a = b + c) + r; should be written as a = b + c; d = a + r; // AVOID! 10.5 Buenas Prácticas a considerar 10.5.1 Paréntesis Es generalmente Buena idea usar paréntesis generosamente en expresiones que envuelven operaciones mixtas para evitar problemas de preferencias de operador. Incluso si la preferencia del operador le parece clara, esto no podría ser para otros, no se puede asumir que otros programadores conocen la preferencia que usted si lo conoce. if (a == b && c == d) // EVITAR! if ((a == b) && (c == d)) // CORRECTO 10.5.2 Retornando Valores Trarta de hacer que la estructura de su programa retorne de la mejor manera. if (booleanExpression) { return true; } else { return false; } Podrias hacerlo de la siguiente manera. return booleanExpression; Similarmente, if (condicion) { return x; } return y; Se pordia escribir como return (condition ? x : y); 10.5.3 Expresiones Antes ‘?’ En El Operador Condicional Si una expresión contiene un operador binario aparece antes del ‘?’ en el operador ternario ?:, este podría estar en paréntesis. Ejemplo: (x >= 0) ? x : -x; 10.5.4 Comentarios Especiales Use XXX en un comentario para señalar algo que es falso. Use FIXME para señalar algo que es falso y dañado. 11 - Ejemplos de Código 11.1 Ejemplo de Archivo de Fuentes Java El siguiente ejemplo muestra como formatear un archive Java que contiene una clase publica. Las Interfaces son formateadas de modo similar. /* * @(#)Blah.java 1.82 99/03/18 * * Copyright (c) 1994-1999 * All rights reserved. * * */ package java.blah; import java.blah.blahdy.BlahBlah; /** * Descripcion de clase aqui. * * @version 1.82 18 Mar 2008 * @author Firstname Lastname */ public class Blah extends SomeClass { /* Un comentario de implementación de clases aquí. */ /** classVar1 comentario de documentación */ public static int classVar1; /** * classVar2 comentarios de documentación que ocupan * mas de una linea */ private static Object classVar2; /** instanceVar1 comentario de documentación */ public Object instanceVar1; /** instanceVar2 comentario de documentación */ protected int instanceVar2; /** instanceVar3 comentario de documentación */ private Object[] instanceVar3; /** * ...constructor Blah comentario de documentación... */ public Blah() { // ...implementación inicia aquí e... } /** * ...method doSomething comentario de documentación... */ public void doSomething() { // ...implementación inicia aquí... } /** * ...method doSomethingElse comentario de documentación... * @param someParam descripcion */ public void doSomethingElse(Object someParam) { // ...implementación inicia aquí... } }