Eine kurze Zusammenfassung der Best Practices für die Java-Codierung

basierend auf Kodierungsstandards von Oracle, Google, Twitter und Spring Framework

Ziel dieses Artikels ist es, Ihnen eine kurze Zusammenfassung der Vor- und Nachteile zu geben. Mit anderen Worten: Bevorzugen und Vermeiden Sie es, basierend auf Codierungsstandards von Technologiegiganten wie Oracle, Google, Twitter und Spring Framework.

Sie können einigen der hier vorgestellten Best Practices zustimmen oder auch nicht. Dies ist absolut in Ordnung, solange ein Kodierungsstandard vorhanden ist.

Warum überhaupt Kodierungsstandards? Es gibt viele gute Gründe, wenn Sie es googeln und ich werde Sie mit der folgenden Abbildung verlassen

Das Kodierungsdokument kann langwierig und langweilig sein. Dieser Artikel basiert auf den Kodierungskonventionen von Google, Oracle, Twitter und Spring. Ziel ist es, Ihnen einen leicht verständlichen und weniger langweiligen Satz von Methoden zur Verfügung zu stellen, mit denen Sie Ihren Code einfach lesen und warten können.

Fast immer werden Sie sich Teams anschließen, die an vorhandener Software arbeiten, und es besteht eine ziemlich gute Chance, dass die meisten Autoren andere Projekte verlassen oder zu anderen Projekten gewechselt haben.

Informieren Sie sich über bewährte Methoden aus verschiedenen Codierungsstandards.

Java-Quelldatei

Folgendes gilt als bewährte Methode für Java-Quelldateien:

  • Die Länge der Quelldatei beträgt weniger als 2.000 Codezeilen
  • Die Quelldatei enthält einen Dokumentationskommentar, eine Paketdeklaration, gefolgt von einem Klassenkommentar, gruppierten (statischen letzten) Importen, Klassen- / Schnittstellensignaturen usw. (siehe unten)
package com.example.model;
/ **
 * Implementierungsfreie Perspektive für Entwickler
 * die möglicherweise nicht unbedingt den Quellcode zur Hand haben
 *
 * @author x, y, z
 * @Datum
 * @Ausführung
 * @Urheberrechte ©
 *
 * /
import com.example.util.FileUtil;
/ *
 * Optionaler klassenspezifischer Kommentar
 *
 * /
öffentliche Klasse SomeClass {
  // Statische Variablen in der Reihenfolge ihrer Sichtbarkeit
  public static final Integer PUBLIC_COUNT = 1;
  statische letzte Ganzzahl PROTECTED_COUNT = 1;
  private static final Integer PRIVATE_COUNT = 1;
  // Instanzvariablen in der Reihenfolge ihrer Sichtbarkeit
  public String name;
  String postalCode;
  private String-Adresse;
  // Konstruktor und in sequentieller Reihenfolge überladen
  public SomeClass () {}
  public SomeClass (String name) {
    this.name = name;
  }
  // Methoden
  public String doSomethingUseful () {
    return "Etwas Nützliches";
  }
  // am ende getters, setter, equals, hashCode und toString
}

Benennung

Klassen- und Schnittstellennamen sind CamelCase. Es wird empfohlen, das ganze Wort zu verwenden und Akronyme / Abkürzungen zu vermeiden. Zum Beispiel Klasse Raster oder Klasse ImageSprite

  • Paketnamen com.deepspace über com.deepSpace oder com.deep_space
  • Dateinamen sind CamelCase und enden mit .java, das dem Klassennamen entspricht. Es gibt eine öffentliche Klasse pro Datei mit jeder übergeordneten Klasse in ihrer Datei
  • Methodennamen sollten Verben in gemischter Schreibweise sein, wobei jedes interne Wort in Großbuchstaben geschrieben wird, zum Beispiel run (); oder runFast ();
  • Konstanten - sollten in Großbuchstaben geschrieben werden, wobei jedes Wort durch ein "_" getrennt wird, z. B. int MIN_WIDTH = 44; und int MAX_WIDTH = 99;
  • Variable - Ein Name, der dem Leser des Programms mitteilt, was die Variable darstellt. Wenn Sie eine Testnote speichern, wählen Sie die Note vs var1. Halten Sie die Variablennamen kurz und schließen Sie keine Metadaten ein.
// Prefer () - Variablennamen sind kurz und beschreiben, was sie speichern
int schoolId;
int [] filtersSchoolIds;
int [] uniqueSchooldIds;
Map  usersById;
String value;
// Vermeide (x) - Zu detaillierte Benennung der Variablen
int schoolIdentificationNumber;
int [] userProvidedSchoolIds;
int [] schoolIdsAfterRemovingDuplicates;
Map  idToUserMap;
String valueString;

Denken Sie daran - der Variablenname sollte kurz sein und dem Leser leicht sagen, welchen Wert er repräsentiert. Nutzen Sie Ihr Urteilsvermögen.

Bevorzugen und vermeiden

Beim Formatieren und Einrücken geht es darum, den Code so zu organisieren, dass er leicht lesbar ist. Dazu gehören Abstand, Zeilenlänge, Zeilenumbrüche und -umbrüche usw.

  • Einrückung - Verwenden Sie 2 oder 4 Leerzeichen und bleiben Sie konsistent
  • Zeilenlänge - Bis zu 70 bis 120 Zeichen, abhängig von der Lesbarkeit. Es ist wichtig, das horizontale Scrollen zu vermeiden und nach einem Komma und einem Operator Zeilenumbrüche einzufügen.

Methoden - Hier finden Sie eine Liste bewährter Methoden

// Prefer () Zeilenumbrüche sind willkürlich und werden nach einem Komma unterbrochen.
String DownloadAnInternet (Internet Internet, Röhren Röhren,
    Blogosphere-Blogs, Menge  -Bandbreite) {
  tubes.download (Internet);
}
// Vermeide (x) Schwer zu diffundierende Methodenargumente zum Methodenkörper
String DownloadAnInternet (Internet Internet, Röhren Röhren,
    Blogosphere-Blogs, Menge  -Bandbreite) {
    tubes.download (Internet);
}
// Bevorzugen Sie () Fügen Sie 8 (2 oder 4) Leerzeichen für einen tiefen Einzug hinzu
private static synchronized horkingLongMethodName (int anArg,
        Objekt anotherArg, String yetAnotherArg,
        Object andStillAnother) {
  ...
}
// Bevorzugen Sie () Einfaches Scannen und zusätzlichen Spaltenraum.
public String downloadAnInternet (
    Internet Internet,
    Röhren,
    Blogosphere-Blogs,
    Menge  Bandbreite) {
  tubes.download (Internet);
  ...
}
Ein Unit-Test hätte das erwischt

If-Checks - Durch das Schreiben von gut formatiertem Code in IMO können Tippfehler und Fehler für den Autor und die Codeüberprüfer leicht erkannt werden (siehe unten):

// Vermeide (x) Lass {} nicht aus
if (Bedingung)
  Aussage;
// Vermeide (x)
wenn (x <0) negativ (x) ist;
// Vermeide (x)
if (a == b && c == d) {
...
}
// Bevorzugt ()
if ((a == b) && (c == d)) {
...
}
// Bevorzugt ()
if (Bedingung) {
  Aussagen;
} else if (Bedingung) {
  Aussagen;
} else if (Bedingung) {
  Aussagen;
}
// Vermeide (x)
if ((Bedingung1 && Bedingung2)
    || (Bedingung3 && Bedingung4)
    ||! (Bedingung5 && Bedingung6)) {// BAD WRAPS
    mach etwas dagegen(); // MACHEN SIE DIESE LINIE EINFACH, UM ZU FEHLEN
}
// Bevorzugt ()
if ((Bedingung1 && Bedingung2)
        || (Bedingung3 && Bedingung4)
        ||! (Bedingung5 && Bedingung6) {
    mach etwas dagegen();
}

Ternärer Operator - Im Folgenden werden empfohlene Vorgehensweisen aufgeführt

alpha = (aLongBooleanExpression)? Beta: Gamma;
alpha = (aLongBooleanExpression)? Beta
        : Gamma;
alpha = (aLongBooleanExpression)
        ? Beta
        : Gamma;

Wechseln - Wenn es um das Wechseln geht, ist dies die beste Vorgehensweise

  • Haben Sie immer einen Standardfall, auch ohne Code
  • Verwenden Sie / * fällt durch * /, um anzuzeigen, dass das Steuerelement auf den nächsten Fall fällt
Schalter (Bedingung) {
  Fall ABC:
    Aussagen;
  / * fällt durch * /
  Fall DEF:
    Aussagen;
    brechen;
  Standard:
    Aussagen;
     brechen;
}

Ausnahmemeldungen - Wenn hier eine Ausnahme ausgelöst wird, werden Beispiele für gute und schlecht eingerückte Meldungen angezeigt.

// Vermeide (x) - Nicht leicht zu lesen
Neue IllegalStateException auslösen ("Anfrage konnte nicht verarbeitet werden" + request.getId ()
    + "für Benutzer" + user.getId () + "query: '" + query.getText ()
    + "'");
// Prefer () - Ziemlich leichter zu lesen
Neue IllegalStateException auslösen ("Verarbeitung fehlgeschlagen")
    + "request" + request.getId ()
    + "für Benutzer" + user.getId ()
    + "query: '" + query.getText () + "'");

Iteratoren und Streams - Streams werden immer häufiger und manchmal können sie sehr komplex sein. Daher ist es wichtig, sie einzurücken, damit sie leicht lesbar sind.

// Vermeide (x) - Nicht leicht zu lesen
Iterable  modules = ImmutableList.  builder (). Add (new LifecycleModule ())
    .add (neues AppLauncherModule ()). addAll (application.getModules ()). build ();
// Prefer () - Ziemlich leichter zu lesen
Iterable  modules = ImmutableList.  builder ()
    .add (neues LifecycleModule ())
    .add (neues AppLauncherModule ())
    .addAll (application.getModules ())
    .bauen();
Befolgen Sie einfach einen Kodierungsstandard - wirklich jeden

Deklarationen und Zuweisungen - Eine Deklaration pro Zeile wird empfohlen, da hiermit Kommentare wie unten gezeigt unterstützt werden.

// Bevorzugt ()
int level; // Einzugsebene
int sizeMeter; // Größe der Tabelle
// Vermeide (x) zugunsten von oben
int level, sizeMeter;
// Prefer () - Einheit in Variablennamen oder -typ einschließen
long pollIntervalMs;
int fileSizeGb;
Amount  fileSize;
// Vermeiden Sie (x) Mischtypen
int foo, fooarray [];
// Vermeide (x) - Trenne nicht mit Komma
Format.print (System.out, "error"), exit (1);
// Vermeiden Sie (x) Mehrfachzuweisungen
fooBar.fChar = barFoo.lchar = 'c';
// Vermeiden Sie (x) eingebettete Zuweisungen, um die Leistung // zu steigern oder eine Zeile zu speichern. Ich bin schuld daran :(
d = (a = b + c) + r;
// Ziehe () oben vor
a = b + c;
d = a + r;
// Bevorzugt ()
String [] args
// Vermeide (x)
String-Argumente []
// Bevorzugen Sie () Verwenden Sie lange "L" anstelle von "l", um Verwechslungen mit 1 zu vermeiden
langes Timeout = 3000000000L;
// Vermeide (x) - Schwer zu sagen, dass der letzte Buchstabe l und nicht 1 ist
langes Timeout = 3000000000l;

Stellen Sie Deklarationen nur am Anfang von Blöcken ein (Ein Block ist Code, der von geschweiften Klammern {und} umgeben ist). Warten Sie nicht, bis die Variablen zum ersten Mal verwendet werden. Dies kann den unachtsamen Programmierer verwirren und die Code-Portabilität innerhalb des Bereichs beeinträchtigen.

// Prefer () deklariert am Anfang des Blocks.
public void doSomething () {
  int whatIRepresent; // Beginn des Methodenblocks
  if (Bedingung) {
    int someFlag; // Beginn des "if" -Blocks
    …
  }
}

Es ist auch wichtig, lokale Erklärungen zu vermeiden, die Erklärungen der höheren Ebenen verbergen, und Verwirrungen zu vermeiden, wie unten gezeigt

int count;
...
public void doSomething () {
  if (Bedingung) {
    int count; // VERMEIDEN!
    ...
  }
  ...
}

Abstand & Zeilenumbrüche - Vermeiden Sie die Versuchung, 1–2 Codezeilen auf Kosten der Lesbarkeit zu speichern. Hier finden Sie die besten Vorgehensweisen in Bezug auf Abstände und Leerzeilen (Ein Leerzeichen macht einen Unterschied).

  • Eine (1) Leerzeile zwischen Methoden und Spring-Entwicklern empfiehlt zwei (2) Leerzeilen nach Konstruktoren, statischem Block, Feldern und innerer Klasse
  • Space-Pad-Operatoren, d. H. Use int foo = a + b + 1; über int foo = a + b + 1;
  • Trennen Sie alle binären Operatoren mit Ausnahme von "." Von Operanden, indem Sie ein Leerzeichen verwenden
  • Die offene Klammer "{" wird am Ende derselben Zeile wie die Deklarationsanweisung oder -methode angezeigt, und die schließende Klammer "}" beginnt eine Zeile, die von selbst eingerückt wird
// Prefer () - Leerzeichen nach "while" und vor "("
while (wahr) {
  ...
}
// Vermeide (x) - Anders als oben kein Leerzeichen
while (wahr) {
  ...
}
// Prefer () - Kein Leerzeichen zwischen "doSomething" und "("
public void doSomething () {
  ...
}
// Vermeide (x) - Im Gegensatz zum obigen Leerzeichen
public void doSomething () {
  ...
}
// Prefer () - Füge ein Leerzeichen nach einem Argument ein
public void doSomething (int a, int b) {
  ...
}
// Prefer () - Leerzeichen zwischen Operanden und Operatoren (d. H. +, =)
a + = c + d;
a = (a + b) / (c * d);
while (d ++ = s ++) {
  n ++;
}

Dokumentation und Kommentare

Es ist erwähnenswert, dass sich fast jeder Code während seiner gesamten Lebensdauer ändert und dass Sie oder jemand versucht, herauszufinden, was ein komplexer Codeblock, eine Methode oder eine Klasse tun soll, es sei denn, dies wird eindeutig beschrieben. Die Realität sieht fast immer so aus

Es gibt Zeiten, in denen der Kommentar zu einem komplexen Teil des Codes, der Methode oder der Klasse keinen Wert hinzufügt oder seinem Zweck dient. Dies geschieht normalerweise beim Kommentieren.

Kommentare sollten verwendet werden, um einen Überblick über den Code zu geben und zusätzliche Informationen bereitzustellen, die im Code selbst nicht ohne weiteres verfügbar sind. Lass uns anfangen. Es gibt zwei Arten von Kommentaren

Implementierungskommentare - dienen zum Auskommentieren von Code oder Kommentieren einer bestimmten Implementierung des Codes.

Dokumentationskommentare - sollen die Spezifikation des Codes aus einer implementierungsfreien Perspektive beschreiben und von Entwicklern gelesen werden, die möglicherweise nicht unbedingt den Quellcode zur Hand haben.

Die Häufigkeit der Kommentare spiegelt manchmal die schlechte Qualität des Codes wider. Wenn Sie gezwungen sind, einen Kommentar hinzuzufügen, sollten Sie den Code neu schreiben, um ihn klarer zu gestalten.

Arten von Implementierungskommentaren

Es gibt vier (4) Arten von Implementierungskommentaren (siehe unten)

  • Blockkommentar - siehe Beispiel unten
  • Einzeiliger Kommentar - wenn der Kommentar nicht länger als eine Zeile ist
  • Nachgestellte Kommentare - Ein sehr kurzer Kommentar wurde an das rechte Ende verschoben
  • Zeilenende-Kommentar - Fängt einen Kommentar an, der bis zur neuen Zeile reicht. Es kann eine komplette Zeile oder nur eine Teilzeile auskommentieren. Es sollte nicht in mehreren aufeinanderfolgenden Zeilen für Textkommentare verwendet werden. Es kann jedoch in mehreren aufeinanderfolgenden Zeilen zum Auskommentieren von Codeabschnitten verwendet werden.
// Kommentar blockieren
/ *
 * Verwendung: Beschreibt Dateien, Methoden und Datenstrukturen
 * und Algorithmen. Kann am Anfang jeder Datei und verwendet werden
 * vor jeder Methode. Wird für lange Kommentare verwendet, die nicht passen
 * einzelne Zeile. 1 Leerzeile nach dem Blockkommentar.
 * /
// Einzeiliger Kommentar
if (Bedingung) {
 / * Behandle den Zustand. * /
  ...
}
// Hinterer Kommentar
if (a == 2) {
 return TRUE; /* besonderer Fall */
} else {
 return isPrime (a); / * funktioniert nur für ungerade a * /
}
// Zeilenende Kommentar
if (foo> 1) {
  // Mach einen Double-Flip.
  ...
} else {
  falsch zurückgeben; // Erkläre hier warum.
}
// if (bar> 1) {
//
// // Mach einen Triple-Flip.
// ...
//}
//sonst
// falsch zurückgeben;

Dokumentationskommentare (d. H. Javadoc)

Javadoc ist ein Tool, das aus den Kommentaren, die mit / ** beginnen und mit * / enden, HTML-Dokumentation für Ihren Java-Code generiert. Weitere Informationen zur Funktionsweise von Javadoc finden Sie in Wikipedia.

Hier ist ein Beispiel für Javadoc

/ **
 * Gibt ein Bildobjekt zurück, das dann auf dem Bildschirm gezeichnet werden kann.
 * Das url-Argument muss eine absolute {@link URL} angeben. Der Name
 * argument ist ein Bezeichner, der relativ zum url-Argument ist.
 * 

 * Diese Methode gibt immer sofort zurück, unabhängig davon, ob die  * Bild existiert. Wenn dieses Applet versucht, das Bild zu zeichnen  * Auf dem Bildschirm werden die Daten geladen. Die Grafikprimitive  * Wenn Sie das Bild zeichnen, wird es schrittweise auf den Bildschirm gezeichnet.  *  * @param url eine absolute URL, die die Basisposition des Bildes angibt  * @param benennt den Ort des Bildes relativ zum url-Argument  * @ das Bild unter der angegebenen URL zurücksenden  * @siehe Bild  * /  public Image getImage (URL-URL, String-Name) {         Versuchen {             return getImage (neue URL (URL, Name));         } catch (MalformedURLException e) {             return null;         }  }

Und das Obige würde zu einem HTML führen, wie folgt, wenn javadoc mit dem Code ausgeführt wird, der das Obige enthält

Sehen Sie hier für mehr

Im Folgenden finden Sie einige wichtige Tags, mit denen Sie die Qualität der generierten Java-Dokumentation verbessern können.

@author => @author Raf
@code => {@code A  C}
@deprecated => @deprecated veraltete Nachricht
@exception => @exception IOException wird ausgelöst, wenn
@link => {@link package.class # member label}
@param => Beschreibung des @param-Parameternamens
@return => Was die Methode zurückgibt
@see => @see "string" ODER @see  
@since => Zeigt die Version an, wenn eine öffentlich zugängliche Methode hinzugefügt wird

Eine vollständige Auflistung und eine detailliertere Beschreibung finden Sie hier

Der Codierungsstandard von Twitter rät von der Verwendung des @author-Tags ab

Code kann im Laufe seines Lebens mehrmals den Besitzer wechseln, und der ursprüngliche Autor einer Quelldatei ist nach mehreren Iterationen häufig irrelevant. Wir sind der Meinung, dass es besser ist, Commit-Verlaufs- und EIGENTÜMER-Dateien zu vertrauen, um den Besitz eines Code-Körpers zu bestimmen.

Im Folgenden finden Sie Beispiele, wie Sie einen Dokumentationskommentar verfassen können, der aufschlussreich ist, wie im Codierungsstandard von Twitter beschrieben

// Schlecht.
// - Das Dokument sagt nichts, was die Methodendeklaration nicht getan hat.
// - Dies ist das 'Füller-Dokument'. Es würde Stilprüfungen bestehen, aber
hilft niemandem.
/ **
 * Teilt eine Zeichenfolge.
 *
 * @param s Ein String.
 * @return Eine Liste von Zeichenfolgen.
 * /
List  split (String s);
// Besser.
// - Wir wissen, worauf sich die Methode aufteilt.
// - Immer noch undefiniertes Verhalten.
/ **
 * Teilt eine Zeichenfolge in Leerzeichen.
 *
 * @param s Der zu teilende String. Eine {@code null} Zeichenfolge wird als leere Zeichenfolge behandelt.
 * @return Eine Liste der durch Leerzeichen getrennten Teile der Eingabe.
 * /
List  split (String s);
// Toll.
// - Deckt noch einen Randfall ab.
/ **
 * Teilt eine Zeichenfolge in Leerzeichen. Wiederholte Leerzeichen
 * sind zusammengebrochen.
 *
 * @param s Der zu teilende String. Eine {@code null} Zeichenfolge wird als leere Zeichenfolge behandelt.
 * @return Eine Liste der durch Leerzeichen getrennten Teile der Eingabe.
 * /
List  split (String s);

Es ist wichtig, beim Verfassen von Kommentaren professionell zu sein

// Vermeide (x)
// Ich hasse xml / soap so sehr, warum kann es das nicht für mich tun?
Versuchen {
  userId = Integer.parseInt (xml.getField ("id"));
} catch (NumberFormatException e) {
  ...
}
// Bevorzugt ()
// TODO (Jim): Versteckt die Feldvalidierung in einer Bibliothek.
Versuchen {
  userId = Integer.parseInt (xml.getField ("id"));
} catch (NumberFormatException e) {
  ...
}

Und es ist wichtig zu bedenken, dass überschriebene Methoden nur dann dokumentiert werden, wenn sich die Implementierung geändert hat.

Und hier sind noch ein paar Punkte zu beachten

  • Vermeiden Sie Platzhalterimporte - wie in den Codierungsstandards von Twitter beschrieben, wird die Quelle der Klasse weniger klar. Ich arbeite in einem Team mit einer Mischung aus Eclipse- und IntelliJ-Benutzern und habe festgestellt, dass Eclipse Platzhalterimporte entfernt und IntelliJ diese einführt. Es gibt wahrscheinlich eine Option, um es zu deaktivieren, wollte nur auf die Standardeinstellung für die beiden hinweisen.
  • Verwenden Sie beim Überschreiben immer die Annotation @Override
  • Ermutigen Sie die Verwendung von @Nullable, wenn ein Feld oder eine Methode null zurückgibt
  • Nutzen Sie spezielle Kommentare für zukünftige Arbeiten und vergessen Sie nicht, einen Verweis auf sich selbst zu hinterlassen, damit andere wissen, wen sie ihre Y-Frage stellen müssen, anstatt sie zu erraten, zu entfernen oder die Schuld zu prüfen, um herauszufinden, wer sie hinzugefügt hat. Einige IDEs wie Eclipse und IntelliJ helfen auch dabei, diese für den einfachen Zugriff sowie als Erinnerung aufzulisten.
// FIXME (Raf): Eine umsetzbare Nachricht beschreibt, was zu tun ist
// TODO (Raf): Eine umsetzbare Nachricht beschreibt, was zu tun ist

Das Endspiel besteht darin, Code zu schreiben, der zukünftigen Autoren und Betreuern das Leben leichter macht.

Das Endspiel

Andere relevante Lesematerialien

Eine Auflistung relevanter Artikel, die für das Schreiben von Code relevant sind. Sie sind übersichtlich, gut strukturiert, einfach zu lesen und zu warten. Wenn Sie mehr lesen möchten, empfehlen Sie auf jeden Fall die folgenden

und eine weitere gute Liste von Tipps zum Schreiben von sauberem Code