Google is committed to advancing racial equity for Black communities. See how.
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Stile del codice Java AOSP per i contributori

Gli stili di codice in questa pagina sono regole rigide per il contributo del codice Java al progetto Android Open Source (AOSP). I contributi alla piattaforma Android che non aderiscono a queste regole generalmente non sono accettati . Riconosciamo che non tutto il codice esistente segue queste regole, ma ci aspettiamo che tutto il nuovo codice sia conforme.

Sii coerente

Una delle regole più semplici è ESSERE COERENTI. Se stai modificando il codice, dedica alcuni minuti a esaminare il codice circostante e determinarne lo stile. Se quel codice utilizza spazi attorno alle clausole if , dovresti farlo anche tu. Se i commenti del codice hanno piccole scatole di stelle intorno a loro, fai in modo che anche i tuoi commenti abbiano piccole scatole di stelle intorno a loro.

Lo scopo di avere linee guida di stile è avere un vocabolario comune di codifica, in modo che i lettori possano concentrarsi su ciò che stai dicendo, piuttosto che su come lo stai dicendo. Presentiamo qui le regole di stile globali in modo che tu conosca il vocabolario, ma anche lo stile locale è importante. Se il codice che aggiungi a un file sembra drasticamente diverso dal codice esistente attorno ad esso, getta i lettori fuori ritmo quando lo leggono. Cerca di evitarlo.

Regole del linguaggio Java

Android segue le convenzioni di codifica Java standard con le regole aggiuntive descritte di seguito.

Non ignorare le eccezioni

Si può essere tentati di scrivere codice che ignori un'eccezione, come ad esempio:

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

Non farlo. Sebbene tu possa pensare che il tuo codice non incontrerà mai questa condizione di errore o che non sia importante gestirlo, ignorare questo tipo di eccezione crea delle mine nel tuo codice che qualcun altro può attivare un giorno. È necessario gestire ogni eccezione nel codice in modo basato sui principi; la gestione specifica varia a seconda del caso.

" Ogni volta che qualcuno ha una clausola vuota, dovrebbe avere una sensazione inquietante. Ci sono sicuramente momenti in cui è effettivamente la cosa giusta da fare, ma almeno devi pensarci. In Java non puoi sfuggire alla sensazione inquietante. "- James Gosling

Le alternative accettabili (in ordine di preferenza) sono:

  • Lancia l'eccezione al chiamante del tuo metodo.
      void setServerPort(String value) throws NumberFormatException {
          serverPort = Integer.parseInt(value);
      }
    
  • Lancia una nuova eccezione appropriata al tuo livello di astrazione.
      void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
      }
    
  • Gestisci l'errore con garbo e sostituisci un valore appropriato nel blocco 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
        }
      }
    
  • Cattura l'eccezione e genera una nuova istanza di RuntimeException . Questo è pericoloso, quindi fallo solo se sei sicuro che se si verifica questo errore, la cosa appropriata da fare è crash.
      /** 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);
        }
      }
    
  • Come ultima risorsa, se sei sicuro che ignorare l'eccezione sia appropriato, puoi ignorarla, ma devi anche commentare il motivo con una buona ragione.
    /** 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.
        }
    }
    

Non intercettare eccezioni generiche

Si può essere tentati di essere pigri quando si rilevano eccezioni e fare qualcosa del genere:

  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!
  }

Non farlo. In quasi tutti i casi, è opportuno prendere generico Exception o Throwable (preferibilmente non Throwable perché include Error eccezioni). È pericoloso perché significa che le eccezioni che non ti aspettavi (incluse le eccezioni di runtime come ClassCastException ) vengono catturate nella gestione degli errori a livello di app. Nasconde le proprietà di gestione degli errori del codice, il che significa che se qualcuno aggiunge un nuovo tipo di eccezione nel codice che stai chiamando, il compilatore non indicherà che devi gestire l'errore in modo diverso. Nella maggior parte dei casi non dovresti gestire diversi tipi di eccezioni allo stesso modo.

La rara eccezione a questa regola è il codice di test e il codice di primo livello in cui si desidera rilevare tutti i tipi di errori (per impedire che vengano visualizzati in un'interfaccia utente o per mantenere in esecuzione un processo batch). In questi casi, si può prendere generico Exception (o Throwable ) e gestire l'errore in modo appropriato. Pensa attentamente prima di farlo, però, e inserisci commenti che spieghino perché è sicuro in questo contesto.

Alternative alla cattura di eccezioni generiche:

  • Cattura ogni eccezione separatamente come parte di un blocco multi-catch, ad esempio:
    try {
        ...
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        ...
    }
  • Rifattorizza il codice per avere una gestione degli errori più dettagliata, con più blocchi try. Separare l'IO dall'analisi e gestire gli errori separatamente in ogni caso.
  • Ripeti l'eccezione. Molte volte non è comunque necessario catturare l'eccezione a questo livello, lascia che sia il metodo a lanciarla.

Ricorda che le eccezioni sono tue amiche! Quando il compilatore si lamenta che non si sta rilevando un'eccezione, non si acciglia. Sorridi! Il compilatore ha appena reso più facile rilevare i problemi di runtime nel codice.

Non utilizzare finalizzatori

I finalizzatori sono un modo per eseguire una porzione di codice quando un oggetto viene sottoposto a garbage collection. Sebbene i finalizzatori possano essere utili per la pulizia (in particolare delle risorse esterne), non ci sono garanzie su quando verrà chiamato un finalizzatore (o anche se verrà chiamato).

Android non utilizza i finalizzatori. Nella maggior parte dei casi, è possibile utilizzare invece una buona gestione delle eccezioni. Se hai assolutamente bisogno di un finalizzatore, definisci un metodo close() (o simile) e documenta esattamente quando quel metodo deve essere chiamato (vedi InputStream per un esempio). In questo caso, è opportuno, ma non obbligatorio, stampare un breve messaggio di registro dal finalizzatore, a condizione che non si preveda che i registri inondino.

Qualificare pienamente le importazioni

Quando vuoi usare class Bar dal pacchetto foo , ci sono due modi possibili per importarlo:

  • import foo.*;

    Potenzialmente riduce il numero di istruzioni di importazione.

  • import foo.Bar;

    Rende ovvio quali classi vengono utilizzate e il codice è più leggibile per i manutentori.

Usa import foo.Bar; per importare tutto il codice Android. Viene fatta un'eccezione esplicita per le librerie standard Java ( java.util.* , java.io.* , ecc.) E il codice di unit test ( junit.framework.* ).

Regole della libreria Java

Esistono convenzioni per l'utilizzo delle librerie e degli strumenti Java di Android. In alcuni casi, la convenzione è cambiata in modi importanti e il codice precedente potrebbe utilizzare un modello o una libreria obsoleti. Quando si lavora con tale codice, va bene continuare lo stile esistente. Quando si creano nuovi componenti, tuttavia, non utilizzare mai librerie obsolete.

Regole di stile Java

Usa i commenti standard Javadoc

Ogni file dovrebbe avere una dichiarazione di copyright in alto, seguita dalle istruzioni package e import (ogni blocco separato da una riga vuota) e infine la dichiarazione di classe o interfaccia. Nei commenti Javadoc, descrivere cosa fa la classe o l'interfaccia.

/*
 * Copyright 2020 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 {
    ...
}

Ogni classe e metodo pubblico non banale che scrivi deve contenere un commento Javadoc con almeno una frase che descrive cosa fa la classe o il metodo. Questa frase dovrebbe iniziare con un verbo descrittivo in terza persona.

Esempi

/** 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) {
    ...
}

Non è necessario scrivere Javadoc per metodi get e set banali come setFoo() se tutto il tuo Javadoc direbbe "sets Foo". Se il metodo esegue qualcosa di più complesso (come applicare un vincolo o ha un effetto collaterale importante), è necessario documentarlo. Se non è ovvio cosa significa la proprietà "Foo", dovresti documentarlo.

Ogni metodo che scrivi, pubblico o meno, trarrebbe vantaggio da Javadoc. I metodi pubblici fanno parte di un'API e quindi richiedono Javadoc. Android non applica uno stile specifico per scrivere commenti Javadoc, ma dovresti seguire le istruzioni in Come scrivere commenti Doc per lo strumento Javadoc .

Scrivi metodi brevi

Quando possibile, mantieni i metodi piccoli e mirati. Riconosciamo che i metodi lunghi a volte sono appropriati, quindi non viene posto alcun limite alla lunghezza del metodo. Se un metodo supera le 40 righe circa, pensa se può essere scomposto senza danneggiare la struttura del programma.

Definisci i campi in posizioni standard

Definisci i campi all'inizio del file o immediatamente prima dei metodi che li utilizzano.

Limita l'ambito delle variabili

Riduci al minimo l'ambito delle variabili locali. Ciò aumenta la leggibilità e la manutenibilità del codice e riduce la probabilità di errore. Dichiara ogni variabile nel blocco più interno che racchiude tutti gli usi della variabile.

Dichiarare le variabili locali nel punto in cui vengono utilizzate per la prima volta. Quasi ogni dichiarazione di variabile locale dovrebbe contenere un inizializzatore. Se non hai ancora informazioni sufficienti per inizializzare una variabile in modo ragionevole, rimanda la dichiarazione finché non lo fai.

L'eccezione sono le istruzioni try-catch. Se una variabile viene inizializzata con il valore di ritorno di un metodo che genera un'eccezione verificata, deve essere inizializzata all'interno di un blocco try. Se il valore deve essere utilizzato al di fuori del blocco try, deve essere dichiarato prima del blocco try, dove non può ancora essere inizializzato in modo sensato:

// 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));

Tuttavia, puoi anche evitare questo caso incapsulando il blocco try-catch in un metodo:

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));

Dichiarare le variabili di ciclo nell'istruzione for stessa a meno che non ci sia un motivo valido per fare altrimenti:

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

e

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

Ordina dichiarazioni di importazione

L'ordine delle istruzioni di importazione è:

  1. Importazioni Android
  2. Importazioni da terze parti ( com , junit , net , org )
  3. java e javax

Per corrispondere esattamente alle impostazioni IDE, le importazioni dovrebbero essere:

  • Alfabetico all'interno di ogni raggruppamento, con lettere maiuscole prima delle lettere minuscole (ad esempio, Z prima della a)
  • Separato da una riga vuota tra ogni raggruppamento principale ( android , com , junit , net , org , java , javax )

In origine, non c'erano requisiti di stile per l'ordine, il che significa che gli IDE cambiavano sempre l'ordine o gli sviluppatori IDE dovevano disabilitare le funzionalità di gestione dell'importazione automatica e mantenere manualmente le importazioni. Questo è stato ritenuto negativo. Quando è stato chiesto lo stile Java, gli stili preferiti variavano enormemente e si è trattato di Android che doveva semplicemente "scegliere un ordine ed essere coerente". Quindi abbiamo scelto uno stile, aggiornato la guida allo stile e fatto in modo che gli IDE lo rispettassero. Ci aspettiamo che mentre gli utenti IDE lavorano sul codice, le importazioni in tutti i pacchetti corrisponderanno a questo modello senza ulteriori sforzi di progettazione.

Abbiamo scelto questo stile in modo tale che:

  • Le importazioni che le persone vogliono guardare per prime tendono ad essere le prime ( android ).
  • Le importazioni che le persone vogliono almeno guardare tendono ad essere in fondo ( java ).
  • Gli esseri umani possono facilmente seguire lo stile.
  • Gli IDE possono seguire lo stile.

Metti le importazioni statiche sopra tutte le altre importazioni ordinate allo stesso modo delle importazioni regolari.

Usa gli spazi per il rientro

Usiamo quattro (4) rientri di spazio per i blocchi e mai le tabulazioni. In caso di dubbio, sii coerente con il codice circostante.

Usiamo otto (8) rientri di spazio per i wrapping di riga, comprese le chiamate di funzione e gli assegnamenti.

Consigliato

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

Non consigliato

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

Segui le convenzioni di denominazione dei campi

  • I nomi dei campi non pubblici e non statici iniziano con m .
  • I nomi dei campi statici iniziano con s .
  • Altri campi iniziano con una lettera minuscola.
  • I campi finali statici pubblici (costanti) sono ALL_CAPS_WITH_UNDERSCORES .

Per esempio:

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 lo stile tutore standard

Metti le parentesi graffe sulla stessa riga del codice prima di loro, non sulla loro riga:

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

Abbiamo bisogno di parentesi graffe attorno alle dichiarazioni per un condizionale. Eccezione: se l'intero condizionale (la condizione e il corpo) si trova su una riga, puoi (ma non sei obbligato a) mettere tutto su una riga. Ad esempio, questo è accettabile:

if (condition) {
    body();
}

e questo è accettabile:

if (condition) body();

ma questo non è accettabile:

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

Limita la lunghezza della linea

Ogni riga di testo nel codice dovrebbe essere lunga al massimo 100 caratteri. Sebbene molte discussioni abbiano circondato questa regola, resta la decisione che 100 caratteri è il massimo con le seguenti eccezioni :

  • Se una riga di commento contiene un comando di esempio o un URL letterale più lungo di 100 caratteri, quella riga potrebbe essere più lunga di 100 caratteri per facilità di taglia e incolla.
  • Le righe di importazione possono superare il limite perché gli esseri umani le vedono raramente (questo semplifica anche la scrittura degli strumenti).

Usa annotazioni Java standard

Le annotazioni dovrebbero precedere altri modificatori per lo stesso elemento del linguaggio. Semplici annotazioni marker (ad esempio, @Override ) possono essere elencate sulla stessa riga con l'elemento language. Se sono presenti più annotazioni o annotazioni parametrizzate, elencale una per riga in ordine alfabetico.

Le pratiche standard di Android per le tre annotazioni predefinite in Java sono:

  • Utilizzare l'annotazione @Deprecated ogni volta che è sconsigliato l'uso dell'elemento annotato. Se si utilizza il @Deprecated annotazione, è necessario anche avere un @deprecated tag Javadoc e dovrebbe nominare un'implementazione alternativa. Inoltre, ricorda che un metodo @Deprecated dovrebbe ancora funzionare . Se si vede vecchio codice che ha un @deprecated tag Javadoc, aggiungere il @Deprecated annotazione.
  • Usa l'annotazione @Override ogni volta che un metodo sovrascrive la dichiarazione o l'implementazione di una superclasse. Ad esempio, se si utilizza il tag Javadoc @inheritdocs e si deriva da una classe (non un'interfaccia), è necessario anche annotare che il metodo sostituisce il metodo della classe genitore.
  • Utilizza l'annotazione @SuppressWarnings solo in circostanze in cui è impossibile eliminare un avviso. Se un avviso supera questo test "impossibile da eliminare", è necessario utilizzare l'annotazione @SuppressWarnings , per garantire che tutti gli avvisi riflettano problemi effettivi nel codice.

    Quando è necessaria un'annotazione @SuppressWarnings , deve essere preceduta da un commento TODO che spieghi la condizione "impossibile eliminare". Questo normalmente identifica una classe offensiva che ha un'interfaccia scomoda. Per esempio:

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

    Quando è richiesta un'annotazione @SuppressWarnings , refactoring del codice per isolare gli elementi software in cui si applica l'annotazione.

Considera gli acronimi come parole

Considera gli acronimi e le abbreviazioni come parole nella denominazione di variabili, metodi e classi per rendere i nomi più leggibili:

Buona Male
XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
class Html classe HTML
URL stringa URL stringa
lungo id ID lungo

Poiché sia ​​il codice JDK che quello Android non sono coerenti con gli acronimi, è praticamente impossibile essere coerenti con il codice circostante. Pertanto, considera sempre gli acronimi come parole.

Usa i commenti TODO

Utilizzare i commenti TODO per il codice temporaneo, una soluzione a breve termine o abbastanza buono ma non perfetto. Questi commenti dovrebbero includere la stringa TODO in tutto maiuscolo, seguita da due punti:

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

e

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

Se il tuo TODO la forma "In una data futura fai qualcosa" assicurati di includere una data specifica ("Correggi entro novembre 2005") o un evento specifico ("Rimuovi questo codice dopo che tutti i mixer di produzione hanno compreso il protocollo V7." ).

Accedi con parsimonia

Sebbene la registrazione sia necessaria, ha un impatto negativo sulle prestazioni e perde la sua utilità se non mantenuta ragionevolmente concisa. Le strutture di registrazione forniscono cinque diversi livelli di registrazione:

  • ERROR : utilizzare quando è accaduto qualcosa di fatale, ovvero qualcosa avrà conseguenze visibili dall'utente e non sarà recuperabile senza eliminare alcuni dati, disinstallare app, cancellare le partizioni di dati o eseguire il reflash dell'intero dispositivo (o peggio). Questo livello viene sempre registrato. I problemi che giustificano alcune registrazioni a livello di ERROR sono buoni candidati da segnalare a un server di raccolta delle statistiche.
  • WARNING : utilizzare quando si è verificato qualcosa di grave e inaspettato, ovvero qualcosa che avrà conseguenze visibili dall'utente ma che è probabile che sia recuperabile senza perdita di dati eseguendo un'azione esplicita, dall'attesa o dal riavvio di un'app fino al nuovo download una nuova versione di un'app o riavviando il dispositivo. Questo livello viene sempre registrato. I problemi che giustificano la registrazione a livello di WARNING potrebbero essere presi in considerazione anche per la segnalazione a un server di raccolta delle statistiche.
  • INFORMATIVE : utilizzare per notare che è accaduto qualcosa di interessante, ovvero quando viene rilevata una situazione che potrebbe avere un impatto diffuso, sebbene non sia necessariamente un errore. Tale condizione dovrebbe essere registrata solo da un modulo che ritiene di essere il più autorevole in quel dominio (per evitare la registrazione duplicata da parte di componenti non autorevoli). Questo livello viene sempre registrato.
  • DEBUG : utilizzare per annotare ulteriormente ciò che sta accadendo sul dispositivo che potrebbe essere rilevante per indagare ed eseguire il debug di comportamenti imprevisti. Registra solo ciò che è necessario per raccogliere informazioni sufficienti su ciò che sta accadendo con il tuo componente. Se i registri di debug dominano il registro, è necessario utilizzare la registrazione dettagliata.

    Questo livello viene registrato anche nelle build di rilascio ed è necessario che sia circondato da un if (LOCAL_LOG) o if LOCAL_LOGD) , dove LOCAL_LOG[D] è definito nella classe o nel sottocomponente, in modo che ci sia la possibilità di disabilitare tutte queste registrazioni . Pertanto, non deve esserci logica attiva in un blocco if (LOCAL_LOG) . Anche tutta la creazione di stringhe per il log deve essere inserita nel blocco if (LOCAL_LOG) . Non effettuare il refactoring della chiamata di log in una chiamata al metodo se farà sì che la creazione di stringhe avvenga al di fuori del blocco if (LOCAL_LOG) .

    C'è del codice che dice ancora if (localLOGV) . Anche questo è considerato accettabile, sebbene il nome non sia standard.

  • VERBOSE : Usa per tutto il resto. Questo livello viene registrato solo nelle build di debug e dovrebbe essere circondato da un blocco if (LOCAL_LOGV) (o equivalente) in modo che possa essere compilato per impostazione predefinita. Qualsiasi costruzione di stringhe viene rimossa dalle build di rilascio e deve apparire all'interno del blocco if (LOCAL_LOGV) .

Appunti

  • All'interno di un dato modulo, diverso dal livello VERBOSE , un errore dovrebbe essere segnalato solo una volta, se possibile. All'interno di una singola catena di chiamate di funzione all'interno di un modulo, solo la funzione più interna dovrebbe restituire l'errore e i chiamanti nello stesso modulo dovrebbero aggiungere solo un po 'di registrazione se ciò aiuta in modo significativo a isolare il problema.
  • In una catena di moduli, diversa dal livello VERBOSE , quando un modulo di livello inferiore rileva dati non validi provenienti da un modulo di livello superiore, il modulo di livello inferiore dovrebbe registrare questa situazione solo nel registro DEBUG e solo se la registrazione fornisce informazioni che non sono altrimenti disponibili per il chiamante. In particolare, non è necessario registrare le situazioni in cui viene generata un'eccezione (l'eccezione deve contenere tutte le informazioni pertinenti) o in cui le uniche informazioni registrate sono contenute in un codice di errore. Ciò è particolarmente importante nell'interazione tra il framework e le app e le condizioni causate da app di terze parti gestite correttamente dal framework non dovrebbero attivare la registrazione superiore al livello DEBUG . Le uniche situazioni che dovrebbero attivare la registrazione a livello INFORMATIVE o superiore sono quando un modulo o un'app rileva un errore al proprio livello o proveniente da un livello inferiore.
  • Quando è probabile che una condizione che normalmente giustifichi alcune registrazioni si verifichi molte volte, può essere una buona idea implementare un meccanismo di limitazione della velocità per impedire il trabocco dei registri con molte copie duplicate delle stesse informazioni (o molto simili).
  • Le perdite di connettività di rete sono considerate comuni e sono completamente previste e non dovrebbero essere registrate gratuitamente. Una perdita di connettività di rete che ha conseguenze all'interno di un'app dovrebbe essere registrata a livello DEBUG o VERBOSE (a seconda che le conseguenze siano abbastanza gravi e abbastanza inaspettate da essere registrate in una build di rilascio).
  • Avere un file system completo su un file system accessibile ao per conto di app di terze parti non dovrebbe essere registrato a un livello superiore a INFORMATIVO.
  • I dati non validi provenienti da qualsiasi fonte non attendibile (incluso qualsiasi file sullo storage condiviso o dati che provengono da una connessione di rete) sono considerati previsti e non dovrebbero attivare alcuna registrazione a un livello superiore a DEBUG quando viene rilevato come non valido (e anche allora la registrazione dovrebbe essere il più limitato possibile).
  • Quando viene utilizzato su oggetti String , l'operatore + crea implicitamente un'istanza StringBuilder con la dimensione del buffer predefinita (16 caratteri) e potenzialmente altri oggetti String temporanei. Quindi la creazione esplicita di oggetti StringBuilder non è più costosa che affidarsi all'operatore + predefinito (e può essere molto più efficiente). Tieni presente che il codice che chiama Log.v() viene compilato ed eseguito nelle build di rilascio, inclusa la creazione delle stringhe, anche se i log non vengono letti.
  • Qualsiasi registrazione destinata a essere letta da altre persone e disponibile nelle build di rilascio dovrebbe essere concisa senza essere criptica e dovrebbe essere comprensibile. Ciò include tutte le registrazioni fino al livello DEBUG .
  • Quando possibile, continua ad accedere su una singola riga. Sono accettabili lunghezze di riga fino a 80 o 100 caratteri. Se possibile, evita lunghezze superiori a circa 130 o 160 caratteri (inclusa la lunghezza del tag).
  • Se la registrazione ha VERBOSE , non utilizzarla mai a livelli superiori a VERBOSE .
  • Se stai utilizzando la registrazione temporanea per diagnosticare un problema difficile da riprodurre, tienilo a livello DEBUG o VERBOSE e racchiudilo con blocchi if che consentono di disabilitarlo in fase di compilazione.
  • Fai attenzione alle falle di sicurezza attraverso il registro. Evita di registrare informazioni private. In particolare, evitare di registrare le informazioni sui contenuti protetti. Ciò è particolarmente importante quando si scrive codice framework in quanto non è facile sapere in anticipo cosa saranno e cosa non saranno informazioni private o contenuto protetto.
  • Non utilizzare mai System.out.println() (o printf() per il codice nativo). System.out e System.err vengono reindirizzati a /dev/null , quindi le tue istruzioni di stampa non hanno effetti visibili. Tuttavia, tutta la creazione di stringhe che avviene per queste chiamate viene comunque eseguita.
  • La regola d'oro della registrazione è che i tuoi log non possono spingere inutilmente altri log fuori dal buffer, proprio come altri potrebbero non spingere fuori i tuoi.

Regole di stile di Javatest

Segui le convenzioni di denominazione dei metodi di test e utilizza un trattino basso per separare ciò che viene testato dal caso specifico in fase di test. Questo stile rende più facile vedere quali casi vengono testati. Per esempio:

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))
}