In diesem Artikel werden einige typische Fehler aufgeführt, die ich im Java-Code meiner Kollegen sehe. Offensichtlich kann die statische Codeanalyse (unser Team verwendet Qulice) nicht alle Probleme finden, weshalb ich sie hier aufführe.
Wenn Sie der Meinung sind, dass etwas fehlt, lassen Sie es mich bitte wissen und ich werde es gerne hinzufügen.
Alle unten aufgeführten Fehler hängen im Wesentlichen mit der objektorientierten Programmierung zusammen, insbesondere mit Javas OOP.
Klassenname
Lesen Sie diesen kurzen Artikel „Was sind Objekte“. Eine Klasse sollte im wirklichen Leben eine abstrakte Entität sein, keine „Validatoren“, „Controller“ und „Manager“. Wenn Ihr Klassenname mit „er“ endet, handelt es sich um ein schlechtes Design.
Natürlich sind Tool-Klassen auch Anti-Patterns, wie zum Beispiel StringUtils, FileUtils und IOUtils von Apache. All das sind Beispiele für schlechtes Design. Weiterführende Literatur: Alternativen zu Werkzeugklassen in OOP.
Verwenden Sie natürlich keine Präfixe oder Suffixe, um Klassen von Schnittstellen zu unterscheiden. Diese Namen sind beispielsweise falsch: IRecord, IfaceEmployee oder RecordInterface. Im Allgemeinen sollte der Schnittstellenname der Name der realen Entität sein und der Klassenname sollte die Implementierungsdetails beschreiben. Wenn die Implementierung nichts Besonderes ist, können Sie sie Default, Simple oder ähnlich nennen. Zum Beispiel:
Kopieren Sie den Codecode wie folgt:
Klasse SimpleUser implementiert User {};
Klasse DefaultRecord implementiert Record {};
Klasse mit Suffix implementiert Name {};
Klasse Validated implementiert Content {};
Methodenname
Methoden können Werte zurückgeben oder ungültig machen. Wenn eine Methode einen Wert zurückgibt, sollte ihr Name beispielsweise beschreiben, was sie zurückgibt (verwenden Sie niemals das Präfix get):
Kopieren Sie den Codecode wie folgt:
boolean isValid(String name);
String-Inhalt();
int ageOf(File file);
Wenn es „void“ zurückgibt, sollte sein Name erklären, was es tut. Zum Beispiel:
Kopieren Sie den Codecode wie folgt:
void save(File file);
ungültiger Prozess(Arbeitsarbeit);
void append(File file, String line);
Von den gerade genannten Regeln gibt es nur eine Ausnahme: Die Testmethode von JUnit zählt nicht. Dies wird weiter unten besprochen.
Der Name der Testmethode
In JUnit-Testfällen sollte der Methodenname eine englische Anweisung ohne Leerzeichen sein. Anhand eines Beispiels wird es deutlicher:
Kopieren Sie den Codecode wie folgt:
/**
* HttpRequest kann seinen Inhalt in Unicode zurückgeben.
* @throws-Ausnahme, wenn der Test fehlschlägt
*/
public void returnsItsContentInUnicode() löst eine Ausnahme aus {
}
Der erste Satz in Ihrem JavaDoc sollte mit dem Namen der Klasse beginnen, die Sie testen möchten, gefolgt von can. Daher sollte Ihr erster Satz etwa lauten: „Jemand kann etwas tun.“
Der Methodenname ist ebenfalls derselbe, nur ohne das Thema. Wenn ich in der Mitte des Methodennamens ein Subjekt hinzufüge, erhalte ich einen vollständigen Satz, wie im obigen Beispiel: „HttpRequest gibt seinen Inhalt in Unicode zurück“.
Bitte beachten Sie, dass der Name der Testmethode nicht mit can beginnt. Nur Kommentare in JavaDoc beginnen mit can. Darüber hinaus sollten Methodennamen nicht mit einem Verb beginnen.
In der Praxis ist es am besten, die Testmethode so zu deklarieren, dass sie eine Ausnahme auslöst.
Variablenname
Vermeiden Sie die Kombination von Variablennamen wie timeOfDay, firstItem oder httpRequest. Dies gilt für Klassenvariablen und Variablen innerhalb von Methoden. Variablennamen sollten lang genug sein, um Mehrdeutigkeiten innerhalb ihres sichtbaren Bereichs zu vermeiden, aber nach Möglichkeit nicht zu lang. Der Name sollte ein Substantiv im Singular oder Plural oder eine entsprechende Abkürzung sein. Zum Beispiel:
Kopieren Sie den Codecode wie folgt:
List<String>-Namen;
void sendThroughProxy(File file, Protocol proto);
privater Dateiinhalt;
öffentliche HttpRequest-Anfrage;
Wenn der Konstruktor die Eingabeparameter in einem neu initialisierten Objekt speichert, kann es manchmal zu Konflikten zwischen den Namen seiner Parameter und Klassenattributen kommen. In diesem Fall schlage ich vor, die Vokale zu entfernen und Abkürzungen zu verwenden.
Beispiel:
Kopieren Sie den Codecode wie folgt:
öffentliche Klassennachricht {
privater String-Empfänger;
öffentliche Nachricht(String rcpt) {
this.recipient = rcpt;
}
}
Oft können Sie anhand des Klassennamens erkennen, welchen Namen die Variable erhalten soll. Verwenden Sie einfach die Kleinbuchstabenform, die wie folgt zuverlässig ist:
Kopieren Sie den Codecode wie folgt:
Dateidatei;
Benutzerbenutzer;
Zweigniederlassung;
Sie sollten dies jedoch niemals mit primitiven Typen wie Integer-Zahlen oder String-Strings tun.
Wenn es mehrere Variablen unterschiedlicher Art gibt, sollten Sie die Verwendung von Adjektiven in Betracht ziehen. Zum Beispiel:
Kopieren Sie den Codecode wie folgt:
String-Kontakt (String links, String rechts);
Konstrukteur
Abgesehen von Ausnahmen sollte nur ein Konstruktor zum Speichern von Daten in Objektvariablen verwendet werden. Andere Konstruktoren rufen diesen Konstruktor mit anderen Parametern auf. Zum Beispiel:
Kopieren Sie den Codecode wie folgt:
öffentliche Klasse Server {
private String-Adresse;
öffentlicher Server(String uri) {
this.address = uri;
}
öffentlicher Server(URI uri) {
this(uri.toString());
}
}
einmalige Variable
Wegwerfbare Variablen sollten unbedingt vermieden werden. Mit „einmalig“ meine ich hier eine Variable, die nur einmal verwendet wird. Zum Beispiel dieses hier:
Kopieren Sie den Codecode wie folgt:
Stringname = „data.txt“;
neue Datei (Name) zurückgeben;
Die oben genannten Variablen werden nur einmal verwendet, daher kann dieser Code wie folgt umstrukturiert werden:
Kopieren Sie den Codecode wie folgt:
return new File("data.txt");
Manchmal, in seltenen Fällen – vor allem für eine bessere Formatierung – können Einwegvariablen verwendet werden. Dies sollte jedoch möglichst vermieden werden.
abnormal
Es versteht sich von selbst, dass Sie niemals selbst eine Ausnahme schlucken sollten, sondern sie so weit wie möglich weitergeben sollten. Private Methoden sollten immer geprüfte Ausnahmen auslösen.
Verwenden Sie keine Ausnahmen zur Flusskontrolle. Beispielsweise ist der folgende Code falsch:
Kopieren Sie den Codecode wie folgt:
int-Größe;
versuchen {
size = this.fileSize();
} Catch (IOException ex) {
Größe = 0;
}
Was sollten Sie also tun, wenn IOException die Meldung „Datenträger ist voll“ meldet? Würden Sie immer noch davon ausgehen, dass die Dateigröße 0 beträgt, und mit der Verarbeitung fortfahren?
Vertiefung
Beim Einrücken gilt vor allem, dass die öffnende Klammer entweder am Ende der Zeile endet oder in derselben Zeile geschlossen wird (das Gegenteil gilt für schließende Klammern). Folgendes ist beispielsweise falsch, da die erste öffnende Klammer nicht in derselben Zeile geschlossen wird und weitere Zeichen dahinter stehen. Auch die zweite Klammer ist problematisch, da ihr Zeichen vorangestellt sind, die entsprechende öffnende Klammer jedoch nicht in derselben Zeile steht:
Kopieren Sie den Codecode wie folgt:
finale Datei file = neue Datei(Verzeichnis,
"file.txt");
Die korrekte Einrückung sollte so aussehen:
Kopieren Sie den Codecode wie folgt:
StringUtils.join(
Arrays.asList(
„erste Zeile“,
„zweite Zeile“,
StringUtils.join(
Arrays.asList("a", "b")
)
),
"Separator"
);
Die zweite wichtige Regel zum Einrücken ist, dass man versuchen sollte, möglichst viele Zeichen gleichzeitig in eine Zeile zu schreiben – die Obergrenze liegt bei 80 Zeichen. Das obige Beispiel erfüllt diesen Punkt nicht, es kann auch verkleinert werden:
Kopieren Sie den Codecode wie folgt:
StringUtils.join(
Arrays.asList(
„erste Zeile“, „zweite Zeile“,
StringUtils.join(Arrays.asList("a", "b"))
),
"Separator"
);
redundante Konstanten
Klassenkonstanten sollten verwendet werden, wenn Sie Informationen innerhalb der Methoden einer Klasse teilen möchten. Die Informationen sollten für Ihre Klasse eindeutig sein. Verwenden Sie keine Konstanten als Ersatz für Zeichenfolgen- oder numerische Literale – dies ist eine sehr schlechte Praxis und wird Ihren Code verunreinigen. Konstanten (wie jedes Objekt in OOP) sollten in der realen Welt ihre eigene Bedeutung haben. Sehen wir uns an, was diese Konstanten im wirklichen Leben bedeuten:
Kopieren Sie den Codecode wie folgt:
Klasse Dokument {
private static final String D_LETTER = "D"; // schlechte Praxis
private static final String EXTENSION = ".doc"; // gute Praxis
}
Ein weiterer häufiger Fehler besteht darin, in Komponententests Konstanten zu verwenden, um redundante Zeichenfolgen oder numerische Literale in Testmethoden zu vermeiden. Tun Sie dies nicht! Jede Testmethode sollte ihre eigenen eindeutigen Eingabewerte haben.
Verwenden Sie in jeder neuen Testmethode neuen Text oder Werte. Sie sind unabhängig voneinander. Warum haben sie also immer noch dieselben Eingabekonstanten?
Testdatenkopplung
Hier ist ein Beispiel für die Datenkopplung in einer Testmethode:
Kopieren Sie den Codecode wie folgt:
Benutzer user = neuer Benutzer("Jeff");
// vielleicht ein anderer Code hier
MatcherAssert.assertThat(user.name(), Matchers.equalTo("Jeff"));
In der letzten Zeile ist „Jeff“ an dasselbe String-Literal in der ersten Zeile gekoppelt. Wenn nach ein paar Monaten jemand den Wert in der dritten Zeile ändern möchte, muss er Zeit damit verbringen, herauszufinden, wo „Jeff“ in derselben Methode auch verwendet wird.
Um dies zu vermeiden, führen Sie besser eine Variable ein.