Programmierrichtlinien für Java

Namensgebung

Namen für beginnen mit Beispiele
Konstanten Substantiv Kleinbuchstaben size, pwm, serialVersionUID
System-Konstanten PORTF, FPSCR, DDR, PI 1)
Variablen Substantiv Kleinbuchstaben version, wordSize
Adjektiv Kleinbuchstaben full, ready
Fuktionen Substantiv Kleinbuchstaben length()
Adjektiv Kleinbuchstaben full(), equal()2)
Methoden Verb Kleinbuchstaben drawLine()3)
Klassen Substantiv Grossbuchstaben File, FifoQueue, Stack
Pakete Substantiv Kleinbuchstaben java.io, ntb, target.ppc555

Namenslänge: Lokale, temporär verwendete Namen sollten kurz sein (z.B. m, k, len). Globale, wichtige Namen sollten sprechend, aber nicht zu lang sein (z.B. words, nofEntries).

Sprache: Wählen sie englische Namen. Sie sind meist kürzer als deutsche Namen und passen besser zu den englischen Schlüsselwörtern. Ausserdem können sie Programme mit englischen Namen leichter an Personen weitergeben, die kein Deutsch verstehen (z.B. über das Internet).

Worttrennung: Die Lesbarkeit von Namen, die aus mehreren Wörtern bestehen, wird durch entsprechende Gross-/Kleinschreibung (z.B. drawLine) verbessert, solche Bezeichner werden vom Leser rascher als Einheit erfasst und können besser von Parameterlisten unterschieden werden, als die Trennung mit Unterstrichen, z.B. draw_line. Die letztere Variante hat ihre Wurzeln in der Zeit, als die "Schnell-Drucker" nur Grossbuchstaben drucken konnten.

Kommentare

Kommentieren Sie, was nicht im Programm steht (und wichtig ist). Vermeiden Sie Kommentare, die nur das wiederholen, was man ohnehin aus dem Programmtext ablesen kann. Wählen Sie für Kommentare wennmöglich dieselbe Sprache wie für Namen im Programm. Aus den oben geschilderten Gründen sind englische Kommentare vorteilhaft. Verwenden Sie javadoc-konforme Kommentare für Klassen, Felder und Methoden, z.B.

/** A stack of integer.
  * Implements a LIFO data structure of fixed length, ....
  */
public class Stack {
  /** indicates stack overflow.
    * This flag may be checked after a push() operation.
    * If overflow == true, the parameter of the most recent push() operation was ignored.
    */
  public boolean overflow;
  ...
 
  /** pushes the value item onto the stack.
    * The overflow flag tells if the operation was successful.
    */
  public void push (int item) {...}
  ...
}

Verwenden Sie Trennkommentare zur Einleitung von Anweisungsfolgen, die eine bestimmte Aufgabe erfüllen, z.B.

//---- Read input array
In.open("input.txt");
int len = In.readInt();
int [] a = new int[len];
for(int i = 0; i < len; i++) a[i] = In.readInt();
 
//---- Invert array
invert(a);
 
//---- Print inverted array
for(int i = 0; i < len; i++) Out.print(a[i] + " ");
Out.println();

Halten Sie die Anweisungsfolgen einer Methode möglichst frei von Kommentaren. Jedesmal, wenn Sie einen Kommentar schreiben, sollten Sie sich überlegen, ob Sie nicht stattdessen das Programm vereinfachen oder bessere Namen wählen können, um dadurch den Kommentar zu vermeiden. Ein gutes Programm ist nicht eines, das möglichst viele Kommentare enthält, sondern eines, das möglichst wenige Kommentare benötigt. Falls Sie dennoch einmal einen Algorithmus ausführlich kommentieren wollen, tun Sie das im Kopfkommentar der Methoden und Klassen und nicht zwischen den einzelnen Anweisungen. Bei zu vielen Kommentaren zwischen den Anweisungen kann es sein, dass Sie das Programm vor lauter Kommentaren nicht mehr sehen.

Einrückungen

Verwenden Sie als Einrückungstiefe 1 Tabublatorzeichen oder 2 Leerzeichen. Zu tiefe Einrückungen sind genauso unleserlich wie zu wenig tiefe oder gar keine Einrückungen. Die folgenden Codemuster zeigen, wie Sie Programmkonstrukte einrücken sollten:

Anweisungen

if(cond) {
  ...
} else if(cond) {
  ...
} else {
  ...
}
switch(expr) {
  case c1:
    ...
  case c2:
    ...
  default:
    ...
}
try {
  ...
} catch(Exeption1 e) {
  ...
} finally {
  ...
}
while(cond) {
  ...
}
do {
  ...
} while(cond);
for(...) {
  ...
}

Klassen

class C {
  ... static fields (Klassenfelder) and class constructors ...
  ... instance fields (Instanzfelder) ...
  ... constructors ( (Objket-)Konstruktoren ) ...
  ... methods (Methoden) ...
}
 
==== Methoden ====
<code java>
public static int func() {
  ... declarations (Deklarationen) ...
  ... statements (Anweisungen) ....
}
 
Normalerweise sollten Sie jede Anweisung in eine eigene Zeile schreiben. Falls jedoch mehrere kurze Anweisungen zusammengehören und eine Einheit bilden, können Sie sie in die gleiche Zeile schreiben, z.B.
<code java>
p.next = head; head = p;
if (a > b) max = a; else max = b;

Auf diese Weise wird der Programmtext kürzer, was oft auch dazu führt, dass er besser überschaubar ist.

Programmkomplexität

Unter der (statischen) Komplexität eines Programms versteht man die Schwierigkeit, mit der man das Programm verstehen und warten kann. Es gibt verschiedene Komplexitätsmasse, auf die wir hier nicht näher eingehen können. Ein einfaches und überraschend gutes Komplexitätsmass ist die Anzahl der Zeilen (lines of code oder LOC) eines Programms oder einer Methode. Kurze Programme sind meist nicht nur effizienter, sondern auch leichter zu verstehen.

Eine Methode sollte keinesfalls länger als eine Bildschirmseite sein. Falls eine Methode länger ist, sollten Sie sie in kleinere Methoden zerlegen. Vermeiden Sie aber Extreme. Programme, die aus Hunderten von Methoden bestehen, die alle nur ein bis zwei Zeilen lang sind, sind ebenfalls schwer zu verstehen, weil der Leser ständig zwischen den einzelnen Methoden hin und her springen muss.

Um auch längere Methoden kompakt zu halten, sollten Sie keine überlangen Namen verwenden und Anweisungen, die zusammengehören, in die gleiche Zeile schreiben. Uebertreiben Sie aber nicht! Zu dichte Programme sind schwer zu lesen; zu kurze Namen wirken kryptisch.

Testhilfen

Moderne Programmierumgebungen verfügen meist über einen Debugger, der ihnen erlaubt, ein Programm Anweisung für Anweisung auszuführen und sich dazwischen die Werte der Variablen anzusehen. Trotz dieser bequemen Hilfe kann es nützlich sein, in ihr Programm Hilfsdrucke einzubauen, die ihnen zum Beispiel den Inhalt einer komplizierten Datenstruktur am Bildschirm oder noch besser auf eine Datei ausgeben. Hilfsdrucke sind kein Ersatz für einen Debugger, aber eine sinnvolle Ergänzung. Sie stellen Informationen kompakt und übersichtlich dar, wie Sie es mit einem Debugger kaum erreichen können.

Hilfsdrucke sollten auch nach dem Testen eines Programms nicht gelöscht werden. Sie können sie entweder auskommentieren oder noch besser mit einem Hilfsdrucke-Schalter ausblenden, z.B.

if (debug) {
  Out.println("-- contents of list:");
  Node p = head;
  while (p != null) {
    Out.println(p.val + " "); p = p.next;
  }
  Out.println();
}

Die Abfrage des Schalters debug kostet kaum Laufzeit und kann selbst in einem ausgetesteten und an den Kunden ausgelieferten Programm erhalten bleiben. Dies hat den Vorteil, dass man Hilfsdrucke beim Auftreten eines Fehlers jederzeit wieder aktivieren kann. Wenn Sie es so einrichten, dass der debug-Schalter per Kommandozeilenparameter gesetzt werden kann, brauchen Sie zum Einschalten das Programm nicht einmal neu zu übersetzen.

Natürlich ist es auch möglich mehrere verschiedene solcher debug-Schalter anzulegen. Damit ist esmöglich, je nach Art des Problems die Hilfsdrucke auszuwählen, was die Zeit für die Problemanalysewesentlich verkürzen kann.

Hat das Programm die geforderte Qualität erreicht, können diese debug-Schalter als Konstanten deklariert werden. Damit sieht der Compiler, dass diese Anweisungen in keinem Fall mehr durchlaufen werden und wird deshalb die Schalter-Abfrage wie auch die entsprechenden Anweisungen nicht mehr übersetzen. D.h. Hilfsdrucke in ihrem Programm belegen weder Platz im Arbeitsspeicher des ausführenden Rechners, noch benötigen sie wertvolle Ausführungszeit:

Deklaration der Schalter während der Test- und Integrationszeit:

public static boolean dbgN = true;

Deklaration der Schalter nach der Test- und Integrationszeit:

public static final boolean dbgN = false;

Plausibilitätsprüfungen

Wenn ein Programm an einer bestimmten Stelle Annhamen über Parameterwerte oder deren Zustand von Datenstrukturen macht, dann sollten diese Annahmen auch überprüft werden. Java bietet zu diesem Zweck die assert-Anweisung an.

assert x >= 0 && x <= 100;

oder

assert x >= 0 && x <= 100: "x is out of range [0..100]";

Aehnlich wie Hilfsdrucke sollten auch assert-Anweisungen nicht nur beim Testen verwendet werden, sondern auch in fertigen Programmen enthalten bleiben. Die Prüfungen werden ja nur ausgeführt, wenn man seine Programme mit der Option -enableassertions ausführt, und kosten dahre kaum Laufzeit.

Sie werden staunen, wie oft diese Plausibilitätsprüfungen Fehler selbst in ausführlich getesteten Programmen aufdecken. Plausibilitätsprüfungen helfen, Fehler frühzeitig aufzudecken und nicht erst dann, wenn sie sich fortgepflanzt haben und sich an ganz anderer Stelle im Programm auswirken.

Man nennt diesen Programmierstil defensives Programmieren. Ein Programmierer kann nie vorsichtig genug sein. Selbst erfahrene Programmierer machen Fehler, die oft beim Testen nicht entdeckt werden und erst im Betrieb eines Programms zum Vorschein kommen. Plausibilitätsprüfungen schaffen ein ruhiges Gewissen. Sie wirken wie "Wachhunde" im Programm, die sicherstellen, dass die Annahmen des Programmierers auch wirklich immer gelten.

1) Konstanten aus Reference-, User- Manuals, etc. werden wenn möglich so übernommen, wie sie in diesen Quellen festgelegt sind, es sei denn, sie widersprechen der Java-Syntax. Wichtig ist, dass man diese rechnerunterstützt, case-sensitive (Ctrl-F) suchen kann.
2) Name bezeichnet Fuktionswert
3) Imperativ