image
image

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.

image

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

Michael Inden

Der Weg zum
Java-Profi

Konzepte und Techniken für die
professionelle Java-Entwicklung

5., überarbeitete und aktualisierte Auflage

image

Michael Inden
michael_inden@hotmail.com

Lektorat: Dr. Michael Barabas

Bibliografische Information der Deutschen Nationalbibliothek

ISBN:

5., überarbeitete und aktualisierte Auflage 2021

Hinweis:

Schreiben Sie uns:

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.

5 4 3 2 1 0

Inhaltsübersicht

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

Inhaltsverzeichnis

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

Vorwort

Vorwort zur 5. Auflage

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].

Änderungen in dieser 5. Auflage

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: