Java Programmierkonventionen

IFS-Logo Diese Seite ist ein Teil der IsyFact-Standards. Alle Inhalte der Seite, insbesondere Texte und Grafiken, sind urheberrechtlich geschützt. Alle urheberrechtlichen Nutzungs- und Verwertungsrechte liegen beim Bundesverwaltungsamt.

Creative Commons Namensnennung Die Nutzung ist unter den Lizenzbedingungen der Creative Commons Namensnennung 4.0 International gestattet.

1. Einleitung

In diesem Dokument werden die Java-Programmierkonventionen der IsyFact beschrieben.

Die Einhaltung der Programmierkonventionen fördert die Wartbarkeit und Weiterentwicklungsfähigkeit der nach den IsyFact Standards erstellten Software.

2. Motivation und Referenzen

Von den Lebensphasen einer Software macht die Erstellung gegenüber der Weiterentwicklung und Wartung nur einen kleinen Teil aus. Es ist davon auszugehen, dass im Laufe der Zeit unterschiedliche Personen, Teams oder Dienstleister an einem Softwaresystem arbeiten. Allen Beteiligten wird die Einarbeitung deutlich erleichtert, wenn die Software „aus einem Guss“ erscheint. Hält sie sich noch an allgemein etablierte und bekannte Standards, verkürzt sich die Einarbeitungszeit noch weiter. Um das zu erreichen, müssen Konventionen für die Programmierung festgelegt werden.

Die in diesem Dokument beschriebenen Richtlinien sind für die Erstellung von Programmen mit der IsyFact verbindlich. Die Strukturen zur Ablage des Quellcodes richten sich nach der Empfehlung von Apache Maven Standard Directory Layout und wurden für die IsyFact erweitert. Die Programmierkonventionen basieren auf Synopse und präzisieren sie an einigen Stellen. Die in The Elements of Java Style (Vermeulen et al., 2000) beschriebenen Konventionen beruhen auf den Sun Coding Conventions (1997) und den Coding Standards der Firma Ambysoft .

3. Vorgaben für die Quellcodeablage

Das Kapitel stellt zunächst die Vorgaben für Anwendungsprojekte vor, da diese die komplexeste Struktur aufweisen. Die weiteren Projekte (Schnittstellen, Batches, Deployment und Dokumentation) stellen aufgrund ihres starken Fokus Vereinfachungen dieser Struktur dar. Als letzte Projektart sind Multi-Modulprojekte beschrieben, die aus Kombinationen der vorangegangenen Projekte bestehen.

3.1. Anwendungsprojekte

3.1.1. Maven

Der Produktkatalog gibt die Nutzung von Maven vor. Daher ist für Anwendungen eine Entwicklung mittels einem oder mehrerer Maven-Module strengstens empfohlen.

3.1.1.1. Artefakte

Bei einem Maven-Artefakt wird eine Group-ID und eine Artefakt-ID definiert. Die Group-ID gibt einen direkten Anhaltspunkt auf die Domäne. Group-IDs werden mit einem Punkt konkateniert.

Tabelle 1. Group-ID von Modulen/Artefakten
Group-ID von Maven-Modulen/-Artefakten

Schema Group-ID

<sprach-kürzel>.<organisation>.<firma>.<domäne>

Beispiel

de.bund.bva.isyfact

Die Artefakt-ID beschreibt die Funktionalität des Artefaktes kurz und prägnant. Prinzipiell besitzt jedes Modul bzw. Artefakt ein Präfix. Artefakte einer Group-ID (Domäne) sollten immer ein einheitliches Präfix besitzen. So haben alle IsyFact-Artefakte das Präfix isy- in ihrer Artefakt-ID. Artefakt-IDs werden mit einem Bindestrich konkateniert.

Tabelle 2. Artefakt-ID von Maven-Modulen/-Artefakten
Artefakt-ID von Maven-Modulen/-Artefakten

Schema Artefakt-ID

<präfix>-<funktion/komponente>

<präfix>-<funktion/komponente>-<teilkomponente>

Beispiel

isy-documentation

isy-documentation-core

3.1.1.2. Module

Wird ein Maven-Modul verwendet, sollte es folgende Struktur besitzen:

  • Auf oberster Ebene, d. h. im Wurzelverzeichnis des Projekts (project-root), befinden sich die Dateien zur Organisation des Quellcodes, sowie anwendungsbezogene und allgemeine Informationen. Dateien in Klammern sind optional. Es ist nicht ausgeschlossen, andere Dateien auf oberster Ebene abzulegen, sofern sie für die Organisation der Applikation oder deren Quellcode zuständig sind.

  • Der Quellcode, Dokumentation, Skripte (SQL, Shell, etc.) und die Tests des Quellcodes liegen in Unterverzeichnissen des Verzeichnisses src.

Der Quellcode wird wiederum gemäß den Vorgaben aus Package-Namen strukturiert.

Listing 1. Struktur eines Anwendungsprojekts
project-root/
  |- license/ (1)
  |- assembly/ (2)
  |
  |- src/main/java/ (3)
  |- src/main/resources/ (4)
  |
  |- src/docs/asciidoc/ (5)
  |
  |- src/skripte/ (6)
  |
  |- src/test/java/ (7)
  |- src/test/resources/ (8)
  |
  |- (.gitattributes)
  |- .gitignore
  |- CHANGELOG.md (9)
  |- (LICENSE.md)
  |- pom.xml
  |- README.md
1 Lizenz-Dateien und ggf. Dependency-Berichte
2 Beschreibungen, wie das auszuliefernde Artefakt gepackt wird
3 Quellcode in Java
4 Konfigurationsdateien (z. B. application.properties) und andere Ressourcen (z.B. UI- oder Fehlertexte)
5 Technische Dokumentation (Systementwurf, Systemhandbuch) im AsciiDoc-Format
6 Skripte (z. B. SQL- oder Shell-Skripte)
7 Tests des Quellcodes in Java
8 Konfigurationsdateien für die Tests selbst oder für das zu testende IT-System
9 Dokumentation von Änderungen, z. B. via Eintrag einer Ticketnummer und kurzer Beschreibung

Die Struktur bei der Verwendung mehrerer Maven-Module wird im Abschnitt Multi-Modul-Projekte erläutert.

3.2. Batch-Projekte

Batch-Projekte bestehen hauptsächlich aus Startskripten und Konfigurationsdateien, um die Batches aufzurufen. Die Implementierung der Batches geschieht in der Anwendung, welche die Batches bereitstellt. Daher enthalten Batch-Projekte weder Quellcode noch Tests.

Batch-Projekte besitzen unter dem Wurzelverzeichnis (project-root) ein einzelnes Unterverzeichnis src/main/resources. Der Aufbau des Verzeichnisses wird im Batchrahmen beschrieben.

Listing 2. Struktur eines Batch-Projekts
project-root/
  |- src/main/resources/ (1)
  |
  |- (.gitattributes)
  |- .gitignore
  |- CHANGELOG.md
  |- (LICENSE.md)
  |- pom.xml
  |- README.md
1 Ausführungsdateien (Shell-Skripte) und Konfigurationsdateien

3.3. Deployment-Projekte

Deployment-Projekte bestehen im Wesentlichen aus den Skripten zur Erstellung einer Deployment-Einheit.

Deployment-Projekte besitzen unter dem Wurzelverzeichnis (project-root) ein einzelnes Unterverzeichnis src/main/resources. In diesem finden sich weitere Unterverzeichnisse, die für die Erstellung von RPMs angepasst sind.

Listing 3. Struktur eines Deployment-Projekts
project-root/
  |- src/main/resources/ (1)
  |    |- BUILD/
  |    |- RPMS.noarch/
  |    |- SOURCES/
  |    |- SPECS/
  |    |- SRPMS/
  |
  |- (build.xml) (2)
  |- (.gitattributes)
  |- .gitignore
  |- CHANGELOG.md
  |- (LICENSE.md)
  |- pom.xml
  |- README.md
1 Skripte und Vorschriften zur Erstellung eines RPMs
2 Optional: Anweisungen zum RPM-Build via Ant (deprecated)

3.4. Dokumentationsprojekte

Dokumentationsprojekte enthalten technische Dokumentation, die keinem Anwendungsprojekt direkt zuzuordnen sind. Beispiele dafür sind Dokumente übergreifender Natur aus architektonischer, technischer oder betrieblicher Sicht.

Dokumentationsprojekte besitzen unter dem Wurzelverzeichnis (project-root) ein einzelnes Unterverzeichnis src/docs/asciidoc. In diesem finden sich weitere Verzeichnisse, z. B. für Inhalte allgemeiner Natur, sowie für die Dokumente. Es empfiehlt sich, für jedes Dokument ein eigenes Verzeichnis zur Ablage spezifischer Inhalte (neben Texten z. B. auch Bilder und Diagramme) anzulegen. Vorgaben für die Struktur einzelner Dokumente finden sich in der Vorgaben zur Dokumentation.

Listing 4. Struktur eines Dokumentationsprojekts
project-root/
  |- src/docs/asciidoc/ (1)
  |
  |- (.gitattributes)
  |- .gitignore
  |- CHANGELOG.md
  |- (LICENSE.md)
  |- pom.xml
  |- README.md
1 Quelltext der Dokumente

3.5. Multi-Modul-Projekte

Die bisher beschriebenen Projekte finden sich oft als Teil eines größeren Projekts wieder. In diesem Fall werden sie in einem Multi-Modul-Projekt zusammengefasst.

Ein Multi-Modul-Projekt beinhaltet unterhalb seines Wurzelverzeichnisses seine Module, die nach einer der obigen Vorlagen strukturiert sind. In der Regel gibt es ein Modul für die Anwendung selbst und eines für das Deployment. Ob es Schnittstellen- und Batch-Module gibt, hängt von den fachlichen Anforderungen an das Projekt ab.

Listing 5. Struktur eines Multi-Modul-Projekts
project-root/
  |- {anwendung} (1)
  |- ({anwendung}-schnittstelle-1)
  |- ({anwendung}-schnittstelle-2)
  |- ({anwendung}-batch)
  |- {anwendung}-deployment
  |
  |- (.gitattributes)
  |- .gitignore
  |- CHANGELOG.md
  |- (LICENSE.md)
  |- pom.xml
  |- README.md
1 Der Platzhalter {anwendung} steht für den Namen oder das Kürzel der umzusetzenden Anwendung

Grundsätzlich können bei diesem Aufbau redundante Dateien in den Wurzelverzeichnissen der Module (z.B. .gitignore) entfallen, wenn sie bereits im Wurzelverzeichnis des Multi-Modul-Projekts vorhanden sind.

4. Vorgaben für die Programmierung

Programmiere immer im Stil des Originals!

Wird bestehender Programmcode verändert, dann werden die Änderungen immer im Stil des schon vorhandenen Codes programmiert, auch wenn der Code dadurch nicht die unten folgenden Richtlinien erfüllt. Bestehender Code, der nach anderen Richtlinien erstellt wurde, wird nicht im Rahmen von Wartungsmaßnahmen an andere Richtlinien angepasst, nur der Richtlinien wegen.

Dokumentiere Abweichungen!

Falls bestimmte Richtlinien nicht angewendet werden können/sollen, ist der technische Chef-Designer des Projektes zu involvieren. Er entscheidet darüber, ob die Abweichung zulässig ist. Abweichungen müssen immer im Entwicklerhandbuch des Projektes mit Begründung dokumentiert werden. Bevor eine Richtlinie verletzt wird, sollte man sicher sein, dass man die Motivation der Regel verstanden hat und die Konsequenzen der Nicht-Einhaltung beurteilen kann.

4.1. Namenskonventionen

4.1.1. Sprache

Die Sprache von Bezeichnern hängt davon ab, was mit ihnen referenziert wird.

Die Sprache ist eine Mischung aus deutsch und englisch. Für technische Bezeichner wird Englisch verwendet, für fachliche Bezeichner Deutsch. In Bezeichnern werden keine Umlaute und kein ß verwendet.

Beispiele: setMeldung(), suchePerson()

Motivation

Der Bruch zwischen den Sprachen fällt so mit dem Bruch zwischen technischem und fachlichem Code zusammen. Komplett deutsche oder komplett englische Bezeichner hätten dagegen folgende Nachteile:

  • Komplett englische Bezeichner würden es erfordern, alle Fachbegriffe zu übersetzen. Alle am Projekt beteiligten Personen müssten diese „Vokabeln“ neu lernen.

  • Komplett deutsche Bezeichner wirken sehr verkrampft, wenn sie Bibliotheksklassen mit englischen Bezeichnern nutzen oder (z. B. durch Ableitung) erweitern.

  • Komplett deutsche Bezeichner führen zu Irritationen und Problemen, da Java bestimmte Namenskonventionen zum Beispiel bei Beans voraussetzt (getXXX und setYYY).

Java erlaubt zwar Umlaute in Bezeichnern, im Falle von Klassennamen müssen dann jedoch auch die Dateinamen Umlaute enthalten. Dies wird nicht von allen Betriebssystemen unterstützt beziehungsweise führt beim Übertragen von Dateien zwischen Systemen leicht zu Problemen.

4.1.2. Allgemeine Regeln

Sprechende Namen wählen!

Es sollen möglichst „sprechende“ (selbsterklärende) Namen verwendet werden. Abkürzungen, zum Beispiel durch das Weglassen von Vokalen, sind grundsätzlich zu vermeiden. Ausnahmen dürfen bei temporär verwendeten Variablen (zum Beispiel Zählervariablen in einer for-Schleife) gemacht werden, wenn die Verwendung im Kontext klar ist.

Gängige Bezeichner benutzen!

Es sollen nur gängige Bezeichner verwendet werden. Existiert ein Glossar, sind die dort aufgeführten Bezeichner zu verwenden.

Nur der erste Buchstabe einer Abkürzung groß!

Zur besseren Unterscheidung der Namensbestandteile eines Bezeichners wird bei Abkürzungen nur der erste Buchstabe der Abkürzung großgeschrieben.

Falsch:

loadXMLDocument()

Richtig:

loadXmlDocument()

Das erleichtert die Lesbarkeit, insbesondere wenn zwei Abkürzungen hintereinander folgen.

Keine Unterscheidung bei Groß-/Kleinschreibung!

Es dürfen nicht mehrere Namen verwendet werden, die sich ausschließlich durch abweichende Groß-/Kleinschreibung unterscheiden.

4.1.3. Dateinamen

Um Einheitlichkeit bei den Dateinamen sicherzustellen, sind Namenskonventionen für Dateiendungen und gebräuchliche Dateinamen notwendig.

Dateinamen enthalten keine Sonderzeichen, Umlaute oder Leerzeichen. Erlaubt sind die Buchstaben von A bis Z (groß und klein), Ziffern, der Unterstrich, der Mittelstrich und der Punkt. Datumsangaben werden dem Dateinamen vorangestellt und erfolgen im Format <JJJJ-MM-TT_Dateiname>.

Tabelle 3. Dateiendungen
Endung Typ bzw. Beschreibung

.properties

Datei mit Konfigurationsparametern

In der nachfolgenden Tabelle werden gebräuchliche Dateinamen aufgeführt.

Tabelle 4. Gebräuchliche Dateinamen
Dateiname Typ bzw. Beschreibung

index.html

Der Name der Datei, in der eine zusammenfassende Beschreibung des Dateiverzeichnisses steht, das kein Package ist.

package.html

Der Name der Datei, in der eine zusammenfassende Beschreibung des Packages steht.

4.1.4. Bezeichner und Kommentare

Mehrere Wörter werden bei zusammengesetzten Bezeichnern direkt aneinander geschrieben und nicht durch Sonderzeichen getrennt. Die einzelnen Wörter beginnen jeweils mit einem Großbuchstaben.

Falsch:

Number_Formatter

Richtig:

NumberFormatter

Ansonsten gelten die Regeln der nachfolgenden Abschnitte.

4.1.5. Package-Namen

Standard-Package-Struktur verwenden!

Die Package-Struktur folgt einer Konvention, die aus der fachlichen und technischen Referenzarchitektur hergeleitet wird.

Listing 6. Package-Struktur
<organisation>.<domäne>.<anwendung>.<layer>.<subsystem/
komponente>. ...
  <domäne>
	= (Name gemäß fachlicher Architektur, z. B. "meinedomaene")
  <anwendung>
	= (Name gemäß fachlicher Architektur, z. B. "meineanwendung)
  <layer>
	= common | batch | service | core | persistence
  <subsystem/komponente>
	= Name der Geschäftsanwendung bzw. querschnittlichen Komponente gemäß fachlicher Architektur

Unterhalb von <subsystem/komponente> werden die Packages projektspezifisch strukturiert.

Keine Sonderzeichen verwenden!

Der Anwendungsname in <anwendung> wird an Java-Package-Konventionen angepasst. Leer- und Sonderzeichen in den Anwendungsnamen werden gestrichen.

Package-Namen immer kleinschreiben!

Namen von Packages dürfen nur Kleinbuchstaben enthalten.

Richtig

de.bund.bva.meinedomaene.meineanwendung.service.admin
de.bund.bva.isyfact.meineanwendung.persistence.meinegk
de.bund.bva.isyfact.logging.common.layout

Falsch

de.bund.bva.isyfact.MeineAnwendung.persistence.meinegk
de.bund.bva.isyfact.meineanwendung.persistence.meineanwendung
de.bund.bva.meinedomaene.meineanwendung.admin.service

4.1.6. Klassen- und Interface-Namen

Erster Buchstabe immer groß!

Bei Klassen- und Interface-Namen wird der erste Buchstabe jedes Teilwortes immer großgeschrieben.

Beispiele: DemoClass, PrintStream, ActionListener

Substantive als Klassennamen!

Für die Namen von Klassen sind Substantive zu verwenden.

Beispiel: Meldung

Plural für Zusammenfassungen!

Für Klassen, die Dinge zusammenfassen, soll der Plural verwendet werden.

Beispiele: LineMetrics, Beans, Types, Sachverhalte

Bei Interfaces Substantive oder Adjektive verwenden!

Bei Interfaces soll der Bezeichner ein Substantiv oder ein Adjektiv sein. Namen von Interfaces werden NICHT mit dem Präfix „I" versehen.

4.1.7. Interface-Implementierungen

Besteht der Zweck genau einer Klasse ausschließlich oder zum größten Teil aus der Implementierung eines Interfaces, dann wird die Klasse so genannt wie das Interface, ergänzt um das Suffix Impl.

Tabelle 5. Klassenname bei hauptsächlicher Implementierung eines Interfaces
Klassenname bei hauptsächlicher Implementierung eines Interfaces

Schema

<Interface>Impl

Beispiele

MeldungImpl

NachrichtErzeugungImpl

Beispiele: ActionListener, Runnable, Accessable

4.1.8. Methodennamen

Methodennamen beginnen immer mit einem Verb!

Methodennamen sind Verben und beginnen immer mit einem Kleinbuchstaben. Danach wird der erste Buchstabe eines jeden Teilwortes großgeschrieben. Teilworte werden nicht durch Sonderzeichen getrennt, insbesondere nicht durch Unterstriche. Nachfolgende Teilworte können Substantive sein.

Beispiel: doSomething, getStrasse, setName

JavaBeans-Konventionen einhalten!

Die JavaBeans-Konventionen müssen eingehalten werden: Lesen von Eigenschaften mittels getProperty() bzw. isProperty() für Booleans, Schreiben von Eigenschaften mittels setProperty().

4.1.9. Variablennamen

Für die Vergabe von Variablennamen gilt: Je globaler die Sichtbarkeit einer Variable ist, desto aussagekräftiger (und ggf. länger) sollte der Name sein. Das schließt nicht aus, das ein für drei Zeilen gültiger Schleifenzähler „i“ heißt.

Als Variablennamen Substantive verwenden und immer klein beginnen!

Variablennamen beginnen immer mit einem Kleinbuchstaben und sind ein Substantiv. Danach wird der erste Buchstabe eines jeden Teilwortes großgeschrieben. Teilworte werden nicht durch Sonderzeichen getrennt.

Beispiel: mySampleVariable

Plural für Bezeichner von Sammlungen!

Für die Bezeichner von Sammlungen sind Namen im Plural zu verwenden.

Beispiel: auftraege, auftragsPositionen, kunden

Standards für temporäre Variablen einsetzen!

Folgende Bezeichner sind für die Bezeichner von temporären Variablen zu verwenden:

Integer

i, j, k

Character

c, d, e

Koordinaten

x, y, z

Object

o

Stream

in, out, inOut

String

s, t

Keine Präfixe außer this. verwenden!

Außer dem Präfix this. bei Instanzvariablen werden keine Präfixe für Klassen-, Instanzvariablen und für Parameter verwendet.

4.1.10. Konstanten

Konstanten immer groß!

Die Bezeichner von Konstanten werden nur mit Großbuchstaben geschrieben. Jedes Teilwort wird durch einen Unterstrich getrennt. Bei jeder Konstante ist zu überlegen, ob sie nicht durch das Typesafe-Enum-Pattern oder eine Konfigurationsvariable aus einer Datei/Datenbank ersetzt werden kann.

Beispiele: A_MAGIC_NUMBER, MAX_VALUE, MIN_VALUE

4.2. Formatierung

Die Formatierung des Quellcodes gemäß der nachfolgenden Regeln kann durch den Eclipse Code Formatter automatisch vorgenommen werden.

4.2.1. Einrückungen und Klammerposition

Für das Einrücken sind immer vier Leerzeichen zu verwenden. Bei Code-Blöcken wird die öffnende Klammer "{" immer als letztes Zeichen der Zeile gesetzt, die den Code-Block einleitet. Die schließende Klammer "}" wird immer in einer neuen Zeile nach dem Block positioniert und links an dem ersten Zeichen der einleitenden Zeile ausgerichtet.

Zur Einrückung des Textes niemals Tabulatoren, sondern immer Leerzeichen verwenden, da Tabulatoren von verschiedenen Werkzeugen unterschiedlich interpretiert werden können.

Geschweifte Klammern sollen auch dann verwendet werden, wenn innerhalb eines Blocks nur ein Statement vorhanden ist und somit syntaktisch auf deren Verwendung verzichtet werden könnte.

Beispiele für Anwendung der Formatierungsregeln (· steht für ein Leerzeichen):

public·class·MyClass·{
····statements;
}
if·(condition)·{
····statements;
}·else·{
····statements;
}

4.2.2. Leerzeichen und Leerzeilen in Kommandos und Ausdrücken

Es wird empfohlen, Leerzeichen wie folgt zu verwenden:

  • zwischen einem Schlüsselwort und einer direkt darauf folgenden "{" Klammer

  • zwischen der Klammer ")" bzw. "}" und einem direkt darauf folgenden Schlüsselwort

  • zwischen einer Klammer ")" und einer direkt darauf folgenden Klammer "{"

  • nach einem Komma (z. B. bei einer Methode mit mehreren Parametern)

  • zwischen einem binären (ternären) Operator (außer dem Punktoperator) und dem vorausgehenden und dem nachfolgenden Ausdruck.
    Beispiel: double·length·=·Math.sqrt(x·*·x··y·*·y);+
    Dies gilt insbesondere für ·=· und ·==·

Leerzeilen eignen sich zur Trennung logischer unabhängiger Teile des Codes. Methoden werden durch eine Leerzeile voneinander getrennt. Auch innerhalb einer Methode können Leerzeilen die logische Trennung von Blöcken verdeutlichen.

4.2.3. Aufteilen langer Codezeilen

Die Zeichen pro Zeile sind auf eine lesbare Anzahl zu begrenzen. Es sollten niemals mehrere Anweisungen in einer Zeile codiert werden. Wenn ein Ausdruck nicht in eine Zeile passt, so ist sie so zu trennen, dass das Ergebnis sinnvoll lesbar ist. Es folgen Hinweise, wo unter Umständen sinnvoll getrennt werden und wie getrennte Zeilen formatiert werden könnten.

Eine Zeile in der Eclipse-Entwicklungsumgebung fasst bei Verwendung der default-Einstellungen ca. 110 Zeichen.

  • Hinter einem Komma

  • Vor einem Operator (+, -, etc.)

  • Bei geschachtelten Ausdrücken möglichst weit außen

  • Die neue Zeile wird so eingerückt, dass sie unter dem Anfang des Teilausdrucks steht, den man trennt

Falls die obigen Regeln zu unleserlichen Einrückungen führen, wird der Code um acht Zeichen eingerückt.

Das Umbrechen einer Zeile geschieht möglichst nach einem Komma. Die nächste Zeile wird dann an dem Ausdruck vor dem Komma ausgerichtet.

4.3. Dokumentation

Folgende Grundsätze sind beim Schreiben von Dokumentation und Kommentaren zu befolgen:

Code und Dokumentation müssen immer übereinstimmen!

Wenn Code verändert wird, muss sichergestellt werden, dass die entsprechenden Kommentare und die Dokumentation weiter zum Code passen. Nach jedem Refactoring muss ein Überprüfen und eventuelles Anpassen der Dokumentation erfolgen.

Kommentare sind in Englisch zu verfassen. Es ist deutliche Sprache zu verwenden und Floskeln sind zu vermeiden!

Für die technische Dokumentation hat sich eine klare und schnörkellose Sprache bewährt.

Bei der Dokumentation von Programmcode sind zwei Adressatenkreise zu unterscheiden:

Personen, die den Code einsetzen, d. h. nutzen wollen. Sie sind an den öffentlichen Programmierschnittstellen der Packages und der Klassen bzw. Interfaces interessiert, also an der Außensicht.

Personen, die den Code warten und weiterentwickeln müssen. Sie sind auch an den öffentlichen Programmierschnittstellen interessiert, aber vor allem auch an den privaten Schnittstellen und der internen Implementierung, also der Innensicht.

Beim Schreiben der Dokumentation sollte man immer davon ausgehen, dass der Leser zwar Java programmieren kann, sich aber nicht mit dem Code und den Zusammenhängen auskennt. Wenn die Software lange nicht mehr "angefasst" werden musste, kann das sogar der Autor der Software selbst sein, der sich anhand der Dokumentation wieder "hineindenken" muss.

In Java wird zwischen Dokumentationskommentaren (/**...**/) und Implementierungskommentaren (/*...*/, //) unterschieden.

4.3.1. Dokumentationskommentare (Javadoc)

Prinzipiell müssen alle Klassen, Interfaces und Methoden einen Dokumentationskommentar (eine Außensicht) enthalten. Ausnahmen sind im Einzelfall anonyme innere Klassen und ihre Methoden sowie Implementierungsklassen von Interfaces (dort mit @see auf die Interface-Dokumentation verweisen). Es wird empfohlen, je Package eine Datei package-info.java zu erzeugen, die das Zusammenspiel von Klassen/Interfaces in dem Package erläutert.

Für die Erstellung von Dokumentationskommentaren gelten die folgenden Regeln:

Alle Dokumentationskommentare werden einheitlich formatiert!

  • Schlüsselworte und Bezeichner im beschreibenden Text werden mit dem HTML-Tag <code> …​ </code> formatiert.

  • Programmcode wird im beschreibenden Text mit dem HTML-Tag <pre> …​ </pre> formatiert. Damit wird gewährleistet, dass eine Darstellung des Codes in "dicktengleicher Schrift" (Nichtproportionalschrift, Festbreitenschrift oder Monospaced Font) erfolgt und Einrückungen so wiedergegeben werden, wie sie beim Editieren eingegeben wurden. Es ist darauf zu achten, dass alle Leerzeichen berücksichtigt werden und kein automatischer Zeilenumbruch erfolgt.

  • Nicht mehr zu verwendende Konstrukte werden als @deprecated gekennzeichnet.

Beispiel:

/**
* Beschreibender Text für zu kommentierendes Element.
*
* @tag Beschreibender Text für dieses Tag
*/

Der erste Satz eines Dokumentationskommentars muss alleine stehen können!

Javadoc verwendet den ersten Satz in einer Beschreibung als Kurzbeschreibung des zu dokumentierenden Elements (Klasse, Schnittstelle, Methode, Attribut).

Javadoc Tags werden in einer einheitlichen Reihenfolge verwendet!

Jeder Parameter einer Methode wird mit einem @param-Tag beschrieben. Das @return-Tag wird nur verwendet, wenn der Rückgabewert der Methode ungleich void ist. Jede checked Exception, die in der throws-Klausel der Methode aufgeführt ist, wird mit einem @exception-Tag kommentiert.

Beispiel:

/**
* Beschreibung.
*
* @param
* @return
* @exception
*
* @see
* @since
* @deprecated
*/

Kommentare zu Attributen sehen zum Beispiel wie folgt aus:

/**
* Beschreibung.
*
* @see
* @since
* @deprecated
*/

@see-Tags sind sparsam zu verwenden, denn diese Verlinkung muss manuell gepflegt werden. Mehrere @see-Tags werden gemäß ihrer "Entfernung" von der aktuellen Stelle aufgeführt (Dokumenten-Navigation, Namensqualifikation). Innerhalb einer Gruppe überladener Methoden werden die Methoden gemäß der Anzahl Parameter aufgelistet.

Beispiel:

/**
* ...
* @see #field
* @see #Constructor()
* @see #Constructor(Type...)
* @see #method()
* @see #method(Type...)
* @see Class
* @see Class#field
* @see Class#Constructor()
* @see Class#Constructor(Type...)
* @see Class#method()
* @see Class#method(Type...)
* @see package.Class
* @see package.Class#field
* @see package.Class#Constructor()
* @see package.Class#Constructor(Type...)
* @see package.Class#method()
* @see package.Class#method(Type...)
* @see package
* @see <a href="URL#label">label</a>
* @see "String"
*/

Bei überschriebenen Methoden wird @inheritDoc nur verwendet, wenn Ergänzungen dokumentiert werden.

@inheritDoc sollte nur genutzt werden, wenn beim Überschreiben der Methode weitere Informationen im Javadoc gegenüber dem Parent ergänzt werden. Wenn die überschreibende Methode keine zusätzlichen Informationen im Javadoc mitgegeben bekommt, kann @inheritDoc weggelassen werden. Javadoc kopiert automatisch die Beschreibung des Parents, wenn keine Beschreibung angegeben wird.

Die Tags @author und @version werden nicht mehr verwendet.

Autoren (und damit Verantwortlichkeiten für Bestandteile des Quellcodes) sowie Details über die aktuelle Version werden über das verwendete Versionskontrollsystem ermittelt.

4.3.2. Implementierungskommentare

Code sollte immer selbsterklärend geschrieben werden und möglichst wenige Inline-Kommentare enthalten. Implementierungskommentare begründen Designentscheidungen, die aus dem Code nicht allein ersichtlich sind, oder sie erklären aufwändige Algorithmen. Sie wiederholen nicht den Code in Prosa (Negativbeispiel: "Erhöhe Schleifenzähler um 1"). Implementierungskommentare werden für folgende Zwecke eingesetzt:

  • Erklärung spezieller oder komplizierter Ausdrücke

  • Erläuterung von Designentscheidungen auf Code-Ebene

  • Quellenhinweise für komplexe Algorithmen

  • Erläuterung von Fehlerbehebungen und Workarounds

  • Hinweis auf Notwendigkeit zur Optimierung und Überarbeitung

  • Benennung bekannter Probleme und Limitierungen

  • Verzierungen (aus "*" gemalte Rechtecke oder Trennlinien) sind zu unterlassen.

Wenn eine Stelle im Code noch nicht fertig ist und später kontrolliert oder überarbeitet werden soll, so ist sie mit // TODO: Grund zu markieren. Einige Entwicklungsumgebungen wie z. B. Eclipse und IntelliJ zeigen diese speziellen Kommentare analog zu Fehlern in einer To-do-Liste an. Alle Kommentare sind in Englisch zu verfassen.

4.3.3. Änderungshistorie

Es wird immer der Ist-Zustand beschrieben. Änderungen werden in der Änderungshistorie beschrieben. Kommentare werden nicht dazu verwendet, alte Versionen des Codes zu deaktivieren. Wenn man alte Versionen wiederherstellen möchte, so ist dazu auf das Konfigurationsmanagement zurückzugreifen. Für die Analyse von Codeänderungen sind die bekannten DIFF-Werkzeuge einzusetzen.

Werkzeug, mit dem sich Unterschiede zwischen zwei Textdateien synoptisch darstellen lassen (diff unter Unix oder UltraEdit).

Änderungen werden mittels eines Version Control System (z. B. Subversion) nachverfolgt. Dazu ist es zwingend erforderlich, die durchgeführten Änderungen bzw. die Ursache dafür beim Check-in ausreichend zu dokumentieren. Die Dokumentationssprache hierfür ist deutsch. Darüber hinaus werden keine Versionsinformationen im Source Code gepflegt.

4.4. Codestruktur

4.4.1. Imports

Import-Statements werden nach Packages sortiert und gruppiert. Folgende Import-Statements sind zu vermeiden:

  • *-Importe

  • sun.*-Importe

  • redundante oder nicht genutzte Importe

4.4.2. Deklarationen in Klassen

  • Variablenbezeichner dürfen sich nicht überdecken. Zum Beispiel darf eine lokale Variable nicht genauso heißen wie ein Attribut der Klasse.

  • Lokale Variablen sind in dem Scope zu deklarieren, in dem sie auch verwendet werden.

  • Falls die Variable nicht selbsterklärend ist, wird sie mit einem kurzen einzeiligen Kommentar beschrieben.

4.4.3. Verwendung der Kurzschreibweisen

Seit Java 1.5 gibt es eine Kurzschreibweise für verschiedene Programmierkonstrukte (z. B. Bedingungen, Schleifen). Folgende Kurzschreibweisen sind erlaubt:

for (TYPE item : list) {
   ...
}

und

"..." + (VAR==null)?"DEFAULT":VAR

Letzteres ist erlaubt, sollte aber vermieden werden.

Nicht erlaubt ist die Kurzschreibweise für Bedingungen, also das Weglassen der Klammern:

if (COND)
  STATEMENT

4.4.4. equals() und hashCode()

Alle Klassen leiten sich von der Basisklasse Object ab und erben von dieser die Methoden equals(), hashCode(), toString(), clone() und finalize(). Diese Methoden sind bewusst als non-final Methoden angelegt, damit sie klassenspezifisch angepasst werden können.

Die von der Klasse Object vererbte Implementierung für die Methoden equals() und hashCode() stellt nur eine Basisimplementierung dar, die für alle Klassen genügt, deren Identität auf Objektgleichheit (gleiche Speicheradresse) basiert. Klassen, die eine eigene Identität, unabhängig von der Objektgleichheit, besitzen, müssen equals() und hashCode() implementieren. Dabei können leicht schwer identifizierbare Fehler auftreten. Die Implementierung von equals() und hashCode() ist nicht trivial, da sie bestimmte Eigenschaften (Reflexivity, Symmetry, Transitivity, Consistency und Non-nullity erfüllen müssen (siehe auch "Effective Java Second Edition" (Bloch, 2008) ).

Zur Implementierung von equals() und hashCode() müssen die Möglichkeiten der Hilfsklasse java.util.Objects verwendet werden, insbesondere die Methoden:

  • static boolean Objects.equals(Object a, Object b)

  • static int Objects.hash(Object…​ values)

4.5. Kryptographie

Kryptografische Verfahren basieren auf Zufallszahlen. Diese werden unter Linux standardmäßig durch dev/random erzeugt. Falls dev/random nicht genug Entropie vorliegt, blockiert es die Erzeugung neuer Zufallszahlen. Dadurch blockieren auch die kryptografischen Verfahren, welche z.B. die Kommunikation mit anderen Anwendungen oder einer Datenbank absichern.

Erzeugung von Zufallszahlen unter Linux

Zur Erzeugung von Zufallszahlen unter Linux wird dev/random verwendet. Falls dev/random zu oft blockiert und das Risiko, potenziell schwache Zufallszahlen zu verwenden, akzeptiert wird, kann alternativ dev/urandom verwendet werden.