Die Code Styles auf dieser Seite sind strenge Regeln für das Einbringen von Java Code in das Android Open Source Project (AOSP). Beiträge zur Android-Plattform, die sich nicht an diese Regeln halten, werden in der Regel nicht akzeptiert. Wir sind uns bewusst, dass nicht jeder bestehende Code diesen Regeln folgt, aber wir erwarten, dass jeder neue Code diesen Regeln entspricht. Beispiele für zu verwendende und zu vermeidende Terminologie für ein inklusiveres Ökosystem finden Sie unter Coding with Respect.
- Bleiben Sie konsistent
- Regeln der Java-Sprache
- Keine Ausnahmen ignorieren
- Fangen Sie keine allgemeinen Ausnahmen ab
- Verwenden Sie keine Finalizer
- Fully qualify imports
- Regeln für Java-Bibliotheken
- Java-Stilregeln
- Schreiben Sie kurze Methoden
- Felder an den üblichen Stellen definieren
- Beschränken Sie den Umfang von Variablen
- Order import statements
- Use spaces for indentation
- Follow field naming conventions
- Use standard brace style
- Limit line length
- Verwenden Sie Standard-Java-Annotationen
- Treat acronyms as words
- Protokollieren Sie sparsam
- Hinweise
- Stilregeln für Java-Tests
Bleiben Sie konsistent
Eine der einfachsten Regeln lautet: Bleiben Sie konsistent. Wenn Sie Code bearbeiten, nehmen Sie sich ein paar Minuten Zeit, um sich den umgebenden Code anzusehen und seinen Stil zu bestimmen. Wenn dieser Code Leerzeichen um die if
-Klauseln verwendet, sollten Sie das auch tun. Wenn die Code-Kommentare kleine Kästchen mit Sternen haben, sollten auch Ihre Kommentare kleine Kästchen mit Sternen haben.
Der Sinn von Stilrichtlinien ist es, ein gemeinsames Vokabular für die Codierung zu haben, damit sich die Leser auf das konzentrieren können, was Sie sagen, und nicht darauf, wie Sie es sagen. Wir stellen hier globale Stilregeln vor, damit Sie das Vokabular kennen, aber auch der lokale Stil ist wichtig. Wenn sich der Code, den Sie einer Datei hinzufügen, drastisch von dem bereits vorhandenen Code unterscheidet, kommt der Leser beim Lesen aus dem Rhythmus. Versuchen Sie, dies zu vermeiden.
Regeln der Java-Sprache
Android folgt den Standard-Java-Codierungskonventionen mit den unten beschriebenen zusätzlichen Regeln.
Keine Ausnahmen ignorieren
Es kann verlockend sein, Code zu schreiben, der eine Ausnahme ignoriert, wie zum Beispiel:
void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { } }
Tun Sie das nicht. Auch wenn Sie denken, dass Ihr Code nie auf diese Fehlerbedingung stoßen wird oder dass es nicht wichtig ist, sie zu behandeln, schafft das Ignorieren dieser Art von Ausnahme Minen in Ihrem Code, die eines Tages von jemand anderem ausgelöst werden können. Sie müssen jede Ausnahme in Ihrem Code auf eine prinzipielle Art und Weise behandeln; die spezifische Behandlung variiert je nach Fall.
„Jedes Mal, wenn jemand eine leere catch-Klausel hat, sollte er ein mulmiges Gefühl haben. Es gibt definitiv Zeiten, in denen es tatsächlich das Richtige ist, aber man muss zumindest darüber nachdenken. In Java kann man dem unheimlichen Gefühl nicht entkommen.“ – James Gosling
Annehmbare Alternativen (in der Reihenfolge ihrer Präferenz) sind:
- Werfen Sie die Ausnahme bis zum Aufrufer Ihrer Methode.
void setServerPort(String value) throws NumberFormatException { serverPort = Integer.parseInt(value); }
- Werfen Sie eine neue Ausnahme, die Ihrer Abstraktionsebene angemessen ist.
void setServerPort(String value) throws ConfigurationException { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { throw new ConfigurationException("Port " + value + " is not valid."); } }
- Behandeln Sie den Fehler anständig und ersetzen Sie einen geeigneten Wert im
catch {}
-Block./** 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 } }
- Fangen Sie die Ausnahme ab und werfen Sie eine neue Instanz von
RuntimeException
. Dies ist gefährlich, also tun Sie es nur, wenn Sie sicher sind, dass es angemessen ist, bei Auftreten dieses Fehlers abzustürzen./** 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); } }
- Als letzten Ausweg können Sie die Ausnahme ignorieren, wenn Sie sicher sind, dass es angemessen ist, sie zu ignorieren, aber Sie müssen auch einen guten Grund dafür angeben.
/** 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. }}
Fangen Sie keine allgemeinen Ausnahmen ab
Es kann verlockend sein, beim Abfangen von Ausnahmen faul zu sein und etwas wie das Folgende zu tun:
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! }
Tun Sie das nicht. In fast allen Fällen ist es unangebracht, generische Exception
oder Throwable
abzufangen (vorzugsweise nicht Throwable
, weil es Error
Ausnahmen enthält). Es ist gefährlich, weil es bedeutet, dass Ausnahmen, die Sie nie erwartet haben (einschließlich Laufzeitausnahmen wie ClassCastException
), in der Fehlerbehandlung auf Anwendungsebene abgefangen werden. Es verschleiert die Fehlerbehandlungseigenschaften Ihres Codes, d.h. wenn jemand eine neue Art von Ausnahme in den von Ihnen aufgerufenen Code einfügt, wird der Compiler nicht darauf hinweisen, dass Sie den Fehler anders behandeln müssen. In den meisten Fällen sollten Sie verschiedene Arten von Ausnahmen nicht auf dieselbe Weise behandeln.
Die seltene Ausnahme von dieser Regel ist Testcode und Top-Level-Code, bei dem Sie alle Arten von Fehlern abfangen wollen (um zu verhindern, dass sie in einer Benutzeroberfläche angezeigt werden, oder um einen Batch-Job am Laufen zu halten). In diesen Fällen können Sie ein generisches Exception
(oder Throwable
) abfangen und den Fehler entsprechend behandeln. Denken Sie jedoch sorgfältig darüber nach, bevor Sie dies tun, und fügen Sie Kommentare ein, die erklären, warum es in diesem Zusammenhang sicher ist.
Alternativen zum Abfangen allgemeiner Ausnahmen:
- Fangen Sie jede Ausnahme separat als Teil eines Multi-Catch-Blocks ab, zum Beispiel:
try { ...} catch (ClassNotFoundException | NoSuchMethodException e) { ...}
- Refactor your code to have more fine-grained error handling, with multiple try blocks. Trennen Sie das IO vom Parsing und behandeln Sie Fehler in jedem Fall separat.
- Werfen Sie die Ausnahme zurück. In vielen Fällen brauchen Sie die Ausnahme auf dieser Ebene ohnehin nicht abzufangen, lassen Sie sie einfach von der Methode auslösen.
Denken Sie daran, dass Ausnahmen Ihr Freund sind! Wenn der Compiler sich darüber beschwert, dass Sie eine Ausnahme nicht abfangen, sollten Sie nicht die Stirn runzeln. Lächle! Der Compiler hat es Ihnen gerade leichter gemacht, Laufzeitprobleme in Ihrem Code zu erkennen.
Verwenden Sie keine Finalizer
Finalizer sind eine Möglichkeit, einen Teil des Codes auszuführen, wenn ein Objekt in den Müll geworfen wird. Während Finalizer für Aufräumarbeiten (insbesondere von externen Ressourcen) praktisch sein können, gibt es keine Garantien dafür, wann ein Finalizer aufgerufen wird (oder sogar, dass er überhaupt aufgerufen wird).
Android verwendet keine Finalizer. In den meisten Fällen können Sie stattdessen eine gute Ausnahmebehandlung verwenden. If you absolutely need a finalizer, define a close()
method (or the like) and document exactly when that method needs to be called (see InputStream for an example). In this case, it’s appropriate but not required to print a short log message from the finalizer, as long as it’s not expected to flood the logs.
Fully qualify imports
When you want to use class Bar
from package foo
, there are two possible ways to import it:
-
import foo.*;
Potentially reduces the number of import statements.
-
import foo.Bar;
Makes it obvious what classes are used and the code is more readable for maintainers.
Use import foo.Bar;
for importing all Android code. An explicit exception is made for Java standard libraries (java.util.*
java.io.*
, etc.) and unit test code (junit.framework.*
).
Regeln für Java-Bibliotheken
Es gibt Konventionen für die Verwendung der Java-Bibliotheken und -Tools von Android. In einigen Fällen hat sich die Konvention in wichtigen Punkten geändert und älterer Code könnte ein veraltetes Muster oder eine veraltete Bibliothek verwenden. Wenn Sie mit solchem Code arbeiten, ist es in Ordnung, den bestehenden Stil beizubehalten. Bei der Erstellung neuer Komponenten sollten Sie jedoch niemals veraltete Bibliotheken verwenden.
Java-Stilregeln
Jede Datei sollte eine Copyright-Erklärung am Anfang haben, gefolgt von Package- und Import-Anweisungen (jeder Block durch eine Leerzeile getrennt) und schließlich die Klassen- oder Schnittstellen-Deklaration. In den Javadoc-Kommentaren ist zu beschreiben, was die Klasse oder Schnittstelle tut.
/* * 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 { ...}
Jede Klasse und jede nicht triviale öffentliche Methode, die Sie schreiben, muss einen Javadoc-Kommentar mit mindestens einem Satz enthalten, der beschreibt, was die Klasse oder Methode tut. Dieser Satz sollte mit einem beschreibenden Verb der dritten Person beginnen.
Beispiele
/** Returns the correctly rounded positive square root of a double value. */static double sqrt(double a) { ...}
oder
/** * Constructs a new String by converting the specified array of * bytes using the platform's default character encoding. */public String(byte bytes) { ...}
Für triviale get- und set-Methoden wie setFoo()
muss kein Javadoc geschrieben werden, wenn im Javadoc nur steht „setzt Foo“. Wenn die Methode etwas Komplexeres tut (z.B. eine Einschränkung erzwingen oder einen wichtigen Nebeneffekt haben), dann müssen Sie es dokumentieren. Wenn es nicht offensichtlich ist, was die Eigenschaft „Foo“ bedeutet, sollten Sie es dokumentieren.
Jede Methode, die Sie schreiben, ob öffentlich oder nicht, würde von Javadoc profitieren. Öffentliche Methoden sind Teil einer API und erfordern daher Javadoc. Android schreibt keinen bestimmten Stil für das Schreiben von Javadoc-Kommentaren vor, aber Sie sollten die Anweisungen in How to Write Doc Comments for the Javadoc Tool befolgen.
Schreiben Sie kurze Methoden
Wenn machbar, halten Sie die Methoden klein und konzentriert. Wir sind uns darüber im Klaren, dass lange Methoden manchmal angebracht sind, daher gibt es keine harte Grenze für die Methodenlänge. Wenn eine Methode länger als 40 Zeilen ist, sollte man überlegen, ob sie nicht aufgelöst werden kann, ohne die Struktur des Programms zu beeinträchtigen.
Felder an den üblichen Stellen definieren
Felder werden entweder am Anfang der Datei oder unmittelbar vor den Methoden, die sie verwenden, definiert.
Beschränken Sie den Umfang von Variablen
Beschränken Sie den Umfang von lokalen Variablen auf ein Minimum. Das erhöht die Lesbarkeit und Wartbarkeit Ihres Codes und verringert die Fehlerwahrscheinlichkeit. Deklarieren Sie jede Variable in dem innersten Block, der alle Verwendungen der Variable einschließt.
Deklarieren Sie lokale Variablen an der Stelle, an der sie zum ersten Mal verwendet werden. Nahezu jede Deklaration einer lokalen Variable sollte einen Initialisierer enthalten. Wenn Sie noch nicht genug Informationen haben, um eine Variable sinnvoll zu initialisieren, verschieben Sie die Deklaration, bis Sie sie haben.
Die Ausnahme sind try-catch-Anweisungen. Wenn eine Variable mit dem Rückgabewert einer Methode initialisiert wird, die eine geprüfte Ausnahme auslöst, muss sie innerhalb eines Try-Blocks initialisiert werden. If the value must be used outside of the try block, then it must be declared before the try block, where it can’t yet be sensibly initialized:
// Instantiate class cl, which represents some sort of SetSet 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 sets.addAll(Arrays.asList(args));
However, you can even avoid this case by encapsulating the try-catch block in a method:
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 setSet s = createSet(cl);s.addAll(Arrays.asList(args));
Declare loop variables in the for statement itself unless there’s a compelling reason to do otherwise:
for (int i = 0; i < n; i++) { doSomething(i);}
and
for (Iterator i = c.iterator(); i.hasNext(); ) { doSomethingElse(i.next());}
Order import statements
The ordering of import statements is:
- Android imports
- Imports from third parties (
com
junit
net
org
) -
java
andjavax
To exactly match the IDE settings, the imports should be:
- Alphabetisch innerhalb jeder Gruppierung, mit Großbuchstaben vor Kleinbuchstaben (zum Beispiel Z vor a)
- Getrennt durch eine Leerzeile zwischen jeder Hauptgruppierung (
android
com
junit
net
org
java
javax
)
Ursprünglich gab es keine Stilvorgaben für die Reihenfolge, was bedeutete, dass die IDEs entweder die Reihenfolge ständig änderten oder die IDE-Entwickler die automatischen Importverwaltungsfunktionen deaktivieren und die Importe manuell pflegen mussten. Dies wurde als schlecht angesehen. Als die Frage nach dem Java-Stil gestellt wurde, variierten die bevorzugten Stile stark und es lief darauf hinaus, dass Android einfach „eine Reihenfolge wählen und konsistent sein“ sollte. Also haben wir uns für einen Stil entschieden, den Styleguide aktualisiert und die IDEs dazu gebracht, ihn zu befolgen. Wir erwarten, dass die IDE-Benutzer bei der Arbeit am Code die Importe in allen Paketen ohne zusätzlichen technischen Aufwand an dieses Muster anpassen werden.
We chose this style such that:
- The imports that people want to look at first tend to be at the top (
android
). - The imports that people want to look at least tend to be at the bottom (
java
). - Humans can easily follow the style.
- IDEs can follow the style.
Put static imports above all the other imports ordered the same way as regular imports.
Use spaces for indentation
We use four (4) space indents for blocks and never tabs. When in doubt, be consistent with the surrounding code.
We use eight (8) space indents for line wraps, including function calls and assignments.
Recommended
Instrument i = someLongExpression(that, wouldNotFit, on, one, line);
Not recommended
Instrument i = someLongExpression(that, wouldNotFit, on, one, line);
Follow field naming conventions
- Non-public, non-static field names start with
m
. - Static field names start with
s
. - Other fields start with a lower case letter.
- Public static final fields (constants) are
ALL_CAPS_WITH_UNDERSCORES
.
For example:
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;}
Use standard brace style
Put braces on the same line as the code before them, not on their own line:
class MyClass { int func() { if (something) { // ... } else if (somethingElse) { // ... } else { // ... } }}
We require braces around the statements for a conditional. Exception: If the entire conditional (the condition and the body) fit on one line, you may (but are not obligated to) put it all on one line. For example, this is acceptable:
if (condition) { body();}
and this is acceptable:
if (condition) body();
but this is not acceptable:
if (condition) body(); // bad!
Limit line length
Each line of text in your code should be at most 100 characters long. While much discussion has surrounded this rule, the decision remains that 100 characters is the maximum with the following exceptions:
- Wenn eine Kommentarzeile einen Beispielbefehl oder eine wörtliche URL enthält, die länger als 100 Zeichen ist, kann diese Zeile länger als 100 Zeichen sein, um das Ausschneiden und Einfügen zu erleichtern.
- Importzeilen können über das Limit hinausgehen, weil Menschen sie selten sehen (dies vereinfacht auch das Schreiben von Tools).
Verwenden Sie Standard-Java-Annotationen
Annotationen sollten anderen Modifikatoren für dasselbe Sprachelement vorangestellt werden. Einfache Marker-Annotationen (z.B. @Override
) können in der gleichen Zeile wie das Sprachelement aufgeführt werden. Wenn es mehrere Anmerkungen oder parametrisierte Anmerkungen gibt, werden sie pro Zeile in alphabetischer Reihenfolge aufgeführt.
Die Android-Standardpraktiken für die drei vordefinierten Annotationen in Java sind:
- Verwenden Sie die
@Deprecated
-Annotation, wenn von der Verwendung des annotierten Elements abgeraten wird. Wenn Sie die@Deprecated
-Annotation verwenden, müssen Sie auch ein@deprecated
-Javadoc-Tag haben, und dieses sollte eine alternative Implementierung nennen. Denken Sie außerdem daran, dass eine@Deprecated
-Methode immer noch funktionieren soll. Wenn Sie alten Code sehen, der ein@deprecated
Javadoc-Tag hat, fügen Sie die@Deprecated
-Anmerkung hinzu. - Verwenden Sie die
@Override
-Anmerkung immer dann, wenn eine Methode die Deklaration oder Implementierung einer Oberklasse überschreibt. Wenn Sie zum Beispiel das@inheritdocs
Javadoc-Tag verwenden und von einer Klasse (nicht von einer Schnittstelle) ableiten, müssen Sie auch vermerken, dass die Methode die Methode der Elternklasse überschreibt. - Verwenden Sie die
@SuppressWarnings
-Anmerkung nur in Fällen, in denen es unmöglich ist, eine Warnung zu vermeiden. If a warning passes this „impossible to eliminate“ test, the@SuppressWarnings
annotation must be used, to ensure that all warnings reflect actual problems in the code.When a
@SuppressWarnings
annotation is necessary, it must be prefixed with aTODO
comment that explains the „impossible to eliminate“ condition. This normally identifies an offending class that has an awkward interface. Ein Beispiel:// TODO: The third-party class com.third.useful.Utility.rotate() needs generics@SuppressWarnings("generic-cast")List<String> blix = Utility.rotate(blax);
When a
@SuppressWarnings
annotation is required, refactor the code to isolate the software elements where the annotation applies.
Treat acronyms as words
Treat acronyms and abbreviations as words in naming variables, methods, and classes to make names more readable:
Good | Bad |
---|---|
XmlHttpRequest | XMLHTTPRequest |
getCustomerId | getCustomerID |
class Html | class HTML |
String url | String URL |
long id | long ID |
As both the JDK and the Android code bases are inconsistent around acronyms, it’s virtually impossible to be consistent with the surrounding code. Therefore, always treat acronyms as words.
Use TODO
comments for code that is temporary, a short-term solution, or good enough but not perfect. These comments should include the string TODO
in all caps, followed by a colon:
// TODO: Remove this code after the UrlTable2 has been checked in.
und
// TODO: Change this to use a flag instead of a constant.
Wenn Ihr TODO
von der Form „Zu einem späteren Zeitpunkt etwas tun“ ist, stellen Sie sicher, dass Sie entweder ein bestimmtes Datum („Beheben Sie das Problem bis November 2005“) oder ein bestimmtes Ereignis („Entfernen Sie diesen Code, sobald alle Produktionsmischer das Protokoll V7 verstehen.“) angeben.
Protokollieren Sie sparsam
Die Protokollierung ist zwar notwendig, wirkt sich aber negativ auf die Leistung aus und verliert ihren Nutzen, wenn sie nicht einigermaßen knapp gehalten wird. Die Logging-Einrichtungen bieten fünf verschiedene Stufen des Loggings:
-
ERROR
: Wird verwendet, wenn etwas Fatales passiert ist, d. h. etwas, das für den Benutzer sichtbare Folgen hat und nicht wiederhergestellt werden kann, ohne dass Daten gelöscht, Anwendungen deinstalliert, die Datenpartitionen gelöscht oder das gesamte Gerät neu geflasht werden muss (oder Schlimmeres). Diese Stufe wird immer protokolliert. Probleme, die eine Protokollierung auf derERROR
-Ebene rechtfertigen, sind gute Kandidaten für eine Meldung an einen Server, der Statistiken sammelt. -
WARNING
: Wird verwendet, wenn etwas Schwerwiegendes und Unerwartetes passiert ist, d. h. etwas, das für den Benutzer sichtbare Folgen hat, aber wahrscheinlich ohne Datenverlust wiederhergestellt werden kann, indem eine explizite Aktion durchgeführt wird, die vom Warten oder Neustart einer App bis hin zum erneuten Herunterladen einer neuen Version einer App oder dem Neustart des Geräts reicht. Diese Stufe wird immer protokolliert. Probleme, die eine Protokollierung auf derWARNING
-Ebene rechtfertigen, können auch für eine Meldung an einen Statistikserver in Betracht gezogen werden. -
INFORMATIVE
: Wird verwendet, um zu vermerken, dass etwas Interessantes passiert ist, d.h. wenn eine Situation erkannt wird, die wahrscheinlich weitreichende Auswirkungen hat, aber nicht unbedingt ein Fehler ist. Ein solcher Zustand sollte nur von einem Modul protokolliert werden, das glaubt, das maßgebliche in diesem Bereich zu sein (um eine doppelte Protokollierung durch nicht maßgebliche Komponenten zu vermeiden). Diese Stufe wird immer protokolliert. -
DEBUG
: Verwenden Sie diese Ebene, um zu notieren, was auf dem Gerät passiert und was für die Untersuchung und Fehlersuche bei unerwartetem Verhalten relevant sein könnte. Protokollieren Sie nur das, was nötig ist, um genügend Informationen über die Vorgänge in Ihrer Komponente zu sammeln. Wenn Ihre Debug-Protokolle das Protokoll dominieren, dann sollten Sie die ausführliche Protokollierung verwenden.Diese Stufe wird auch bei Release-Builds protokolliert und muss von einem
if (LOCAL_LOG)
– oderif LOCAL_LOGD)
-Block umgeben sein, wobeiLOCAL_LOG
in Ihrer Klasse oder Unterkomponente definiert ist, so dass es eine Möglichkeit gibt, diese Art der Protokollierung zu deaktivieren. Daher darf in einemif (LOCAL_LOG)
-Block keine aktive Logik vorhanden sein. Der gesamte Aufbau der Zeichenkette für das Protokoll muss ebenfalls innerhalb desif (LOCAL_LOG)
-Blocks platziert werden. Der Log-Aufruf sollte nicht in einen Methodenaufruf umgewandelt werden, wenn dadurch der Aufbau der Zeichenkette außerhalb desif (LOCAL_LOG)
-Blocks stattfinden würde.Es gibt einen Code, der immer noch
if (localLOGV)
sagt. Dies wird ebenfalls als akzeptabel angesehen, obwohl der Name nicht dem Standard entspricht. -
VERBOSE
: Für alles andere verwenden. Diese Ebene wird nur bei Debug-Builds protokolliert und sollte von einemif (LOCAL_LOGV)
-Block (oder gleichwertig) umgeben sein, damit sie standardmäßig herauskompiliert werden kann. Jegliche String-Erstellung wird aus den Release-Builds entfernt und muss innerhalb desif (LOCAL_LOGV)
Blocks erscheinen.
Hinweise
- Innerhalb eines Moduls, außer auf der
VERBOSE
Ebene, sollte ein Fehler nur einmal gemeldet werden, wenn möglich. Innerhalb einer einzelnen Kette von Funktionsaufrufen innerhalb eines Moduls sollte nur die innerste Funktion den Fehler zurückgeben, und Aufrufer im selben Modul sollten nur dann eine Protokollierung hinzufügen, wenn dies wesentlich dazu beiträgt, das Problem einzugrenzen. - In einer Kette von Modulen, außer auf der
VERBOSE
Ebene, wenn ein untergeordnetes Modul ungültige Daten entdeckt, die von einem übergeordneten Modul kommen, sollte das untergeordnete Modul diese Situation nur imDEBUG
Log protokollieren, und nur, wenn die Protokollierung Informationen liefert, die dem Aufrufer sonst nicht zur Verfügung stehen. Insbesondere besteht keine Notwendigkeit, Situationen zu protokollieren, in denen eine Ausnahme ausgelöst wird (die Ausnahme sollte alle relevanten Informationen enthalten), oder in denen die einzige protokollierte Information in einem Fehlercode enthalten ist. Dies ist besonders wichtig bei der Interaktion zwischen dem Framework und den Anwendungen, und von Drittanbieteranwendungen verursachte Bedingungen, die vom Framework ordnungsgemäß gehandhabt werden, sollten keine höhere Protokollierung als dieDEBUG
-Ebene auslösen. Die einzigen Situationen, die eine Protokollierung auf derINFORMATIVE
-Ebene oder höher auslösen sollten, ist, wenn ein Modul oder eine Anwendung einen Fehler auf seiner eigenen Ebene oder von einer niedrigeren Ebene aus entdeckt. - Wenn eine Bedingung, die normalerweise eine Protokollierung rechtfertigen würde, wahrscheinlich viele Male auftritt, kann es eine gute Idee sein, einen Mechanismus zur Ratenbegrenzung zu implementieren, um zu verhindern, dass die Protokolle mit vielen doppelten Kopien der gleichen (oder sehr ähnlichen) Informationen überfüllt werden.
- Verluste der Netzverbindung werden als normal angesehen und sind durchaus zu erwarten, sollten aber nicht grundlos protokolliert werden. Ein Verlust der Netzwerkverbindung, der Konsequenzen innerhalb einer Anwendung hat, sollte auf der
DEBUG
oderVERBOSE
Ebene protokolliert werden (je nachdem, ob die Konsequenzen ernst genug und unerwartet genug sind, um in einem Release-Build protokolliert zu werden). - Ein vollständiges Dateisystem auf einem Dateisystem zu haben, das für oder im Namen von Anwendungen von Drittanbietern zugänglich ist, sollte nicht auf einem höheren Level als INFORMATIV protokolliert werden.
- Ungültige Daten, die von einer nicht vertrauenswürdigen Quelle stammen (einschließlich Dateien auf gemeinsam genutztem Speicher oder Daten, die über eine Netzwerkverbindung kommen), werden als erwartet angesehen und sollten keine Protokollierung auf einer höheren Ebene als
DEBUG
auslösen, wenn sie als ungültig erkannt werden (und selbst dann sollte die Protokollierung so begrenzt wie möglich sein). - Bei Verwendung auf
String
-Objekten erzeugt der+
-Operator implizit eineStringBuilder
-Instanz mit der Standard-Puffergröße (16 Zeichen) und möglicherweise anderen temporärenString
-Objekten. Das explizite Erstellen vonStringBuilder
-Objekten ist also nicht teurer als das Verlassen auf den Standardoperator+
(und kann sehr viel effizienter sein). Denken Sie daran, dass Code, derLog.v()
aufruft, kompiliert und bei Release-Builds ausgeführt wird, einschließlich der Erstellung der Strings, auch wenn die Logs nicht gelesen werden. - Jede Protokollierung, die von anderen Leuten gelesen werden soll und in Release-Builds verfügbar sein soll, sollte knapp, aber nicht kryptisch und verständlich sein. Dies schließt alle Protokolle bis zur
DEBUG
Ebene ein. - Wenn möglich, sollte die Protokollierung in einer einzigen Zeile stehen. Zeilenlängen bis zu 80 oder 100 Zeichen sind akzeptabel. Vermeiden Sie nach Möglichkeit Zeilenlängen von mehr als 130 oder 160 Zeichen (einschließlich der Länge des Tags).
- Wenn die Protokollierung Erfolge meldet, verwenden Sie sie nie auf höheren Ebenen als
VERBOSE
. - Wenn Sie die temporäre Protokollierung verwenden, um ein schwer reproduzierbares Problem zu diagnostizieren, halten Sie sie auf der Ebene
DEBUG
oderVERBOSE
und umschließen Sie sie mit if-Blöcken, die es erlauben, sie zur Kompilierungszeit zu deaktivieren. - Seien Sie vorsichtig mit Sicherheitslecks im Protokoll. Vermeiden Sie es, private Informationen zu protokollieren. Vermeiden Sie insbesondere die Protokollierung von Informationen über geschützte Inhalte. Dies ist besonders wichtig, wenn man Framework-Code schreibt, da es nicht einfach ist, im Voraus zu wissen, was private Informationen oder geschützte Inhalte sein werden und was nicht.
- Verwenden Sie niemals
System.out.println()
(oderprintf()
für nativen Code).System.out
undSystem.err
werden auf/dev/null
umgeleitet, so dass Ihre Druckanweisungen keine sichtbaren Auswirkungen haben. Allerdings wird die gesamte Zeichenkettenerstellung, die bei diesen Aufrufen stattfindet, weiterhin ausgeführt. - Die goldene Regel der Protokollierung ist, dass Ihre Protokolle nicht unnötigerweise andere Protokolle aus dem Puffer verdrängen dürfen, so wie andere Ihre Protokolle nicht verdrängen dürfen.
Stilregeln für Java-Tests
Befolgen Sie die Konventionen für die Benennung von Testmethoden und verwenden Sie einen Unterstrich, um das zu testende Programm von dem zu testenden Fall zu trennen. Dieser Stil macht es einfacher zu sehen, welche Fälle getestet werden. For example:
testMethod_specificCase1 testMethod_specificCase2void testIsDistinguishable_protanopia() { ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA) assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK)) assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))}