Dipl.-Inform. Michael Inden ist Oracle-zertifizierter Java-Entwickler. Nach seinem Studium in Oldenburg hat er bei diversen internationalen Firmen in verschiedenen Rollen etwa als Softwareentwickler, -architekt, Consultant, Teamleiter, CTO sowie Leiter Academy gearbeitet. Zurzeit ist er freiberuflich als Autor und Trainer in Zürich tätig.
Michael Inden hat über zwanzig Jahre Berufserfahrung beim Entwurf komplexer Softwaresysteme gesammelt, an diversen Fortbildungen und mehreren Java-One-Konferenzen teilgenommen. Sein besonderes Interesse gilt dem Design qualitativ hochwertiger Applikationen sowie dem Coaching. Sein Wissen gibt er gerne als Trainer in internen und externen Schulungen und auf Konferenzen weiter, etwa bei der JAX/W-JAX, JAX London, Oracle Code One, ch.open sowie bei der Java User Group Switzerland.
Zu diesem Buch – sowie zu vielen weiteren dpunkt.büchern – können Sie auch das entsprechende E-Book im PDF-Format herunterladen. Werden Sie dazu einfach Mitglied bei dpunkt.plus+: www.dpunkt.plus |
Konzepte und Techniken für die
professionelle Java-Entwicklung
5., überarbeitete und aktualisierte Auflage
Michael Inden
michael_inden@hotmail.com
Lektorat: Dr. Michael Barabas
Projektkoordinierung/Lektoratsassistenz: Anja Weimer
Fachgutachten: Torsten Horn, Aachen
Copy-Editing: Ursula Zimpfer, Herrenberg
Satz: Michael Inden
Herstellung: Stefanie Weidner
Umschlaggestaltung: Helmut Kraus, www.exclam.de
Bibliografische Information der Deutschen Nationalbibliothek
Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.
ISBN:
Print 978-3-86490-707-4
PDF 978-3-96088-842-0
ePub 978-3-96088-843-7
mobi 978-3-96088-844-4
5., überarbeitete und aktualisierte Auflage 2021
Copyright © 2021 dpunkt.verlag GmbH
Wieblinger Weg 17
69123 Heidelberg
Hinweis:
Der Umwelt zuliebe verzichten wir auf die Einschweißfolie.
Schreiben Sie uns:
Falls Sie Anregungen, Wünsche und Kommentare haben, lassen Sie es unswissen: hallo@dpunkt.de.
Die vorliegende Publikation ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Verwendung der Texte und Abbildungen, auch auszugsweise, ist ohne die schriftliche Zustimmung des Verlags urheberrechtswidrig und daher strafbar. Dies gilt insbesondere für die Vervielfältigung, Übersetzung oder die Verwendung in elektronischen Systemen.
Es wird darauf hingewiesen, dass die im Buch verwendeten Soft- und Hardware-Bezeichnungen sowie Markennamen und Produktbezeichnungen der jeweiligen Firmen im Allgemeinen warenzeichen-, marken- oder patentrechtlichem Schutz unterliegen.
Alle Angaben und Programme in diesem Buch wurden mit größter Sorgfalt kontrolliert. Weder Autor noch Verlag können jedoch für Schäden haftbar gemacht werden, die in Zusammenhang mit der Verwendung dieses Buches stehen.
5 4 3 2 1 0
1Einleitung
IJava-Grundlagen, Analyse und Design
2Professionelle Arbeitsumgebung
3Objektorientiertes Design
4Lambdas, Methodenreferenzen und Defaultmethoden
5Java-Grundlagen
IIBausteine stabiler Java-Applikationen
6Das Collections-Framework
7Das Stream-API
8Datumsverarbeitung seit JDK 8
9Applikationsbausteine
10Multithreading-Grundlagen
11Modern Concurrency
12Fortgeschrittene Java-Themen
13Basiswissen Internationalisierung
IIIWichtige Neuerungen in Java 12 bis 15
14Neues und Änderungen in den Java-Versionen 12 bis 15
IVModularisierung
15Modularisierung mit Project Jigsaw
VFallstricke und Lösungen im Praxisalltag
16Bad Smells
17Refactorings
18Entwurfsmuster
VIQualitätssicherungsmaßnahmen
19Programmierstil und Coding Conventions
20Unit Tests
21Codereviews
22Optimierungen
23Schlussgedanken
VIIAnhang
AGrundlagen zur Java Virtual Machine
Literaturverzeichnis
Index
1Einleitung
1.1Über dieses Buch
1.1.1Motivation
1.1.2Was leistet dieses Buch und was nicht?
1.1.3Wie und was soll mithilfe des Buchs gelernt werden?
1.1.4Wer sollte dieses Buch lesen?
1.2Aufbau des Buchs
1.3Konventionen und ausführbare Programme
IJava-Grundlagen, Analyse und Design
2Professionelle Arbeitsumgebung
2.1Vorteile von IDEs am Beispiel von Eclipse
2.2Projektorganisation
2.2.1Projektstruktur in Eclipse
2.2.2Projektstruktur für Maven und Gradle
2.3Einsatz von Versionsverwaltungen
2.3.1Arbeiten mit zentralen Versionsverwaltungen
2.3.2Dezentrale Versionsverwaltungen
2.3.3VCS und DVCS im Vergleich
2.4Einsatz eines Unit-Test-Frameworks
2.4.1Das JUnit-Framework
2.4.2Parametrierte Tests mit JUnit 5
2.4.3Vorteile von Unit Tests
2.5Debugging
2.5.1Fehlersuche mit einem Debugger
2.5.2Remote Debugging
2.6Deployment von Java-Applikationen
2.6.1Das JAR-Tool im Kurzüberblick
2.6.2JAR inspizieren und ändern, Inhalt extrahieren
2.6.3Metainformationen und das Manifest
2.6.4Inspizieren einer JAR-Datei
2.7Einsatz eines IDE-unabhängigen Build-Prozesses
2.7.1Maven im Überblick
2.7.2Builds mit Gradle
2.7.3Vorteile von Maven und Gradle
2.8Weiterführende Literatur
3Objektorientiertes Design
3.1OO-Grundlagen
3.1.1Grundbegriffe
3.1.2Beispielentwurf: Ein Zähler
3.1.3Vom imperativen zum objektorientierten Entwurf
3.1.4Diskussion der OO-Grundgedanken
3.1.5Wissenswertes zum Objektzustand
3.2Grundlegende OO-Techniken
3.2.1Schnittstellen (Interfaces)
3.2.2Basisklassen und abstrakte Basisklassen
3.2.3Interfaces und abstrakte Basisklassen
3.3Wissenswertes zu Vererbung
3.3.1Probleme durch Vererbung
3.3.2Delegation statt Vererbung
3.4Fortgeschrittenere OO-Techniken
3.4.1Read-only-Interface
3.4.2Immutable-Klasse
3.4.3Marker-Interface
3.4.4Konstantensammlungen und Aufzählungen
3.4.5Value Object (Data Transfer Object)
3.5Prinzipien guten OO-Designs
3.5.1Geheimnisprinzip nach Parnas
3.5.2Law of Demeter
3.5.3SOLID-Prinzipien
3.6Formen der Varianz
3.6.1Grundlagen der Varianz
3.6.2Kovariante Rückgabewerte
3.7Generische Typen (Generics)
3.7.1Einführung
3.7.2Generics und Auswirkungen der Type Erasure
3.8Weiterführende Literatur
4Lambdas, Methodenreferenzen und Defaultmethoden
4.1Einstieg in Lambdas
4.1.1Syntax von Lambdas
4.1.2Functional Interfaces und SAM-Typen
4.1.3Exceptions in Lambdas
4.2Syntaxerweiterungen in Interfaces
4.2.1Defaultmethoden
4.2.2Statische Methoden in Interfaces
4.3Methodenreferenzen
4.4Externe vs. interne Iteration
4.5Wichtige Functional Interfaces für Collections
4.5.1Das Interface Predicate<T>
4.5.2Das Interface UnaryOperator<T>
4.6Praxiswissen: Definition von Lambdas
5Java-Grundlagen
5.1Die Klasse Object
5.1.1Die Methode toString()
5.1.2Die Methode equals()
5.2Primitive Typen und Wrapper-Klassen
5.2.1Grundlagen
5.2.2Konvertierung von Werten
5.2.3Wissenswertes zu Auto-Boxing und Auto-Unboxing
5.2.4Ausgabe und Verarbeitung von Zahlen
5.3Stringverarbeitung
5.3.1Die Klasse String
5.3.2Die Klassen StringBuffer und StringBuilder
5.3.3Ausgaben mit format() und printf()
5.3.4Die Methode split() und reguläre Ausdrücke
5.3.5Optimierung bei Strings in JDK 9
5.3.6Neue Methoden in der Klasse String in JDK 11
5.4Varianten innerer Klassen
5.5Ein- und Ausgabe (I/O)
5.5.1Dateibehandlung und die Klasse File
5.5.2Ein- und Ausgabestreams im Überblick
5.5.3Zeichencodierungen bei der Ein- und Ausgabe
5.5.4Speichern und Laden von Daten und Objekten
5.5.5Dateiverarbeitung mit dem NIO
5.5.6Neue Hilfsmethoden in der Klasse Files in JDK 11
5.6Fehlerbehandlung
5.6.1Einstieg in die Fehlerbehandlung
5.6.2Checked Exceptions und Unchecked Exceptions
5.6.3Besonderheiten beim Exception Handling
5.6.4Exception Handling und Ressourcenfreigabe
5.6.5Assertions
5.7Weitere Neuerungen in JDK 9, 10 und 11
5.7.1Erweiterung der @Deprecated-Annotationin JDK 9
5.7.2Syntaxerweiterung var in JDK 10 und 11
5.7.3Versionsverarbeitung mit JDK 9 und 10
5.8Weiterführende Literatur
IIBausteine stabiler Java-Applikationen
6Das Collections-Framework
6.1Datenstrukturen und Containerklassen
6.1.1Wahl einer geeigneten Datenstruktur
6.1.2Arrays
6.1.3Das Interface Collection
6.1.4Das Interface Iterator
6.1.5Listen und das Interface List
6.1.6Mengen und das Interface Set
6.1.7Grundlagen von hashbasierten Containern
6.1.8Grundlagen automatisch sortierender Container
6.1.9Die Methoden equals(), hashCode() und compareTo() im Zusammenspiel
6.1.10Schlüssel-Wert-Abbildungen und das Interface Map
6.1.11Erweiterungen am Beispiel der Klasse HashMap
6.1.12Erweiterungen im Interface Map in JDK 8
6.1.13Collection-Factory-Methoden in JDK 9
6.1.14Unveränderliche Kopien von Collections mit Java 10
6.1.15Entscheidungshilfe zur Wahl von Datenstrukturen
6.2Suchen und Sortieren
6.2.1Suchen
6.2.2Sortieren von Arrays und Listen
6.2.3Sortieren mit Komparatoren
6.2.4Erweiterungen im Interface Comparator mit JDK 8
6.3Utility-Klassen und Hilfsmethoden
6.3.1Nützliche Hilfsmethoden
6.3.2Dekorierer synchronized und unmodifiable
6.3.3Vordefinierte Algorithmen in der Klasse Collections
6.4Containerklassen: Generics und Varianz
6.5Die Klasse Optional<T>
6.5.1Grundlagen zur Klasse Optional
6.5.2Weiterführendes Beispiel und Diskussion
6.5.3Verkettete Methodenaufrufe
6.5.4Erweiterungen in der Klasse Optional<T> in JDK 9
6.5.5Erweiterung in Optional<T> in JDK 10 und 11
6.6Fallstricke im Collections-Framework
6.6.1Wissenswertes zu Arrays
6.6.2Wissenswertes zu Stack, Queue und Deque
6.7Weiterführende Literatur
7Das Stream-API
7.1Grundlagen zu Streams
7.1.1Streams erzeugen – Create Operations
7.1.2Intermediate und Terminal Operations im Überblick
7.1.3Zustandslose Intermediate Operations
7.1.4Zustandsbehaftete Intermediate Operations
7.1.5Terminal Operations
7.1.6Wissenswertes zur Parallelverarbeitung
7.1.7Neuerungen im Stream-API in JDK 9
7.1.8Neuerungen im Stream-API in JDK 10
7.2Filter-Map-Reduce
7.2.1Herkömmliche Realisierung
7.2.2Filter-Map-Reduce mit JDK 8
7.3Praxisbeispiele
7.3.1Aufbereiten von Gruppierungen und Histogrammen
7.3.2Maps nach Wert sortieren
8Datumsverarbeitung seit JDK 8
8.1Überblick über die neu eingeführten Typen
8.1.1Neue Aufzählungen, Klassen und Interfaces
8.1.2Die Aufzählungen DayOfWeek und Month
8.1.3Die Klassen MonthDay, YearMonth und Year
8.1.4Die Klasse Instant
8.1.5Die Klasse Duration
8.1.6Die Aufzählung ChronoUnit
8.1.7Die Klassen LocalDate, LocalTime und LocalDateTime
8.1.8Die Klasse Period
8.1.9Die Klasse ZonedDateTime
8.1.10Zeitzonen und die Klassen ZoneId und ZoneOffset
8.1.11Die Klasse Clock
8.1.12Formatierung und Parsing
8.2Datumsarithmetik
8.2.1Einstieg in die Datumsarithmetik
8.2.2Real-World-Example: Gehaltszahltag
8.3Interoperabilität mit Legacy-Code
9Applikationsbausteine
9.1Einsatz von Bibliotheken
9.2Google Guava im Kurzüberblick
9.2.1String-Aktionen
9.2.2Stringkonkatenation und -extraktion
9.2.3Erweiterungen für Collections
9.2.4Weitere Utility-Funktionalitäten
9.3Wertebereichs- und Parameterprüfungen
9.4Logging-Frameworks
9.4.1Apache log4j2
9.4.2Tipps und Tricks zum Einsatz von Logging mit log4j2
9.5Konfigurationsparameter und -dateien
9.5.1Einlesen von Kommandozeilenparametern
9.5.2Verarbeitung von Properties
9.5.3Weitere Möglichkeiten zur Konfigurationsverwaltung
10Multithreading-Grundlagen
10.1Threads und Runnables
10.1.1Definition der auszuführenden Aufgabe
10.1.2Start, Ausführung und Ende von Threads
10.1.3Lebenszyklus von Threads und Thread-Zustände
10.1.4Unterbrechungswünsche durch Aufruf von interrupt()
10.2Zusammenarbeit von Threads
10.2.1Konkurrierende Datenzugriffe
10.2.2Locks, Monitore und kritische Bereiche
10.2.3Deadlocks und Starvation
10.2.4Kritische Bereiche und das Interface Lock
10.3Kommunikation von Threads
10.3.1Kommunikation mit Synchronisation
10.3.2Kommunikation über die Methoden wait(), notify() und notifyAll()
10.3.3Abstimmung von Threads
10.3.4Unerwartete IllegalMonitorStateExceptions
10.4Das Java-Memory-Modell
10.4.1Sichtbarkeit
10.4.2Atomarität
10.4.3Reorderings
10.5Besonderheiten bei Threads
10.5.1Verschiedene Arten von Threads
10.5.2Exceptions in Threads
10.5.3Sicheres Beenden von Threads
10.6Weiterführende Literatur
11Modern Concurrency
11.1Concurrent Collections
11.1.1Thread-Sicherheit und Parallelität mit »normalen« Collections
11.1.2Parallelität mit den Concurrent Collections
11.1.3Blockierende Warteschlangen und das Interface Blocking-Queue<E>
11.2Das Executor-Framework
11.2.1Einführung
11.2.2Definition von Aufgaben
11.2.3Parallele Abarbeitung im ExecutorService
11.3Das Fork-Join-Framework
11.3.1Einführendes Beispiel
11.3.2Real-World-Example: Merge Sort
11.4Die Klasse CompletableFuture<T>
11.4.1Einführung
11.4.2Beispiel: Parallele Verarbeitung von Dateiinhalten
11.4.3Erweiterungen in JDK 9
11.4.4Beispiel: Von synchron zu mutlithreaded
11.5Reactive Streams und die Klasse Flow
11.5.1Schnelleinstieg Reactive Streams
11.5.2Reactive Streams im JDK
11.5.3Beispiel zur Klasse Flow
11.5.4Fazit
11.6Weiterführende Literatur
12Fortgeschrittene Java-Themen
12.1Crashkurs Reflection
12.1.1Grundlagen
12.1.2Zugriff auf Methoden und Attribute
12.1.3Spezialfälle
12.1.4Type Erasure und Typinformationen bei Generics
12.1.5Fazit
12.2Annotations
12.2.1Einführung in Annotations
12.2.2Standard-Annotations des JDKs
12.2.3Definition eigener Annotations
12.2.4Annotations zur Laufzeit auslesen
12.3Serialisierung
12.3.1Grundlagen der Serialisierung
12.3.2Die Serialisierung anpassen
12.3.3Versionsverwaltung der Serialisierung
12.3.4Optimierung der Serialisierung
12.4Garbage Collection
12.4.1Grundlagen zur Garbage Collection
12.4.2Der Garbage Collector »G1«
12.5Dynamic Proxies
12.5.1Statischer Proxy
12.5.2Dynamischer Proxy
12.6HTTP/2-API
12.6.1Einführung
12.6.2Real-World-Example: Wechselkurs mit REST
12.6.3Fazit
12.7Weiterführende Literatur
13Basiswissen Internationalisierung
13.1Internationalisierung im Überblick
13.1.1Grundlagen und Normen
13.1.2Die Klasse Locale
13.1.3Die Klasse PropertyResourceBundle
13.1.4Formatierte Ein- und Ausgabe
13.1.5Datumswerte und die Klasse DateFormat
13.1.6Zahlen und die Klasse NumberFormat
13.1.7Textmeldungen und die Klasse MessageFormat
13.1.8Stringvergleiche mit der Klasse Collator
13.2Programmbausteine zur Internationalisierung
13.2.1Unterstützung mehrerer Datumsformate
13.2.2Fazit und Ausblick
IIIWichtige Neuerungen in Java 12 bis 15
14Neues und Änderungen in den Java-Versionen 12 bis 15
14.1Syntaxneuerungen
14.1.1Text Blocks
14.1.2Switch Expressions
14.1.3Records (Preview)
14.1.4Pattern Matching bei instanceof (Preview)
14.1.5Sealed Types (Preview)
14.1.6Lokale Enums und Interfaces (Preview)
14.2API-Neuerungen
14.2.1Neue Methoden in der Klasse String
14.2.2Neue Hilfsmethode in der Utility-Klasse Files
14.2.3Der teeing()-Kollektor
14.3JVM-Neuerungen
14.3.1Verbesserung bei NullPointerExceptions
14.3.2Entfernung der JavaScript-Engine
14.4Microbenchmark Suite
14.4.1Eigene Microbenchmarks und Varianten davon
14.4.2Microbenchmarks mit JMH
14.4.3Fazit zu JMH
14.5Java 15 – notwendige Anpassungen für Build-Tools und IDEs
14.5.1Java 15 mit Gradle
14.5.2Java 15 mit Maven
14.5.3Java 15 mit Eclipse
14.5.4Java 15 mit IntelliJ
14.5.5Java 15 mit JShell oder der Kommandozeile
14.6Fazit
IVModularisierung
15Modularisierung mit Project Jigsaw
15.1Grundlagen
15.1.1Begrifflichkeiten
15.1.2Ziele von Project Jigsaw
15.2Modularisierung im Überblick
15.2.1Grundlagen zu Project Jigsaw
15.2.2Beispiel mit zwei Modulen
15.2.3Packaging
15.2.4Abhängigkeiten und Modulgraphen
15.2.5Module des JDKs einbinden
15.2.6Arten von Modulen
15.3Sichtbarkeiten und Zugriffsschutz
15.3.1Sichtbarkeiten
15.3.2Zugriffsschutz und Reflection
15.4Empfehlenswertes Verzeichnislayout für Module
15.5Kompatibilität und Migration
15.5.1Kompatibilitätsmodus
15.5.2Migrationsszenarien
15.5.3Fallstrick bei der Bottom-up-Migration
15.5.4Beispiel: Migration mit Automatic Modules
15.5.5Beispiel: Automatic und Unnamed Module
15.5.6Beispiel: Abwandlung mit zwei Automatic Modules
15.5.7Fazit
15.6Zusammenfassung
VFallstricke und Lösungen im Praxisalltag
16Bad Smells
16.1Programmdesign
16.1.1Bad Smell: Verwenden von Magic Numbers
16.1.2Bad Smell: Konstanten in Interfaces definieren
16.1.3Bad Smell: Zusammengehörende Konstanten nicht als Typ definiert
16.1.4Bad Smell: Casts auf unbekannte Subtypen
16.1.5Bad Smell: Programmcode im Logging-Code
16.1.6Bad Smell: Dominanter Logging-Code
16.1.7Bad Smell: Unvollständige Änderungen nach Copy-Paste
16.1.8Bad Smell: Unvollständige Betrachtung aller Alternativen
16.1.9Bad Smell: Prä-/Postinkrement in komplexeren Statements
16.1.10 Bad Smell: Mehrere aufeinanderfolgende Parameter gleichen Typs
16.1.11 Bad Smell: Grundloser Einsatz von Reflection
16.1.12 Bad Smell: System.exit() mitten im Programm
16.1.13 Bad Smell: Variablendeklaration nicht im kleinstmöglichen Sichtbarkeitsbereich
16.2Klassendesign
16.2.1Bad Smell: Unnötigerweise veränderliche Attribute
16.2.2Bad Smell: Herausgabe von this im Konstruktor
16.2.3Bad Smell: Aufruf abstrakter Methoden im Konstruktor
16.2.4Bad Smell: Mix abstrakter und konkreter Basisklassen
16.2.5Bad Smell: Referenzierung von Subklassen in Basisklassen
16.2.6Bad Smell: Öffentlicher Defaultkonstruktor lediglich zum Zugriff auf Hilfsmethoden
16.3Fehlerbehandlung und Exception Handling
16.3.1Bad Smell: Unbehandelte Exception
16.3.2Bad Smell: Unpassender Exception-Typ
16.3.3Bad Smell: Fangen der allgemeinsten Exception
16.3.4Bad Smell: Exceptions zur Steuerung des Kontrollflusses
16.3.5Bad Smell: Unbedachte Rückgabe von null
16.3.6Bad Smell: Rückgabe von null statt Exception im Fehlerfall
16.3.7Bad Smell: Sonderbehandlung von Randfällen
16.3.8Bad Smell: Keine Gültigkeitsprüfung von Eingabeparametern
16.3.9Bad Smell: Fehlerhafte Fehlerbehandlung
16.3.10 Bad Smell: I/O ohne finally oder ARM
16.3.11 Bad Smell: Resource Leaks durch Exceptions im Konstruktor
16.4Häufige Fallstricke
16.5Weiterführende Literatur
17Refactorings
17.1Refactorings am Beispiel
17.2Das Standardvorgehen
17.3Kombination von Basis-Refactorings
17.3.1Refactoring-Beispiel: Ausgangslage und Ziel
17.3.2Auflösen der Abhängigkeiten
17.3.3Vereinfachungen
17.3.4Verlagern von Funktionalität
17.4Der Refactoring-Katalog
17.4.1Reduziere die Sichtbarkeit von Attributen
17.4.2Minimiere veränderliche Attribute
17.4.3Reduziere die Sichtbarkeit von Methoden
17.4.4Ersetze Mutator- durch Business-Methode
17.4.5Minimiere Zustandsänderungen
17.4.6Führe ein Interface ein
17.4.7Spalte ein Interface auf
17.4.8Führe ein Read-only-Interface ein
17.4.9Führe ein Read-Write-Interface ein
17.4.10 Lagere Funktionalität in Hilfsmethoden aus
17.4.11 Trenne Informationsbeschaffung und -verarbeitung
17.4.12 Wandle Konstantensammlung in enum um
17.4.13 Entferne Exceptions zur Steuerung des Kontrollflusses
17.4.14 Wandle in Utility-Klasse mit statischen Hilfsmethoden um
17.4.15 Löse if-else / instanceof durch Polymorphie auf
17.5Defensives Programmieren
17.5.1Führe eine Zustandsprüfung ein
17.5.2Überprüfe Eingabeparameter
17.6Fallstricke bei Refactorings
17.7Weiterführende Literatur
18Entwurfsmuster
18.1Erzeugungsmuster
18.1.1Erzeugungsmethode
18.1.2Fabrikmethode (Factory Method)
18.1.3Erbauer (Builder)
18.1.4Singleton
18.1.5Prototyp (Prototype)
18.2Strukturmuster
18.2.1Fassade (Façade)
18.2.2Adapter
18.2.3Dekorierer (Decorator)
18.2.4Kompositum (Composite)
18.3Verhaltensmuster
18.3.1Iterator
18.3.2Null-Objekt (Null Object)
18.3.3Schablonenmethode (Template Method)
18.3.4Strategie (Strategy)
18.3.5Befehl (Command)
18.3.6Proxy
18.3.7Beobachter (Observer)
18.3.8MVC-Architektur
18.4Weiterführende Literatur
VIQualitätssicherungsmaßnahmen
19Programmierstil und Coding Conventions
19.1Grundregeln eines guten Programmierstils
19.1.1Keep It Human-Readable
19.1.2Keep It Simple And Short (KISS)
19.1.3Keep It Natural
19.1.4Keep It Clean
19.2Die Psychologie beim Sourcecode-Layout
19.2.1Gesetz der Ähnlichkeit
19.2.2Gesetz der Nähe
19.3Coding Conventions
19.3.1Grundlegende Namens- und Formatierungsregeln
19.3.2Namensgebung
19.3.3Dokumentation
19.3.4Programmdesign
19.3.5Klassendesign
19.3.6Parameterlisten
19.3.7Logik und Kontrollfluss
19.4Sourcecode-Prüfung mit Tools
19.4.1Metriken
19.4.2Sourcecode-Prüfung im Build-Prozess
20Unit Tests
20.1Testen im Überblick
20.1.1Was versteht man unter Testen?
20.1.2Testarten im Überblick
20.1.3Zuständigkeiten beim Testen
20.1.4Testen und Qualität
20.2Wissenswertes zu Testfällen
20.2.1Testfälle mit JUnit definieren
20.2.2Problem der Kombinatorik beim Bestimmen von Testfällen
20.3Besondere Assertions und Annotations
20.4Parametrierte Tests mit JUnit 5
20.4.1Einstieg
20.4.2Verbesserung des Tests der Rabattberechnung
20.4.3Praxisbeispiel: Berechnung in Testfall vereinfachen
20.4.4Praxis-Trickkiste
20.5Fortgeschrittene Unit-Test-Techniken
20.5.1Stellvertreterobjekte / Test-Doubles
20.5.2Vorarbeiten für das Testen mit Stubs und Mocks
20.5.3Die Technik EXTRACT AND OVERRIDE
20.5.4Einstieg in das Testen mit Mocks und Mockito
20.5.5Abhängigkeiten mit Mockito auflösen
20.5.6Unit Tests von privaten Methoden
20.6Test Smells
20.6.1Test Smell: Unangebrachtes assertTrue() und assert-False()
20.6.2Test Smell: Zu viele Asserts im Testfall
20.6.3Test Smell: Asserts ohne Hinweis
20.6.4Test Smell: Einsatz von toString() in assertEquals()
20.6.5Test Smell: Unit Tests zur Prüfung von Laufzeiten
20.7Nützliche Tools für Unit Tests
20.7.1Hamcrest
20.7.2AssertJ
20.7.3MoreUnit
20.7.4Infinitest
20.7.5JaCoCo
20.7.6EclEmma
20.8Umstieg von JUnit 4 auf JUnit 5
20.8.1Erweiterung im Gradle-Build für JUnit-5-Tests
20.8.2Veränderungen in den Annotations
20.8.3Alternativen für JUnit Rules
20.8.4Veränderungen bei parametrierten Tests
20.8.5Alternative zur Hamcrest-Integration in JUnit 4
20.9Fazit
20.10Weiterführende Literatur
21Codereviews
21.1Definition
21.2Probleme und Tipps zur Durchführung
21.3Vorteile von Codereviews
21.4Codereview-Checkliste
22Optimierungen
22.1Grundlagen
22.1.1Optimierungsebenen und Einflussfaktoren
22.1.2Optimierungstechniken
22.1.3CPU-bound-Optimierungsebenen am Beispiel
22.1.4Messungen – Erkennen kritischer Bereiche
22.1.5Abschätzungen mit der O-Notation
22.2Einsatz geeigneter Datenstrukturen
22.2.1Einfluss von Arrays und Listen
22.2.2Optimierungen für Set und Map
22.2.3Design eines Zugriffsinterface
22.3Lazy Initialization
22.3.1Konsequenzen des Einsatzes der Lazy Initialization
22.3.2Lazy Initialization mithilfe des PROXY-Musters
22.4Optimierungen am Beispiel
22.5I/O-bound-Optimierungen
22.5.1Technik – Wahl passender Strategien
22.5.2Technik – Caching und Pooling
22.5.3Technik – Vermeidung unnötiger Aktionen
22.6Memory-bound-Optimierungen
22.6.1Technik – Wahl passender Strategien
22.6.2Technik – Caching und Pooling
22.6.3Optimierungen der Stringverarbeitung
22.6.4Technik – Vermeidung unnötiger Aktionen
22.7CPU-bound-Optimierungen
22.7.1Technik – Wahl passender Strategien
22.7.2Technik – Caching und Pooling
22.7.3Technik – Vermeidung unnötiger Aktionen
22.8Weiterführende Literatur
23Schlussgedanken
VIIAnhang
AGrundlagen zur Java Virtual Machine
A.1Wissenswertes rund um die Java Virtual Machine
A.1.1Ausführung eines Java-Programms
A.1.2Speicherverwaltung und Classloading
Literaturverzeichnis
Index
Sie halten die mittlerweile 5. Auflage dieses Buchs in den Händen. Das wurde nur durch den großen Zuspruch und das auch nach Jahren anhaltende Interesse für dieses Buch möglich. Somit geht zunächst ein herzlicher Dank an alle Leser der vorherigen Auflagen.
Diese 5. Auflage wurde vollständig auf Java 11 als derzeitige LTS-Version (Long Term Support) aktualisiert sowie in diversen Teilen überarbeitet und erweitert. Dieses Buch soll Ihnen einen fundierten Einstieg in die professionelle Java-Programmierung ermöglichen und damit Ihren Weg zum Java-Profi erleichtern. Wie schon aus den Vorgängern gewohnt, gebe ich immer wieder Tipps aus dem Praxisalltag, weise auf Fallstricke hin und zeige Lösungswege auf. Damit Sie aber am Puls der Zeit sind und über alles Wesentliche bis hin zum aktuellen Java 15 Bescheid wissen, behandle ich die vielfältigen Neuerungen ebenso wie die Modularisierung in jeweils eigenen Kapiteln. Für eine noch umfassendere Behandlung der Thematik verweise ich Sie auf mein Buch »Java – die Neuerungen in Version 9 bis 14: Modularisierung, Syntax- und API-Erweiterungen« [41].
Im Rahmen der Überarbeitung für diese 5. Auflage habe ich das Buch nochmals vollständig gelesen und kritisch beleuchtet. Dadurch konnten kleinere Unstimmigkeiten, missverständliche Formulierungen und ein paar verbliebene Tippfehler erkannt und korrigiert werden. Zudem habe ich die Anregungen und Wünsche von Lesern sowie von Kollegen und Freunden mit eigenen Ideen kombiniert. Daraus sind diverse Ergänzungen und Überarbeitungen in den bereits vorhandenen Kapiteln entstanden. Auch wurden verschiedene Dinge restrukturiert und thematisch neu gegliedert.
Nachfolgend liste ich wesentliche Änderungen dieser 5. Auflage im Vergleich zum Vorgänger auf: