Tutorial de Java

Sugerencias de Codificación, II

Anterior | Siguiente

Comentarios

Los programas Java pueden tener dos tipos de comentarios: de implementación o de documentación. Los primeros son aquellos que se asemejan a los comentarios que se pueden encontrar en C++ y que están delimitados por /*...*/ y //. Los comentarios de documentación son exclusivos de Java y están delimitados por /**...*/. Estos últimos comentarios pueden ser extraídos a ficheros HTML utilizando la herramienta javadoc.

Los comentarios de implementación se usan para aclarar el código o explicar una determinada implementación. Los comentarios para documentación describen la especificación que ha dado lugar al código, desde una perspectiva más general que la de la implementación, para que pueda ser comprendida por desarrolladores que no tengan necesariamente que tener a mano el código fuente.

Los comentarios se deben utilizar para dar una visión general y proporcionar información adicional que no se lee directamente en el código. Los comentarios deben contener solamente información que sea relevante a la lectura y entendimiento del programa. Por ejemplo, información sobre cómo se construye un paquete o en qué directorio se guarda, no debe incluirse como comentario.

La aclaración de decisiones de diseño que no sean triviales o no sean obvias, sí debe colocarse, pero hay que evitar la duplicación de información que se encuentre presente en el código (con suficiente claridad). Es muy fácil que comentarios redundantes se queden obsoletos. En general, se deben evitar los comentarios que puedan quedarse fuera de lugar con la evolución del código.

La frecuencia de los comentarios, a veces lo que refleja es una calidad pobre del código. Cuando sea necesario incluir demasiados comentarios de aclaración, debería considerarse la posibilidad de reescribir el código para hacerlo más claro.

Los comentarios jamás deben adornarse con largas cajas pintadas con asteriscos u otros caracteres. Los comentarios nunca deben incluir caracteres especiales como retornos de carro o saltos de página.

Comentarios de Implementación

Los programas pueden tener cuatro tipos de comentarios referidos a la implementación: bloque, línea simple, de aclaración y de fin de línea.

Bloque

Los bloques se utilizar para proporcionar descripciones de ficheros, métodos, estructuras de datos y algoritmos. Se deben utilizar al comienzo de cada fichero y antes de cada método. También se pueden emplear en otros lugares, como por ejemplo dentro de métodos. Los bloques que se encuentren dentro de una función o método deben estar indentados al mismo nivel que el código que describen.

Un comentario de bloque siempre debe ir precedido por una línea en blanco para separarlo del resto del código. Cada una de las líneas del bloque debe comenzar siempre por un asterisco (*), excepto la primera.

/*
 * Este es un comentario de Bloque.
 */

Línea simple

Los comentarios cortos pueden aparecer en una sola línea indentada al nivel del código que la sigue. Si un comentario no cabe en una línea, debería seguirse el formato explicado para el bloque. Es conveniente colocar una línea en blanco antes de la línea simple de comentario.

if (condicion) {
    /* Control de la condición. */
    ...
}

Aclaración

Son comentarios muy cortos que pueden aparecer en la misma línea que el código que describen. Deben separarse suficientemente de las sentencias. Si aparecen varias aclaraciones en un mismo bloque de código, deben estar indentados al mismo nivel. Evitar el estilo de comentario del lenguaje ensamblador de colocar una aclaración a cada línea de código.

Este es un ejemplo de aclaraciones en código Java:

if (a == 2) {
    return( TRUE );            /* caso especial */
} else {
    return( esprimo(a) );      /* funcina sólo para a impar */
}

Fin de líneas

El delimitador // inicia un comentario que continúa hasta el carácter de nueva línea. Puede comentar una línea completa o sólo parcialmente. No debería utilizarse para comentar líneas consecutivas de texto, aunque se puede usar para comentar múltiples líneas consecutivas de código. El ejemplo muestra casos de las tres situaciones.

if (foo > 1) {
    // Hace un salto doble.
    ...
}
else
    return( false );          // Explicar aquí el porqué.

//if (bar > 1) {
//
//    // Hace un salto triple.
//    ...
//}
//else
//    return( false );

Comentarios de Documentación

El lector puede encontrar más detalles de cómo escribir comentarios de documentación en la referencia de javadoc, o en la página Web de esta herramienta (http://java.sun.com/products/jdk/javadoc/).

Los comentarios de documentación describen las clases Java, interfaces, constructores, métodos y campos. Cada uno de estos comentarios está delimitado por /**...*/, con un comentario por API, que debe aparecer justo antes de la declaración:

/**
 * La clase Ejemplo proporciona ...
 */
class Ejemplo { ...

Las clases e interfaces no están indentadas, mientras que sus miembros sí lo están. La primera línea del comentario (/**) para clases e interfaces no está indentada; las siguientes líneas del comentario están indentadas 1 espacio, para alinear verticalmente los asteriscos. Los miembros, incluyendo los constructores, tienen una identación de 4 espacios y las líneas siguientes de 5.

Si se necesita proporcionar información acerca de una clase, interfaz, variable o método, que no es adecuada para la documentación, se debe utilizar un comentario de bloque o de línea simple inmediatamente después de la declaración. Por ejemplo, detalles acerca de la implementación de una clase deben ir en un comentario de bloque a continuación de la sentencia class, no en el comentario de documentación de la clase.

Los comentarios de documentación no deben colocarse dentro del bloque de definición de un método o constructor, porque Java asocia el comentario de documentación a la primera sentencia que se encuentra después del propio comentario.

Declaraciones

Algunas recomendaciones que deben seguirse a la hora de las declaraciones de variables o métodos se recogen en los siguientes párrafos.

Número por línea

Se recomienda colocar solamente una declaración por línea y se insta a comentarla siempre. Es decir:

int nivel;   // nivel de indentación
int nombre;  // nombre de la tabla

es preferible a colocar:

int nivel, nombre;

En ningún caso variables y funciones deben compartir una misma línea de declaración; por ejemplo:

long dbaddr, getDbaddr(); // ERRONEO!

Nunca colocar tipos diferentes en una misma línea; por ejemplo:

int foo, fooarray[]; // ERRONEO!

En los ejemplos anteriores se utiliza un espacio para separar el tipo y el identificador. Otra alternativa aceptable es el uso de tabuladores para tal efecto; por ejemplo:

int     nivel;             // nivel de indentación
int     nombre;            // nombre de la tabla
Object  entradaActual;     // elemento actualmente seleccionado

Posición

Las declaraciones solamente deben situarse al comienzo de los bloques, entendiendo por bloque cualquier trozo de código delimitado por llaves "{" y "}". No esperar a declarar las variables hasta que se utilicen por primera vez; esto puede confundir a un programador despistado y fastidiar la portabilidad del código dentro del ámbito.

void MiMetodo() {
    int int1;         // comienzo del bloque del método
    if (condicion) {
        int int2;     // comienzo del bloque del "if"
        ...
    }
}

La única excepción a esta regla es el uso de índices en los bucles, que en Java se pueden colocar dentro de la sentencia que declara el bucle.

for (int i = 0; i < maxLoops; i++) { ...

Evitar declaraciones locales que oculten declaraciones de un nivel más alto. Por ejemplo, no declarar una variable con el mismo nombre en un bloque más interno.

int contador;
...
func() {
    if (condicion) {
        int contador;     // EVITARLO!
        ...
    }
    ...
}

Inicialización

Intentar siempre inicializar las variables locales allí donde se declaren. La única razón admitida para no inicializarlas en el momento de la declaración, es que su valor inicial dependa de alguna operación que deba realizarse en primer lugar.

Declaraciones de clases e interfaces

Cuando se codifiquen clases e interfaces Java, se deben seguir las siguientes reglas de formateo:

  • Los métodos deber ir separados, al menos, por una línea en blanco
  • No colocar ningún espacio entre el nombre del método y el paréntesis "(" con el que comienza la lista de parámetros
  • La llave de apertura "{" debe aparecer al final de la misma línea que la sentencia de declaración
  • La llave de cierre "}" debe situarse al comienzo de la línea indentada para alinearse con la sentencia de apertura, excepto cuando se trata de un método vacío, en cuyo caso puede aparecer a continuación de la llave de apertura
class Ejemplo extends Object {
    int ivar1;
    int ivar2;
    Ejemplo( int i, int j ) {
        ivar1 = i;
        ivar2 = j;
    }
    int metodoVacio() {}
    ...
}

Sentencias

Sentecias simples

Cada línea debería contener solamente una sentencia; por ejemplo:

argv++; argc--;       // EVITARLO!

No utilizar nunca el operador coma para agrupar múltiples sentencias, a no ser que sea por una razón muy, muy obvia; por ejemplo:

if (err) {
    Format.print(System.out, "error"), exit(1);   // MUY, MUY MAL!
}

Sentencias complejas

Sentencias complejas, o compuestas, son aquellas que contienen sentencias simples encerradas entre llaves. A continuación hay varios ejemplos.

  • Las sentencias incluidas deben estar indentadas un nivel más que la sentencia compuesta
  • La llave de apertura debe colocarse al final de la línea en que comienza la sentencia compuesta; la llave de cierre debe ir al comienzo de una línea e indentarla al mismo nivel de la sentencia compuesta
  • Deben usarse llaves para todas estas sentencias cuando forman parte de una estructura de control, como una sentencia if-else o for. Esto hace más fácil incorporar sentencias sin que se introduzcan errores debido a llaves olvidadas.

return

Si devuelve un valor, éste no debe ir entre paréntesis a no ser que su uso haga el valor de retorno más obvio o más claro.

return;

return miDisco.size();

return (size ? size : defaultSize);

if, if-else, if-else-if-else

El tipo de sentencias condicionales if-else deberían adaptarse a alguna de las siguientes formas:

if (condicion) {
    sentencias;
}

if (condicion) {
    sentencias;
} else {
    sentencias;
}

if (condicion) {
    sentencias;
} else if (condicion) {
    sentencias;
} else if (condicion) {
    sentencias;
}

Las sentencias if siempre deben incluir las llaves. Si se emiten, esa sentencia está sentenciada a ser una fuente de errores.

if (condicion) // EVITARLO!  FALTAN LAS LLAVES {}!
    sentencia;

for

Una sentencia for debería ser siempre de la forma:

for (initializacion; condicion; incremento) {
     sentencias;
}

Una sentencia for vacía, auqella en la que todo su trabajo está definido en las cláusulas de inicialización, condición e incremento, debería tener la siguiente forma:

for (initializacion; condicion; incremento);

Cuando se utilice el operador coma en las cláusulas de inicialización o incremento en la sentencia for, evitar la complejidad no utilizando más de tres variables. Si es necesario, utilizar sentencias separadas antes del bucle for (para la cláusula de inicialización), o al final del bucle (para la cláusula de incremento):

while

Una sentencia while debería tener la forma que se muestra a continuación:

while (condicion) {
    sentencias;
}

En el caso de una sentencia while vacía, la forma que debería tener es la que sigue:

while (condicion);

do-while

Una sentencia do-while debería tener la forma siguiente:

do {
    sentencias;
} while (condicion);

switch

Una sentencia switch debería ser de la forma que se indica:

switch (condicion) {
case ABC:
    sentencias;
    /* sigue la ejecución */
case DEF:
    sentencias;
    break;
case XYZ:
    sentencias;
    break;
default:
    sentencias;
    break;
}

Cada vez que una cláusula case deba seguir la ejecución en la siguiente cláusula case, es decir, no incluya la sentencia break; es imprescindible incluir un comentario en el lugar que ocuparía la sentencia break, tal como se muestra en el ejemplo con el comentario /* sigue la ejecución */.

Cada sentencia switch debería incluir el caso default. Aquí la sentencia break es redundante, pero debería incluirse siempre para evitar errores en caso de que se añada una sentencia case posterior y se ejecute si deber hacerlo.

try-catch

Una sentencia try-catch debería tener el siguiente formato:

try {
    sentencias;
} catch (ExceptionClass e) {
    sentencias;
}

Navegador

Home | Anterior | Siguiente | Indice | Correo