Estilo de código Java del AOSP para colaboradores

Los estilos de código de esta página son reglas estrictas para contribuir con código Java al Proyecto de código abierto de Android (AOSP). Por lo general, no se aceptan las contribuciones a la plataforma de Android que no cumplen con las reglas. Reconocemos que no todo el código existente cumple con estas reglas, pero esperamos que todo el código nuevo sí lo haga. Consulta el documento Programación respetuosa para ver algunos ejemplos de términos que se deben usar o evitar para lograr un ecosistema más inclusivo.

Sé coherente

Una de las reglas más simples es SER COHERENTE. Si estás editando código, tómate algunos minutos para revisar el código que lo rodea y determinar su estilo. Si ese código usa espacios alrededor de las cláusulas if, tú también deberías hacerlo. Si los comentarios del código tienen pequeños cuadros de estrellas a su alrededor, haz lo mismo con tus comentarios.

El objetivo de tener pautas de estilo es contar con vocabulario de programación en común para que los lectores puedan concentrarse en lo que estás diciendo y no en cómo lo dices. Aquí incluimos reglas de estilo globales para que conozcas el vocabulario. Sin embargo, el estilo local también es importante. Si el código que agregas a un archivo se ve muy distinto al código existente que lo rodea, puede confundir a los lectores cuando lo lean. Intenta evitar que esto suceda.

Reglas del lenguaje Java

Android cumple con las convenciones de programación de Java estándar, además de las reglas adicionales que se describen a continuación.

No ignores las excepciones

Puede ser tentador escribir código que ignore una excepción, por ejemplo:

  void setServerPort(String value) {
      try {
          serverPort = Integer.parseInt(value);
      } catch (NumberFormatException e) { }
  }

Evita lo anterior. Aunque creas que tu código nunca se encontrará con este error o que no es importante ocuparse de él, ignorar este tipo de excepciones crea defectos en tu código que otra persona podría aprovechar en el futuro. Debes manejar cada excepción en tu código de acuerdo con principios. El manejo específico depende de cada caso.

"Duda cada vez que tengas una cláusula de captura vacía. Aunque, en algunos casos, es lo correcto, deberías reflexionar al respecto. En Java, resulta difícil no pensar que algo está mal". (James Gosling)

Las alternativas aceptables (en orden de preferencia) son las siguientes:

  • Muestra la excepción al llamador de tu método.
      void setServerPort(String value) throws NumberFormatException {
          serverPort = Integer.parseInt(value);
      }
    
  • Muestra una excepción nueva que sea apropiada para tu nivel de abstracción.
      void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
      }
    
  • Maneja el error correctamente y reemplaza un valor apropiado en el bloque catch {}.
      /** Set port. If value is not a valid number, 80 is substituted. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            serverPort = 80;  // default port for server
        }
      }
    
  • Captura la excepción y arroja una instancia nueva de RuntimeException. Como esto puede resultar peligroso, hazlo solo cuando tengas la certeza de que, si el error ocurre, lo correcto sea generar una falla.
      /** Set port. If value is not a valid number, die. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("port " + value " is invalid, ", e);
        }
      }
    
  • Como último recurso, si estás seguro de que ignorar la excepción es lo correcto, puedes hacerlo, aunque debes comentar por qué y dar un buen motivo.
    /** If value is not a valid number, original port number is used. */
    
    void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // Method is documented to just ignore invalid user input.
            // serverPort will just be unchanged.
        }
    }
    

No captures excepciones genéricas

También puede ser tentador no hacer todos los pasos necesarios cuando se capturan excepciones y hacer lo siguiente:

  try {
      someComplicatedIOFunction();        // may throw IOException
      someComplicatedParsingFunction();   // may throw ParsingException
      someComplicatedSecurityFunction();  // may throw SecurityException
      // phew, made it all the way
  } catch (Exception e) {                 // I'll just catch all exceptions
      handleError();                      // with one generic handler!
  }

Evita lo anterior. En casi todos los casos, es inapropiado capturar Exception o Throwable genéricos (es preferible que no sea Throwable, ya que incluye excepciones de Error). Es peligroso porque significa que las excepciones que no esperabas (incluidas las excepciones de tiempo de ejecución, como ClassCastException) se capturan en el manejo de errores a nivel de la app. Como se ocultan las propiedades de manejo de fallas de tu código, si alguien agrega un tipo nuevo de excepción al código al que estás llamando, el compilador no te indicará que debes manejar el error de otro modo. En la mayoría de los casos, no deberías manejar del mismo modo los distintos tipos de excepciones.

La excepción inusual a esta regla es el código de prueba y el código de nivel superior en el que quieres capturar todos los tipos de errores (para evitar que se muestren en una IU o para mantener un trabajo por lotes en ejecución). En estos casos, puedes capturar una Exception genérica (o un Throwable) y manejar el error de manera adecuada. Sin embargo, analízalo con cuidado antes de hacerlo y explica en los comentarios por qué es seguro en este contexto.

Alternativas para capturar excepciones genéricas:

  • Captura cada excepción por separado como parte de un bloque de captura múltiple, por ejemplo:
    try {
        ...
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        ...
    }
  • Refactoriza tu código para tener un manejo de errores más detallado con varios bloques de prueba. Divide E/S del análisis y maneja los errores por separado en cada caso.
  • Vuelve a arrojar la excepción. En muchos casos, no necesitas capturar la excepción en este nivel. Solo deja que el método la arroje.

Recuerda que las excepciones son tus aliadas. Cuando el compilador se queje de que no estás capturando una excepción, no te lo tomes a mal. ¡Sonríe! El compilador acaba de facilitarte la captura de problemas de tiempo de ejecución en tu código.

No uses finalizadores

Los finalizadores son una forma de ejecutar un fragmento de código cuando un objeto se recolecta por no ser utilizado. Si bien pueden ser útiles para la limpieza (especialmente de recursos externos), no hay garantías de cuándo se llamará a un finalizador (ni de que se lo llamará).

Android no usa finalizadores. En la mayoría de los casos, puedes usar un buen manejo de excepciones. Si el finalizador es imprescindible, define un método close() (o similar) y documenta exactamente cuándo es necesario llamar a ese método (consulta InputStream para ver un ejemplo). En este caso es apropiado, pero no obligatorio, imprimir un mensaje de registro breve del finalizador, siempre que no se espere que sobrecargue los registros.

Califica completamente las importaciones

Si quieres usar la clase Bar del paquete foo, puedes importarla de dos maneras posibles:

  • import foo.*;

    Reduce potencialmente la cantidad de sentencias de importación.

  • import foo.Bar;

    Deja en claro qué clases se usaron y los encargados de mantener el código pueden leerlo con más facilidad.

Usa import foo.Bar; para importar todo el código de Android. Se crea una excepción explícita para las bibliotecas estándar de Java (java.util.*, java.io.*, etc.) y el código de prueba de unidades (junit.framework.*).

Reglas de la biblioteca de Java

Hay convenciones sobre el uso de herramientas y bibliotecas Java de Android. En algunos casos, la convención cambió de maneras significativas y es posible que el código más antiguo use un patrón o una biblioteca obsoletos. Si trabajas con este tipo de código, está permitido seguir usando el estilo existente. Sin embargo, cuando crees componentes nuevos, nunca uses bibliotecas obsoletas.

Reglas de estilo de Java

Usa comentarios estándar de Javadoc

Cada archivo debe tener una declaración de derechos de autor en la parte superior, seguida de instrucciones de paquete e importación (cada bloque separado por una línea en blanco) y, por último, la declaración de clase o interfaz. En los comentarios de Javadoc, describe la función de la clase o la interfaz.

/*
 * Copyright yyyy The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.foo;

import android.os.Blah;
import android.view.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Does X and Y and provides an abstraction for Z.
 */

public class Foo {
    ...
}

Cada clase y cada método público no trivial que escribas deberán contener un comentario de Javadoc con al menos una oración que describa la función de la clase o el método. Esta oración deberá comenzar con un verbo descriptivo en tercera persona.

Ejemplos

/** Returns the correctly rounded positive square root of a double value. */

static double sqrt(double a) {
    ...
}

o

/**
 * Constructs a new String by converting the specified array of
 * bytes using the platform's default character encoding.
 */
public String(byte[] bytes) {
    ...
}

No es necesario que escribas Javadoc para métodos get y set triviales como setFoo() si todo lo que tu Javadoc va a decir es "sets Foo". Si el método realiza una acción más compleja (por ejemplo, si aplica una restricción o tiene un efecto secundario importante), entonces debes documentarlo. Si no es evidente qué significa la propiedad "Foo", se debe documentar.

Todos los métodos que escribas, públicos o no, se beneficiarán con Javadoc. Los métodos públicos forman parte de una API y, por lo tanto, requieren Javadoc. Android no aplica un estilo específico para escribir comentarios de Javadoc, sino que debes seguir las instrucciones sobre la escritura de comentarios doc para la herramienta Javadoc.

Escribe métodos breves

Siempre que sea posible, asegúrate de que los métodos sean breves y estén enfocados. Sabemos que a veces los métodos largos son más apropiados, de manera que no hay un límite estricto en cuanto a su longitud. Si un método tiene más de unas 40 líneas, considera dividirlo sin dañar la estructura del programa.

Define campos en lugares estándar

Define campos en la parte superior del archivo o inmediatamente antes de los métodos que los usan.

Limita el alcance de las variables

Mantén el alcance de las variables locales al mínimo. De este modo, aumenta la legibilidad y el mantenimiento de tu código y se reducen las probabilidades de error. Declara cada variable en el bloque más interno que abarca todos los usos de la variable.

Declara las variables locales en el momento en que se usan por primera vez. Casi todas las declaraciones de variables locales deben incluir un inicializador. Si todavía no tienes información suficiente para inicializar una variable como corresponde, pospón la declaración hasta que dispongas de los datos necesarios.

La excepción son las sentencias de captura y prueba. Si una variable se inicializa con un valor de resultado de un método que muestra una excepción verificada, se debe inicializar dentro de un bloque de prueba. Si el valor se debe usar fuera del bloque de prueba, debes declararlo antes del bloque de prueba, donde todavía no se puede inicializar como corresponde:

// Instantiate class cl, which represents some sort of Set

Set s = null;
try {
    s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
    throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
    throw new IllegalArgumentException(cl + " not instantiable");
}

// Exercise the set
s.addAll(Arrays.asList(args));

Sin embargo, puedes evitar incluso este caso si encapsulas un bloque de captura y prueba en un método:

Set createSet(Class cl) {
    // Instantiate class cl, which represents some sort of Set
    try {
        return (Set) cl.newInstance();
    } catch(IllegalAccessException e) {
        throw new IllegalArgumentException(cl + " not accessible");
    } catch(InstantiationException e) {
        throw new IllegalArgumentException(cl + " not instantiable");
    }
}

...

// Exercise the set
Set s = createSet(cl);
s.addAll(Arrays.asList(args));

Declara las variables de bucle en la sentencia "for", a menos que haya un motivo válido para hacerlo de otro modo:

for (int i = 0; i < n; i++) {
    doSomething(i);
}

y

for (Iterator i = c.iterator(); i.hasNext(); ) {
    doSomethingElse(i.next());
}

Ordena las sentencias de importación

El orden de las sentencias de importación es el siguiente:

  1. Importaciones de Android
  2. Importaciones de terceros (com, junit, net, org)
  3. java y javax

Para que concuerden de manera exacta con la configuración de IDE, las importaciones deben cumplir con lo siguiente:

  • Deben seguir un orden alfabético dentro de cada grupo, en el que las letras en mayúscula van antes que las letras en minúscula (por ejemplo, Z va antes que a).
  • Deben estar separadas por una línea en blanco entre cada grupo significativo (android, com, junit, net, org, java, javax).

Originalmente, no había ningún requisito de estilo con respecto al orden, de manera que los IDEs siempre cambiaban de orden, o bien los desarrolladores de IDEs tenían que inhabilitar las funciones de administración de importación automática y mantener las importaciones de forma manual. Esto se consideraba poco efectivo. Cuando se preguntó sobre el estilo Java, los estilos preferidos variaban considerablemente y se determinó que Android solo necesitaba "elegir un orden y ser coherente". Por lo tanto, elegimos un estilo, actualizamos la guía de estilo e hicimos que los IDEs lo cumplieran. Esperamos que, a medida que los usuarios de IDE trabajen en el código, las importaciones en todos los paquetes coincidan con este patrón sin necesidad de trabajo de ingeniería adicional.

Elegimos este estilo de modo que ocurra lo siguiente:

  • Las importaciones que las personas quieran ver primero aparezcan en la parte superior (android).
  • Las importaciones que las personas quieran ver menos aparezcan en la parte inferior (java).
  • Las personas puedan cumplir con el estilo fácilmente.
  • Los IDEs puedan cumplir con el estilo.

Coloca las importaciones estáticas por encima del resto de las importaciones en el mismo orden que las importaciones regulares.

Usa espacios para la sangría

Utilizamos cuatro (4) sangrías de espacio para los bloques y nunca usamos tabulaciones. Si tienes dudas, mantén la coherencia con el código que lo rodea.

Utilizamos ocho (8) sangrías de espacio para las uniones de líneas, incluidas las asignaciones y las llamadas a función.

Recomendado

Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);

No recomendado

Instrument i =
    someLongExpression(that, wouldNotFit, on, one, line);

Cumple con convenciones de nomenclatura de campo

  • Los nombres de campos no públicos y no estáticos comienzan con m.
  • Los nombres de campos estáticos comienzan con s.
  • Otros campos comienzan con una letra minúscula.
  • Los campos finales estáticos (constantes, profundamente inmutables) son ALL_CAPS_WITH_UNDERSCORES.

Por ejemplo:

public class MyClass {
    public static final int SOME_CONSTANT = 42;
    public int publicField;
    private static MyClass sSingleton;
    int mPackagePrivate;
    private int mPrivate;
    protected int mProtected;
}

Usa el estilo de llave estándar

Coloca las llaves en la misma línea que el código que las antecede, no en su propia línea:

class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}

Es necesario colocar llaves alrededor de las sentencias de una condicional. Excepción: Si toda la condición (la condición y el cuerpo) cabe en una línea, puedes colocarla en una sola línea, aunque no es obligatorio. Se acepta, por ejemplo, el siguiente caso:

if (condition) {
    body();
}

Y el siguiente:

if (condition) body();

No se acepta, sin embargo, el caso a continuación:

if (condition)
    body();  // bad!

Limita la longitud de la línea

Cada línea de texto en tu código debe tener, como máximo, 100 caracteres. Si bien hubo mucho debate con respecto a esta regla, el máximo permitido sigue siendo de 100 caracteres, con las siguientes excepciones:

  • Si una línea de comentario contiene un comando de ejemplo o una URL literal de más de 100 caracteres, esa línea puede exceder los 100 caracteres para brindar mayor facilidad para cortar y pegar.
  • Las líneas de importaciones pueden superar el límite, ya que las personas raramente las ven (esto también simplifica la escritura de herramientas).

Usa anotaciones Java estándar

Las anotaciones deben preceder a otros modificadores del mismo elemento del lenguaje. Las anotaciones de marcadores simples (por ejemplo, @Override) pueden mostrarse en la misma línea con el elemento del lenguaje. Si hay varias anotaciones o anotaciones parametrizadas, muéstralas una por línea en orden alfabético.

Las prácticas estándar de Android para las tres anotaciones predefinidas en Java son las siguientes:

  • Usa la anotación @Deprecated cada vez que se desaconseje el uso del elemento con anotación. Si usas la anotación @Deprecated, también debes tener una etiqueta @deprecated de Javadoc, la cual debe nombrar una implementación alternativa. Además, recuerda que un método @Deprecated debe seguir funcionando. Si ves código antiguo con una etiqueta @deprecated de Javadoc, agrega la anotación @Deprecated.
  • Usa la anotación @Override cada vez que un método anule la declaración o implementación de una superclase. Por ejemplo, si usas la etiqueta @inheritdocs de Javadoc y derivas de una clase (no de una interfaz), también debes anotar que el método anula el método de la clase superior.
  • Usa la anotación @SuppressWarnings solo en circunstancias en las que sea imposible eliminar una advertencia. Si una advertencia pasa esta prueba de "imposible de eliminar", debes usar la anotación @SuppressWarnings para garantizar que todas las advertencias reflejen los problemas reales en el código.

    Cuando una anotación @SuppressWarnings sea necesaria, deberá tener un prefijo con un comentario TODO que explique la condición "imposible de eliminar". Por lo general, esto identifica una clase infractora que tiene una interfaz inusual. Por ejemplo:

    // TODO: The third-party class com.third.useful.Utility.rotate() needs generics
    @SuppressWarnings("generic-cast")
    List<String> blix = Utility.rotate(blax);
    

    Cuando se requiere una anotación @SuppressWarnings, refactoriza el código para aislar los elementos de software en los que se aplica la anotación.

Trata los acrónimos como palabras

Trata los acrónimos y las abreviaturas como palabras en las variables, los métodos y las clases de nomenclatura para que los nombres sean más fáciles de leer:

Bueno Malo
XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
class Html class HTML
String url String URL
long id long ID

Como las bases de código JDK y Android son muy poco coherentes en cuanto a los acrónimos, es prácticamente imposible que haya coherencia con el código que las rodea. Por lo tanto, siempre trata los acrónimos como palabras.

Usa los comentarios "TODO"

Usa comentarios TODO para el código que sea temporal; una solución a corto plazo; o código que sea lo suficientemente bueno, pero no perfecto. Estos comentarios deben incluir la cadena TODO en mayúscula, seguida de dos puntos:

// TODO: Remove this code after the UrlTable2 has been checked in.

y

// TODO: Change this to use a flag instead of a constant.

Si tu comentario TODO tiene el formato "En una fecha futura realizar una acción", asegúrate de incluir una fecha específica ("Corregir antes de noviembre de 2005") o un evento específico ("Quitar este código una vez que todos los mezcladores de producción comprendan el protocolo V7").

Registra con moderación

Si bien el registro es necesario, tiene un impacto negativo en el rendimiento y pierde su utilidad con rapidez si no se mantiene relativamente conciso. Las utilidades de registro proporcionan cinco niveles de registro diferentes:

  • ERROR: Se usa cuando se produce un error irrecuperable, es decir, algo tendrá consecuencias visibles para el usuario y no podrá recuperarse sin borrar datos, desinstalar apps, limpiar las particiones de datos o sobrescribir todo el dispositivo (o algo peor). Este nivel se registra siempre. Los problemas que ameritan que se creen registros en el nivel ERROR son buenos candidatos para informarlos a un servidor de recopilación de estadísticas.
  • WARNING: Se usa cuando ocurre un problema serio e inesperado; p. ej., una situación que tendrá consecuencias visibles para el usuario, pero que probablemente se pueda recuperar sin perder datos si realizas una acción explícita, como esperar o reiniciar una app, volver a descargar una versión nueva de una aplicación o reiniciar el dispositivo. Este nivel se registra siempre. Los problemas que ameritan que se creen registros en el nivel WARNING también pueden ser candidatos para informarlos a un servidor de recopilación de estadísticas.
  • INFORMATIVE: Se usa para indicar que sucedió algo interesante, es decir, cuando se detecta una situación que tal vez tenga un impacto generalizado, aunque no necesariamente sea un error. Esta condición solo debe ser registrada por un módulo que cree tener más autoridad en ese dominio (para evitar registros duplicados por parte de componentes sin autoridad). Este nivel se registra siempre.
  • DEBUG: Se usa para indicar lo que sucede en el dispositivo que podría ser relevante para investigar y depurar comportamientos inesperados. Solo debes registrar lo que sea necesario para recopilar información suficiente sobre lo que sucede con tu componente. Si tus registros de depuración dominan el registro, deberías usar el registro detallado.

    Este nivel se registra incluso en compilaciones de lanzamiento y debe estar rodeado por un bloque if (LOCAL_LOG) o if LOCAL_LOGD), en el que LOCAL_LOG[D] se define en tu clase o subcomponente, de manera que exista la posibilidad de inhabilitar todo el registro. Por lo tanto, no debe haber una lógica activa en un bloque if (LOCAL_LOG). También se debe colocar dentro del bloque if (LOCAL_LOG) toda la compilación de cadenas para el registro. No refactorices la llamada de registro en una llamada de método si se va a ocasionar que la compilación de cadenas se realice fuera del bloque if (LOCAL_LOG).

    Todavía hay partes del código que dicen if (localLOGV). Esto también se considera aceptable, aunque el nombre no sea estándar.

  • VERBOSE: Se usa para todo lo demás. Este nivel solo se registrará en las compilaciones de depuración y debe estar rodeado por un bloque if (LOCAL_LOGV) (o su equivalente) para que se pueda compilar de manera predeterminada. Todas las compilaciones de cadenas se quitarán de las compilaciones de lanzamiento y deben mostrarse dentro del bloque if (LOCAL_LOGV).

Notas

  • Dentro de un módulo determinado, que no sea en el nivel VERBOSE, los errores solo se deben informar una vez de ser posible. Dentro de una sola cadena de llamadas a función de un módulo, solo la función más interna debe mostrar el error, y los llamadores del mismo módulo solo deben agregar registros si eso ayuda considerablemente a aislar el problema.
  • En una cadena de módulos, siempre que no sea en el nivel VERBOSE, cuando un módulo de nivel inferior detecta datos no válidos provenientes de un módulo de nivel superior, el módulo de nivel inferior solo debe registrar la situación en el registro DEBUG, y solo si el registro brinda información que, de otro modo, no estaría disponible para el llamador. Específicamente, no es necesario registrar situaciones en las que se muestra una excepción (la excepción debería incluir toda la información relevante) ni situaciones en las que la única información que se registra está incluida en un código de error. Esto es importante sobre todo en la interacción entre el framework y las apps. Además, las condiciones que generen las apps de terceros que estén manejadas correctamente por el framework no deberían activar registros en niveles superiores a DEBUG. Las únicas situaciones que deberían activar registros en el nivel INFORMATIVE o niveles superiores son aquellas en las que un módulo o una app detecta un error que ocurre en su propio nivel o que proviene de un nivel inferior.
  • Cuando es probable que una condición que normalmente justificaría el registro ocurra muchas veces, puede convenir implementar algún mecanismo de límite de frecuencia para evitar el exceso de registros con muchas copias duplicadas de la misma información (o de información muy similar).
  • Las pérdidas de conectividad de red se consideran comunes y esperadas, y no deberían registrarse de forma indiscriminada. Una pérdida de conectividad de red que tenga consecuencias dentro de una app debería registrarse en el nivel DEBUG o VERBOSE (según si las consecuencias son lo suficientemente serias e inesperadas para registrarse en una compilación de lanzamiento).
  • Tener un sistema de archivos completo en un sistema de archivos al que se pueda acceder en apps de terceros o en su nombre no debería registrarse en un nivel superior a "INFORMATIVE".
  • Los datos no válidos provenientes de cualquier fuente que no sea de confianza (incluidos los archivos en el almacenamiento compartido o los datos que provengan de una conexión de red) se consideran esperados y no deberían activar ningún registro en un nivel superior a DEBUG cuando se detecte que no son válidos (incluso entonces, el registro debería ser lo más limitado posible).
  • Cuando se usa en objetos String, el operador + crea de manera implícita una instancia de StringBuilder con el tamaño del búfer predeterminado (16 caracteres) y potencialmente otros objetos String temporales. Por lo tanto, crear objetos StringBuilder de manera explícita no es más costoso que recurrir al operador + predeterminado (de hecho, puede ser mucho más eficiente). Ten en cuenta que un código que llama a Log.v() se compila y se ejecuta en compilaciones de lanzamiento, incluida la compilación de cadenas, incluso aunque no se lean los registros.
  • Todos los registros que otras personas deban poder leer o que estén disponibles en compilaciones de lanzamiento deben ser comprensibles y lo suficientemente concisos sin ser crípticos. Esto incluye todos los registros hasta el nivel DEBUG.
  • Cuando sea posible, mantén el registro en una sola línea. Se aceptan longitudes de línea de hasta 80 o 100 caracteres. Si es posible, evita longitudes superiores a 130 o 160 caracteres (incluida la longitud de la etiqueta).
  • Si el registro informa sobre operaciones realizadas correctamente, no lo uses en niveles superiores a VERBOSE.
  • Si usas el registro temporal para diagnosticar un problema que es difícil de reproducir, mantenlo en el nivel DEBUG o VERBOSE y delimítalo con bloques "if" que permitan inhabilitarlo durante el tiempo de compilación.
  • Ten cuidado con las filtraciones de seguridad a través del registro. Evita registrar información privada. En particular, evita registrar información sobre el contenido protegido. Esto es importante sobre todo cuando escribes el código del framework, ya que no resulta fácil saber con anticipación qué será información privada o contenido protegido y qué no.
  • Nunca uses System.out.println() (o printf() para el código nativo). System.out y System.err se redireccionan a /dev/null, por lo que tus sentencias de impresión no tienen efectos visibles. Sin embargo, la compilación de cadenas para estas llamadas se ejecuta de todos modos.
  • La regla de oro del registro es que tus registros no deben expulsar innecesariamente otros fuera del búfer, del mismo modo que otros registros no pueden hacerlo con los tuyos.

Reglas de estilo de Javatests

Sigue las convenciones de nomenclatura del método de prueba y usa un guion bajo para separar el objeto de la prueba del caso específico que estás probando. Con este estilo, es más sencillo ver qué casos se están probando. Por ejemplo:

testMethod_specificCase1 testMethod_specificCase2

void testIsDistinguishable_protanopia() {
    ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA)
    assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK))
    assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))
}