Code Review in Java: Was prüfen und wie man Feedback in der Praxis gibt
\n\nCode Review (Code-Überprüfung) ist die systematische Prüfung fremden Codes, um Fehler zu erkennen, die Qualität zu verbessern und Wissen auszutauschen. In der Java-Entwicklung ist dies aufgrund der strengen Typisierung, der Besonderheiten der Nebenläufigkeit und der Leistungsanforderungen besonders wichtig. Viele Entwickler reduzieren das Review jedoch auf eine einfache Stilprüfung oder verwandeln es im Gegenteil in toxische Kritik. In diesem Artikel gehen wir darauf ein, was genau in Java-Code geprüft werden sollte und wie man Feedback gibt, das nützt und nicht verletzt.
\n\n1. Was in Java-Code prüfen: Eine Checkliste für den Reviewer
\n\nDamit ein Review effektiv ist, sollte man nicht nur auf die Syntax, sondern auch auf Architektur, Sicherheit und Leistung achten. Hier sind die wichtigsten Kategorien, die es zu prüfen gilt.
\n\n1.1 Architektur und Design
\n- \n
- SOLID-Prinzipien: Verstößt die Klasse gegen das Prinzip der einzigen Verantwortung? Wird das Interface zu einem „göttlichen Objekt“? \n
- Kopplung und Kohäsion: Klassen sollten lose gekoppelt (loose coupling) und hoch kohäsiv (high cohesion) sein. \n
- Verwendung von Entwurfsmustern: Ist die Anwendung komplexer Muster gerechtfertigt? Manchmal ist ein einfaches if-else besser als eine Factory mit einem Dutzend Klassen. \n
// Schlecht: Klasse macht alles auf einmal\npublic class ReportService {\n public void generateReport() { /* Generierung */ }\n public void sendEmail() { /* Versand */ }\n public void saveToDatabase() { /* Speicherung */ }\n}\n\n// Gut: Trennung der Verantwortlichkeiten\npublic class ReportGenerator { ... }\npublic class EmailSender { ... }\npublic class ReportRepository { ... }\n\n\n1.2 Ausnahmebehandlung und Fehler
\n- \n
- Unterdrückung von Ausnahmen: Ein leerer
catch (Exception e)ist nicht erlaubt – das verbirgt Fehler. \n - Spezifität: Fangen Sie spezifische Ausnahmen, nicht
ExceptionoderThrowable. \n - Protokollierung: Ausnahmen sollten mit ausreichend Kontext protokolliert werden (Stacktrace, Eingabedaten). \n
// Schlecht: Ausnahme verschlucken\ntry {\n processFile(file);\n} catch (Exception e) {\n // nichts tun\n}\n\n// Gut: Protokollierung und Weiterwerfen\ntry {\n processFile(file);\n} catch (IOException e) {\n log.error("Fehler bei der Dateiverarbeitung: {}", file, e);\n throw new ProcessingException("Datei konnte nicht verarbeitet werden", e);\n}\n\n\n1.3 Leistung und Speicher
\n- \n
- Überflüssige Operationen: Objekterstellung in Schleifen, unnötige String-Kopien mit
new String(). \n - Verwendung von Collections: Ist der Typ richtig gewählt (ArrayList vs. LinkedList)? Gibt es unnötige Synchronisationen? \n
- Stream API: Verschlechtert der Stream die Lesbarkeit? Manchmal ist eine normale Schleife verständlicher. \n
// Schlecht: String-Erstellung in einer Schleife\nString result = "";\nfor (String s : list) {\n result += s; // jedes Mal ein neuer String\n}\n\n// Gut: StringBuilder\nStringBuilder sb = new StringBuilder();\nfor (String s : list) {\n sb.append(s);\n}\n\n\n1.4 Nebenläufigkeit und Synchronisation
\n- \n
- Korrekte Verwendung von synchronized: Ist ein zu großer Codeblock gesperrt? \n
- Concurrent Collections: Verwenden Sie
ConcurrentHashMapanstelle einer Hashtabelle mit externer Synchronisation? \n - Deadlock-Gefahr: Werden Ressourcen in unterschiedlicher Reihenfolge gesperrt? \n
// Deadlock-Risiko\nsynchronized (lockA) {\n synchronized (lockB) { ... }\n}\n// In einem anderen Thread:\nsynchronized (lockB) {\n synchronized (lockA) { ... }\n}\n\n\n2. Wie man Code für ein einfaches Review schreibt
\n\nEin gutes Review beginnt mit gutem Code. U