Der Weg zum Java-Profi - Michael Inden - E-Book

Der Weg zum Java-Profi E-Book

Michael Inden

0,0

Beschreibung

Standardwerk in 5. Neuauflage !

  • Das Standardwerk für die professionelle Javaentwicklung
  • Fundierter Überblick über Profithemen, die man sonst nicht findet.
  • Alles, was man braucht, um im Coding-Job mithalten zu können

Dieses Buch bietet eine umfassende Einführung in die professionelle Java-Entwicklung und vermittelt Ihnen das notwendige Wissen, um stabile und erweiterbare Softwaresysteme auf Java-SE-Basis zu bauen. Praxisnahe Beispiele helfen dabei, das Gelernte rasch umzusetzen. Neben der Praxis wird viel Wert auf das Verständnis zugrunde liegender Konzepte gelegt. Dabei kommen dem Autor Michael Inden seine umfangreichen Schulungs- und Entwicklererfahrungen zugute – und Ihnen als Leser damit ebenso. Diese Neuauflage wurde durchgehend überarbeitet und aktualisiert und berücksichtigt die Java-Versionen 9 bis 15. Ansonsten wurde der bewährte Themenmix der Vorauflagen beibehalten: Grundlagen, Analyse und Design: Professionelle Arbeitsumgebung – Objektorientiertes Design– Lambdas – Java-Grundlagen Bausteine stabiler Java-Applikationen: Collections-Framework – Stream-API – Datumsverarbeitung seit JDK 8 – Applikationsbausteine – Multithreading-Grundlagen – Modern Concurrency – Fortgeschrittene Java-Themen  – Basiswissen Internationalisierung Fallstricke und Lösungen: Bad Smells – Refactorings – Entwurfsmuster Qualitätssicherung: Programmierstil und Coding Conventions – Unit Tests – Codereviews – Optimierungen Darüber hinaus thematisiert je ein Kapitel die Neuerungen in Java 12 bis 15 sowie die Modularisierung mit Project Jigsaw. Ergänzt wird das Ganze durch einen Anhang mit einen Überblick über Grundlagen zur Java Virtual Machine.

"Es ist wirklich ein gelungenes Buch für Java-Programmierer die ihre Kenntnisse vertiefen und professionalisieren wollen!" (rn-wissen.de)
"Vom motivierten Einsteiger bis zum Java-Profi, ein in Breite und Tiefe überzeugendes Werk [...] empfehle ich jedem, der sich ernsthaft mit professioneller Java-Entwicklung auseinandersetzen möchte."

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern

Seitenzahl: 1923

Das E-Book (TTS) können Sie hören im Abo „Legimi Premium” in Legimi-Apps auf:

Android
iOS
Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



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

Michael Inden

Der Weg zumJava-Profi

Konzepte und Techniken für dieprofessionelle Java-Entwicklung

5., überarbeitete und aktualisierte Auflage

Michael [email protected]

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: [email protected].

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

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:

Kapitel 2

»

Professionelle Arbeitsumgebung

« – Der Text wurde leicht überarbeitet und aktualisiert, das gilt etwa für die Einführung ins Unit-Testen. Diese setzt nun auf JUnit 5. Darüber hinaus behandle ich das Build-Tool Ant in dieser 5. Auflage nicht mehr, da es in der Praxis kaum noch eine Rolle spielt. Zudem wurde die Beschreibung von Gradle auf die im September 2020 aktuelle Version 6.6.1 angepasst.

Kapitel 3

»

OO-Design

« – In diesem Kapitel wurden ein paar Details und Beispiele leicht überarbeitet, um die Verständlichkeit weiter zu verbessern, etwa im Bereich der kovarianten Rückgabewerte. Zudem weise ich, wo sinnvoll, auf mögliche Vereinfachungen durch aktuelle Java-14- bzw. Java-15-Sprachmittel hin.

Kapitel 4

»

Lambdas, Methodenreferenzen und Defaultmethode

n

« – Dieses Kapitel enthält nun Neuerungen für Interfaces in Java 9. Außerdem wurde eine Beschreibung zu einer kosmetischen Erweiterung in

Predicate<T>

in JDK 11 ergänzt. Schließlich thematisiere ich nun ein kleines, aber wichtiges Detail bei der Definition von Lambdas und dem Zugriff auf Variablen.

Kapitel 5

»

Java-Grundlagen

« – Die Behandlung der Java-Grundlagen wurde gestrafft, etwa im Bereich des alten APIs zur Dateiverwaltung. Zudem habe ich ganze Abschnitte wie denjenigen zum alten Datums-API entfernt und diverse Beispiele auf das moderne Date and Time API umgestellt. Außerdem wurden wesentliche Neuerungen aus Java 9 bis 11 an passenden Stellen, etwa im Bereich für Strings und auch für die Utility-Klasse

Files

oder die Syntaxneuerung

var

, integriert.

Kapitel 6

»

Das Collections-Framework

« – Neben Detailkorrekturen inklusive inhaltlicher Straffung wurden einige Neuerungen aus Java 8 und 9 an passender Stelle hinzugefügt, insbesondere Collection-Factory-Methoden sowie Hilfsmethoden in der Klasse

Arrays

. Die Beschreibung zur Klasse

Optional<T>

wurde überarbeitet und um die Neuerungen aus Java 10 und 11 erweitert.

Kapitel 7

»

Stream-API

« – In diesem Kapitel wurden einige inhaltliche Ergänzungen, etwa für die Kombination von

skip()

und

limit()

, sowie kleinere sprachliche Korrekturen vorgenommen. Darüber hinaus ist vor allem ein Abschnitt zu den Neuerungen im Stream-API in Java 9 hinzugefügt worden. Die Verarbeitung von ZIP-Dateien wurde als Praxisbeispiel entfernt.

Kapitel 8

»

Datumsverarbeitung seit JDK 8

« – Dieses Kapitel hat ebenfalls kleine sprachliche Korrekturen sowie minimale Anpassungen zur Stringenz der Beispiele erfahren. Zudem werden nun Erweiterungen aus Java 9 beschrieben. Um die Möglichkeiten der Datumsarithmetik noch besser nachvollziehen zu können, habe ich zwei Beispiele ergänzt. Besonders erwähnenswert ist dasjenige zur Berechnung des Gehaltszahltags als Real-World-Example. Dieses verfolgt ein schrittweises Vorgehen mit dem Hinzufügen von jeweils kleinen Funktionsblöcken und zeigt auch gleich geeignetes Testing mit JUnit 5.

Kapitel 9

»

Applikationsbausteine

« – In diesem Kapitel wurden diverse Kleinigkeiten angepasst und Kürzungen vorgenommen. Das betrifft vor allem die Themen Preferences sowie Wertebereichsprüfungen. Bei Letzterem wurde auf die Darstellung eigener Lösungen zugunsten von Google Guava verzichtet. Zudem habe ich das abschließende Beispiel zur Verarbeitung von CSV so umgestaltet, dass es nun das Java-14-Feature

record

s nutzt.

Kapitel 10

»

Multithreading

« – Dieses Kapitel hat diverse Detailänderungen erfahren und der Teil zu Producer-Consumer wurde gekürzt. Weil mittlerweile modernere und zu bevorzugende Konstrukte existieren, habe ich die Beschreibung zur zeitgesteuerten Ausführung mit

Timer

und

TimerTask

entfernt. Insbesondere wurden fortgeschrittenere Themen und die Beschreibung moderner APIs in ein eigenständiges Kapitel ausgelagert.

Kapitel 11

»

Modern Concurrency

« – Dieses Kapitel wurde komplett neu gestaltet und diverse Beispiele ergänzt und prägnanter formuliert. Ziel ist es, modernere Concurrency-Konzepte vorzustellen. Die hier beschriebenen Concurrency Utilities und das Executor- sowie das Fork-Join-Framework erlauben es, statt auf Low-Level-Ebene zu parallelisierende Abläufe auf konzeptionell höherer Ebene umzusetzen. Aber es wird noch besser: Verarbeitungsabläufe lassen sich mithilfe von

CompletableFuture

sehr elegant beschreiben und parallelisieren. Abschließend thematisiere ich die Reactive Streams, die eine Verbindung zum Reactive Programming bilden.

Kapitel 12

»

Fortgeschrittene Java-Themen

« – Der Text hat ein Facelift erhalten. Die Beispiele wurden durchgehend auf das Date and Time API aktualisiert. Insbesondere habe ich den Teil zur Garbage Collection deutlich gekürzt. Vollständig entfernt wurde die Beschreibung zur JavaScript-Verarbeitung, da diese mit Java 15 nicht mehr Bestandteil des JDKs ist. Eine Beschreibung zum HTTP/2-API wurde in diesem Kapitel ergänzt. Als Schmankerl schauen wir uns dort an, wie man damit REST-Calls absetzen und auf diese Weise Wechselkurse ermitteln kann.

Kapitel 13

»

Basiswissen Internationalisierung

« – Der Text wurde in den Bereichen gekürzt, die das alte Datums-API behandelt haben. Diverse Teile verwenden jetzt das modernere Date and Time API aus Java 8. Da Java im Bereich Desktop und GUIs kaum mehr verwendet wird, habe ich die Beispiele, die JavaFX oder Swing nutzen, entfernt.

Kapitel 17

»

Refactorings

« – Auch das Kapitel zu Refactorings hat einen Facelift erfahren. Vor allem wurden alle begleitenden Unit Tests auf JUnit 5 umgestellt. Zudem kam in einem Beispiel noch die Bibliothek Joda-Time zum Einsatz. Das wurde nun auf das Date and Time API des JDKs umgestellt.

Kapitel 19

»

Programmierstil und Coding Conventions

« – Dieses Kapitel enthält Detailkorrekturen. Dabei wurden vor allem die Abschnitte zu den Tools überarbeitet und aktualisiert. Die Beschreibung zum Tool FindBugs sowie dessen Nachfolger SpotBugs wurde entfernt, da diese keine neuen Java-Versionen unterstützen, derzeit nicht einmal Java 10 und 11.

Kapitel 20

»

Unit Tests

« – Auch hier wurde der gesamte Text überarbeitet und umstrukturiert. Vor allem wird nun konsequent das aktuelle JUnit 5 genutzt, wodurch sich einige Testfälle deutlich leichter als mit den Vorgängern beschreiben lassen. Insbesondere den parametrierten Tests wird viel Aufmerksamkeit gewidmet. Test Smells werden nun ausführlicher behandelt und zeigen konkrete Lösungsmöglichkeiten.

Kapitel 22

»

Optimierungen

« – Die Performance-Messungen wurden mit JDK 14 wiederholt. Einige Messungen erfolgten ergänzend mit dem seit JDK 12 ins JDK integrierten JMH (Java Microbenchmark Harness). Beim Kopieren von Dateiinhalten wird nun auch die Variante mit

transferTo()

als Neuerung aus Java 9 betrachtet. Bei den CPU-bound-Optimierungen zeige ich mit Memoization eine sehr effiziente Technik, um rekursive Berechnungen dramatisch beschleunigen zu können.

Erweiterungen

Kapitel 14

»

Ergänzungen in Java 12 bis 15

« – In den letzten 3 Jahren sind diverse Java-Versionen erschienen, die verschiedene interessante Neuerungen in der Syntax und den APIs mit sich bringen. Wichtige Themen werden in diesem Kapitel vorgestellt.

Entfallene Themen

Aus drucktechnischen Gründen mussten die Kapitel zu JavaFX sowie zur GUI-Programmierung mit Swing aus der Druckvariante des Buchs entfernt werden. Diese stehen aber – wie auch einige in früheren Auflagen entfernte Anhänge zu UML und dem Softwareentwicklungsprozess – als PDF auf der Seite des Verlags zum Download bereit.

Danksagung

Ein Fachbuch zu schreiben ist eine schöne, aber arbeitsreiche und langwierige Aufgabe. Alleine kann man dies kaum bewältigen, daher möchte ich mich an dieser Stelle bei allen bedanken, die direkt oder indirekt dazu beigetragen haben.

Bei der Erstellung des Manuskripts konnte ich auf ein starkes Team an Korrekturlesern zurückgreifen, insbesondere wieder einmal auf Michael Kulla, der akribisch gelesen und viele hilfreiche Anmerkungen eingebracht hat. Vielen Dank! Für das neu erstellte Kapitel Modern Concurrency haben Prof. Dr. Rainer Oechsle und René Preißel diverse nützliche Anmerkungen zur Verbesserung beigesteuert und kleinere Unstimmigkeiten aufgedeckt. In diesem Kontext erhielt ich ein paar hilfreiche Anmerkungen von Dr. Heinz Kabutz. Besten Dank an alle!

Wie immer geht natürlich auch ein Dankeschön an das Team des dpunkt.verlags (vor allem Dr. Michael Barabas, Anja Weimer und Stefanie Weidner) für die gute Zusammenarbeit. Außerdem möchte ich mich bei Torsten Horn für die fundierte fachliche Durchsicht sowie bei Ursula Zimpfer für ihre Adleraugen beim Copy-Editing bedanken.

Abschließend geht natürlich ein lieber Dank an meine Frau Lilija für ihr Verständnis und ihre Unterstützung. Bei der Erstellung dieser 5. Auflage war ich glücklicherweise weit weniger im Stress als bei den vorherigen Ausgaben, sodass sogar die eine oder andere gemeinsame Fahrradtour oder Wanderung möglich wurde. Auch die Vorbereitungen auf die Geburt unserer Tochter laufen auf Hochtouren und die Freude ist groß.

Anregungen und Kritik

Ich wünsche allen Lesern viel Freude und einige neue Erkenntnisse durch die Lektüre dieser 5. Auflage. Möge Ihnen der »Weg zum Java-Profi« mit meinem Buch ein wenig leichter fallen.

Trotz großer Sorgfalt lassen sich Fehler bei einem so umfangreichen Buch leider nicht vollständig vermeiden. Falls Ihnen ein solcher auffällt oder eine Formulierung missverständlich sein sollte, so zögern Sie bitte nicht, mir dies mitzuteilen. Haben Sie Anregungen, Verbesserungsvorschläge oder fehlt Ihnen noch eine Information? Sie erreichen mich per Mail unter: [email protected].

Zürich, im Oktober 2020

Michael Inden

Danksagung zur 4. Auflage

Bei der Erstellung des Manuskripts konnte ich auf ein starkes Team an Korrekturlesern zurückgreifen, insbesondere diesmal auch auf Michael Kulla, der akribisch gelesen und viele hilfreiche Anmerkungen eingebracht hat. Vielen Dank! Wieder einmal haben mich meine Freunde Merten Driemeyer, Dr. Clemens Gugenberger, Prof. Dr. Carsten Kern und Andreas Schöneck hervorragend unterstützt. Den einen oder anderen Hinweis und Tipp erhielt ich von Jeton Memeti, Marius Reusch und Prof. Dr. Andreas Spillner.

Weil der Java-9-Teil inhaltlich – wenn auch vom Umfang deutlich abgespeckt – weitestgehend meinem Buch »Java 9 – Die Neuerungen« [40] entstammt, danke ich allen dort Beteiligten ebenfalls.

Danksagung zur 3. Auflage

Bei der Erstellung des Manuskripts konnte ich auf ein starkes Team an Korrekturlesern zurückgreifen, insbesondere diesmal auch auf Benjamin Muschko und Hans Dockter als Experten zu Gradle sowie Hendrik Schreiber, selbst Autor eines Java-Fachbuchs zu Optimierungen. Vielen Dank an euch!

Einige Tipps erhielt ich von Tim Bötzmeyer und Reinhard Pupkes. Auch haben mich folgende Personen hervorragend unterstützt: Merten Driemeyer, Dr. Clemens Gugenberger, Dr. Carsten Kern, Florian Messerschmidt und Andreas Schöneck. Darüber hinaus kamen gute Anmerkungen von verschiedenen Zühlke-Kollegen: Michael Haspra, Jörg Keller, Rick Janda, Franziska Meyer, Sagi Nedunkanal, Joachim Prinzbach und Dr. Christoph Schmitz. Der Java-8-Teil entstammt weitestgehend meinem Buch »Java 8 – Die Neuerungen«. Allen dort Beteiligten danke ich ebenfalls.

Neben den Korrekturlesern möchte ich einen ganz herzlichen Dank an meinen damaligen Arbeitgeber Zühlke Engineering AG und insbesondere meinen Chef Wolfgang Giersche für die gewährte freie Zeit zum Finalisieren des Buchs aussprechen. Das war eine große Hilfe in der letzten heißen Phase vor der Abgabe des Manuskripts.

Danksagung zur 2. Auflage

Bei der Erstellung der 2. Auflage konnte ich wieder auf ein starkes Team an Korrekturlesern zurückgreifen. Einige Tipps erhielt ich von Dr. Alexander Kort und Reinhard Pupkes. Auch haben mich folgende Personen hervorragend unterstützt: Stefan Bartels, Tim Bötzmeyer, Rudolf Braun, Andreas Bubolz, Merten Driemeyer, Bernd Eckstein, Dr. Clemens Gugenberger, Peter Kehren, Dr. Carsten Kern, Dr. Iris Rottländer, Roland Schmitt-Hartmann und Andreas Schöneck.

Dabei möchte ich folgende vier Personen herausheben: Stefan Bartels für seine sprachliche Gründlichkeit, Andreas Bubolz für seine Genauigkeit und Dr. Clemens Gugenberger sowie Andreas Schöneck für die ganzen hilfreichen Anregungen.

Danksagung zur 1. Auflage

Zu meiner Zeit bei der Heidelberger Druckmaschinen AG in Kiel ist bei den Vorbereitungen zu Codereviews und der Ausarbeitung von Vorträgen zum ersten Mal der Gedanke an ein solches Buch entstanden. Danke an meine damaligen Kollegen, die an diesen Meetings teilgenommen haben. Als Veranstalter und Vortragender lernt man immer wieder neue Details. Dietrich Mucha und Reinhard Pupkes danke ich für ihre Korrekturen und Anmerkungen, die gemeinsamen Erfahrungen beim Ausarbeiten von Coding Conventions und Codereviews sowie die nette Zeit beim Pair Programming. Die Zusammenarbeit mit Tim Bötzmeyer hat mir viel Freude bereitet. Unsere langen, interessanten Diskussionen über Java und die Fallstricke beim OO-Design haben mir diverse neue Einblicke verschafft.

Auch einige Kollegen bei der IVU Traffic Technologies AG in Aachen haben mich mit Korrekturen und Anregungen unterstützt. Unter anderem danke ich Rudolf Braun, Christian Gehrmann, Peter Kehren, Felix Korb und Roland Schmitt-Hartmann für den einen oder anderen Hinweis und Tipp, um den Text weiter zu verbessern. Mein spezieller Dank gilt Merten Driemeyer, der sich sehr gründlich mit frühen Entwürfen des Manuskripts beschäftigt und mir an diversen Stellen fachliche und sprachliche Tipps gegeben hat. Gleiches gilt für Dr. Iris Rottländer, die sowohl formal als auch inhaltlich an vielen Stellen durch ihre Anmerkungen für eine Verbesserung des Textes gesorgt hat. Auch Dr. Carsten Kern und Andreas Schöneck haben gute Hinweise gegeben und einige verbliebene kleinere Fehler aufgedeckt. Last, but not least haben die Anmerkungen von Dr. Clemens Gugenberger und unsere nachfolgenden Diskussionen einigen Kapiteln den letzten Feinschliff gegeben. Gleiches gilt für Stefan Bartels, der mich immer wieder durch gute Anmerkungen unterstützt und damit zur Verständlichkeit des Textes beigetragen hat. Alle sechs haben mir entscheidend geholfen, inhaltlich für mehr Stringenz und Klarheit zu sorgen. Mein größter Dank geht an Andreas Bubolz, der mich immer wieder unterstützt und enorm viel Zeit und Mühe investiert hat. Als Korrekturleser und Sparringspartner in vielen Diskussionen hat er diverse Unstimmigkeiten im entstehenden Text aufgedeckt.

Einleitung

1Einleitung

Bevor es mit den Programmierthemen losgeht, möchte ich Ihnen dieses Buch vorstellen. Ich beginne damit, warum dieses Buch entstanden ist und wie es Ihnen hoffentlich helfen kann, ein noch besserer Java-Entwickler zu werden. Danach folgt eine Gliederung des Inhalts, damit Sie sich gut im Buch zurechtfinden.

1.1Über dieses Buch

1.1.1Motivation

Mein Ziel war es, ein Buch zu schreiben, wie ich es mir selbst immer als Hilfe gewünscht habe. Die hier vorgestellten Hinweise und Techniken sollen Sie auf Ihrem Weg vom engagierten Hobbyprogrammierer oder Berufseinsteiger zum erfahrenen Softwareentwickler begleiten. Dieser Weg ist ohne Anleitung gewöhnlich steinig und mit einige Mühen, Irrwegen und Problemen verbunden. Einige dieser leidvollen Erfahrungen möchte ich Ihnen ersparen. Aber auch erfahreneren Softwareentwicklern soll dieses Buch die Möglichkeit geben, über die im täglichen Einsatz lieb gewonnenen Gewohnheiten nachzudenken und die eine oder andere davon zu ändern, um die Produktivität weiter zu steigern. Mein Wunsch ist, dass sich nach Lektüre des Buchs für Sie die Ingenieurdisziplin der Softwareentwicklung mit der Kunst des Programmierens verbindet und Dinge auf einmal einfach so auf Anhieb funktionieren. Das ist etwas ganz anderes, als vor jedem Gang in die Testabteilung Magenschmerzen zu bekommen.

Sowohl der Berufseinstieg als auch die tägliche Arbeit können manchmal frustrierend sein. Meiner Meinung nach soll Softwareentwicklung aber Freude bereiten, denn nur so können wir exzellente Resultate erzielen. In der Praxis besteht jedoch die Gefahr, in die Fettnäpfchen zu treten, die im Sourcecode hinterlassen wurden. Dies geschieht meistens dadurch, dass die existierende Lösung softwaretechnisch umständlich oder schlecht implementiert ist und/oder nicht bis zu Ende durchdacht wurde. Der Sourcecode ist dann häufig schwierig wart- und erweiterbar. Manchmal bereitet bereits das Auffinden der Stelle, an der man Modifikationen durchführen sollte, Probleme.

Dieses Buch soll aufzeigen, wie man die zuvor beschriebene »Altlasten«-Falle vermeidet oder aus ihr herauskommt und endlich Sourcecode schreiben kann und darf, der leicht zu lesen ist und in dem es Spaß macht, Erweiterungen zu realisieren. Grundlage dafür ist, dass wir uns einen Grundstock an Verhaltensweisen und an Wissen aneignen.

1.1.2Was leistet dieses Buch und was nicht?

Wieso noch ein Buch über Java-Programmierung? Tatsächlich kann man sich diese Frage stellen, wo es doch unzählige Bücher zu diesem Thema gibt. Viele davon sind einführende Bücher, die häufig nur kurz die APIs anhand simpler Beispiele vorstellen. Die andere große Masse der Java-Literatur beschäftigt sich mit speziellen Themen, die für den »erfahrenen Einsteiger« bereits zu komplex geschrieben und in denen zu wenig erklärt ist. Genau hier setzt dieses Buch an und wagt den Spagat, den Leser nach der Lektüre einführender Bücher abzuholen und so weit zu begleiten, dass er mit einem guten Verständnis die Spezialliteratur lesen und gewinnbringend einsetzen kann.

Ziel dieses Buchs ist es, dem Leser fundierte Kenntnisse in Java und einigen praxisrelevanten Themenbereichen, unter anderem dem Collections-Framework und im Bereich Multithreading, zu vermitteln. Es werden vertiefende Blicke auf die zugrunde liegenden Details geworfen, um nach der Lektüre des Buchs professionelle Programme schreiben zu können. Wie bereits angedeutet, bietet dieses Buch keinen Einstieg in die Sprache selbst, sondern es wird einiges an Wissen vorausgesetzt. In den einleitenden Grundlagenkapiteln zu einer professionellen Arbeitsumgebung, über objektorientiertes Design und Java sowie über die funktionale Programmierung mit Lambdas wird allerdings die Basis für das Verständnis der Folgekapitel geschaffen.

In diesem Buch versuche ich, einen lockeren Schreibstil zu verwenden und nur an den Stellen formal zu werden, wo dies wirklich wichtig ist, etwa bei der Einhaltung von Methodenkontrakten. Da der Fokus dieses Buchs auf dem praktischen Nutzen und dem guten Verständnis von Konzepten liegt, werden neben APIs auch häufig vereinfachte Beispiele aus der realen Welt vorgestellt. Die meisten der abgebildeten Listings stehen als kompilierbare und lauffähige Programme auf der Webseite zum Buch zum Download bereit. Im Buch selbst werden aus Platzgründen und zugunsten einer besseren Übersichtlichkeit in der Regel nur die wichtigen Passagen abgedruckt.

1.1.3Wie und was soll mithilfe des Buchs gelernt werden?

Dieses Buch zeigt und erklärt einige in der Praxis bewährte Ansätze, Vorgehens- und Verhaltensweisen, ohne dabei alle Themengebiete bis in kleinste Detail auszuleuchten. Wichtiges Hintergrundwissen wird jedoch bei Bedarf vermittelt. Es wird der pragmatische Weg gegangen und bevorzugt die in der täglichen Praxis relevanten Themen vorgestellt. Sollte ein Thema bei Ihnen besonderes Interesse wecken und Sie weitere Informationen wünschen, so finden sich in den meisten Kapiteln Hinweise auf weiterführende Literatur. Dies ist im Prinzip auch schon der erste Tipp: Lesen Sie viele Bücher und schaffen Sie sich damit eine breite Wissensbasis. Ich zitiere hier aus Jon Bentleys Buch »Perlen der Programmierkunst« [3]: »Im Stadium des Entwurfsprozesses ist es unschätzbar, die einschlägige Literatur zu kennen.«

Diesem Hinweis kann ich mich nur anschließen und möchte Ihnen hier speziell einige – meiner Meinung nach – ganz besondere Bücher ans Herz legen und empfehle ausdrücklich, diese Bücher begleitend oder ergänzend zu diesem Buch zu lesen:

»

SCJP – Sun Certified Programmer & Developer for Java 2

«

[68]

– Die Vorbereitung zur SCJP-Zertifizierung wird mit all seinen Fallstricken und kniffligen Details auf unterhaltsame Weise von Kathy Sierra und Bert Bates aufbereitet. Mittlerweile heißt die Zertifizierung OCPJP (Oracle Cerified Professional Java Programmer) und es sind diverse neue Bücher dazu erschienen. Das von Sierra und Bates war aber etwas Besonderes.

»

The Java Programming Language

«

[2]

– Ein unglaublich gutes Buch von Ken Arnold, James Gosling und David Holmes über die Sprache Java, das detailreich, präzise und dabei angenehm verständlich zu lesen ist.

»

Effective Java

«

[5]

,

[6]

und

[7]

– Die erste Auflage dieses grandiosen Buchs von Joshua Bloch habe ich auf der Java One 2001 in San Francisco gekauft und es hat mein Denken und Programmieren in Java stark beeinflusst. Mittlerweile existiert eine dritte, auf JDK 9 aktualisierte Auflage (die leider kaum auf Modularisierung eingeht).

»

Entwurfsmuster

«

[23]

– Das Standardwerk der sogenannten »Gang of Four« (Erich Gamma, Richard Helm, Ralph Johnson und John Vlissides) habe ich 1998 kennengelernt und mit großem Interesse gelesen und gewinnbringend eingesetzt. Die vorgestellten Ideen sind beim Entwurf guter Software enorm hilfreich.

»

Head First Design Patterns

«

[21]

– Dieses Buch einer anderen »Gang of Four« (Eric Freeman, Elizabeth Freeman, Kathy Sierra und Bert Bates) lässt Entwurfsmuster als ein unterhaltsames Thema erscheinen und erleichtert den Einstieg.

»

Refactoring

«

[20]

– Einige Tricks und Kniffe zur Verbesserung von Sourcecode lernt man von Kollegen oder durch Erfahrung. Martin Fowler fasst dieses Wissen in dem genannten Buch zusammen und stellt ein systematisches Vorgehen zur Sourcecode-Transformation vor.

»

Refactoring to Patterns

«

[45]

– Dieses Buch von Joshua Kerievsky verknüpft die Ideen von Refactorings mit denen zu Entwurfsmustern.

»

Code Craft: The Practice of Writing Excellent Code

«

[25]

– Ein sehr lesenswertes Buch von Pete Goodliffe, das diverse gute Hinweise gibt, wie man exzellenten Sourcecode schreiben kann, der zudem (nahezu) fehlerfrei, gut testbar sowie einfach zu warten ist.

Lesen hilft uns bereits, aber nur durch Übung und Einsatz in der Praxis können wir unsere Fähigkeiten verbessern. Weil ein Buch jedoch nicht interaktiv ist, werde ich bevorzugt eine schrittweise Vorstellung der jeweiligen Themen vornehmen, wobei zum Teil auch bewusst zunächst ein Irrweg gezeigt wird. Anhand der vorgestellten Korrekturen erkennt man dann die Vorteile viel deutlicher, als wenn nur eine reine Präsentation der Lösung erfolgen würde. Mit dieser Darstellungsweise hoffe ich, dass Sie sich ein paar gute Gewohnheiten antrainieren. Das fängt mit scheinbar einfachen Dingen wie der Vergabe von sinnvollen Namen für Variablen, Methoden und Klassen an und endet in der Verwendung von problemangepassten Entwurfsmustern. Anfangs erfordert dies erfahrungsgemäß ein wenig Fleiß, Einarbeitung, Disziplin und eventuell sogar etwas Überwindung. Daher werde ich bei der Vorstellung einer Technik jeweils sowohl auf die Vorteile als auch potenzielle Nachteile eingehen.

1.1.4Wer sollte dieses Buch lesen?

Dieses Buch konzentriert sich auf Java als Programmiersprache – allerdings benötigen Sie bereits einige Erfahrung mit Java, um die Beispiele sowie die beschriebenen Tücken nachvollziehen zu können und möglichst viel von den Tipps und Tricks in diesem Buch zu profitieren. Wenn Sie dieses Buch in den Händen halten, gehe ich also davon aus, dass Sie sich schon (etwas) mit Java auseinandergesetzt haben.

Das Buch richtet sich im Speziellen an zwei Zielgruppen: Zum einen sind dies engagierte Hobbyprogrammierer, Informatikstudenten oder Berufseinsteiger, die von Anfang an lernen wollen, wie man professionell Software schreibt. Zum anderen sind dies erfahrenere Softwareentwickler, die ihr Wissen in einigen fortgeschritteneren Themen komplettieren wollen und vermehrt Priorität auf sauberes Design legen oder Coding Conventions, Codereviews und Unit-Testen bei der Arbeit etablieren wollen.

Abhängig vom Kenntnisstand zu Beginn der Lektüre starten Entwickler mit Erfahrung bei Teil II oder Teil III des Buchs und können die dort vorgestellten Techniken sofort gewinnbringend in der Praxis einsetzen. Lesern mit noch relativ wenig Erfahrung empfehle ich, den ersten Teil konzentriert und vollständig durchzuarbeiten, um sich eine gute Basis zu verschaffen. Dadurch wird das Verständnis der später vorgestellten Themen erleichtert, denn die nachfolgenden Teile des Buchs setzen die Kenntnis dieser Basis voraus und das Niveau nimmt ständig zu. Ziel ist es, nach Lektüre des Buchs den Einstieg in die professionelle Softwareentwicklung mit Java erreicht zu haben und viele dazu erforderliche Techniken sicher zu beherrschen. Das Buch ist daher mit diversen Praxistipps gespickt, mit denen Sie auf interessante Hintergrundinformationen oder auf mögliche Probleme hingewiesen werden und die wie folgt in den Text integriert sind:

Tipp: Praxistipp

In derart formatierten Kästen finden sich im späteren Verlauf des Buchs immer wieder einige wissenswerte Tipps und ergänzende Hinweise zum eigentlichen Text.

1.2Aufbau des Buchs

Der Aufbau des Buchs gliedert sich in mehrere Teile. Folgende Aufzählung konkretisiert die dort vorgestellten Themen:

Teil I

»

Java-Grundlagen, Analyse und Design

«

– Dieser Teil legt die Grundlagen für einen guten Softwareentwurf. Dazu wird sowohl auf objektorientiertes Design als auch auf eine produktive Arbeitsumgebung mit den richtigen Hilfsmitteln eingegangen.

Teil I

beginnt in

Kapitel 2

mit der Vorstellung einer sinnvoll ausgestatteten Arbeitsumgebung, die beim Entwickeln von professionellen Programmen hilft. Danach wird in

Kapitel 3

das Thema objektorientiertes Design beschrieben. Damit sind die Grundlagen für einen professionellen, objektorientierten Softwareentwurf gelegt und die Vorbereitungen zum Implementieren getroffen. In

Kapitel 4

erfolgt eine Vorstellung von Lambda-Ausdrücken, die die funktionale Programmierung mit Java ermöglichen. Zu Abschluss von

Teil I

stellt

Kapitel 5

schließlich grundlegende Java-Sprachelemente vor, die zum Verständnis der Beispiele in den folgenden Kapiteln notwendig sind.

Teil II

»

Bausteine stabiler Java-Applikationen

«

– Der zweite Teil beschäftigt sich mit Bausteinen stabiler Java-Applikationen. Dazu werden Kenntnisse zu fundamentalen Java-APIs vermittelt, aber auch fortgeschrittene Java-Techniken behandelt. Zunächst stellt

Kapitel 6

das Thema Collections vor, um eine effiziente Wahl von Datenstrukturen zur Verwaltung von Daten zu ermöglichen. Im Anschluss gehe ich in

Kapitel 7

auf das Stream-API ein. Danach schauen wir uns in

Kapitel 8

die Verbesserungen bei der Datumsverarbeitung mit dem in Java 8 ergänzten Date and Time API an. In

Kapitel 9

beschäftigen wir uns mit wiederverwendbaren Softwarebausteinen, die verhindern, das Rad ständig neu zu erfinden. Ein weiterer Baustein beim professionellen Programmieren ist Multithreading.

Kapitel 10

bietet eine Einführung und thematisiert grundlegende Bausteine wie Threads, Synchronisierung usw. Damit lassen sich zwar Multithreading-Anwendungen schreiben, jedoch muss man als Programmierer sehr auf Details achten und kann sich weniger auf die Nebenläufigkeit konzentrieren. Mittlerweile gibt es diverse Abhilfen in Form verschiedener Bestandteile des JDKs, die es erlauben, Multithreading mehr auf konzeptioneller Ebene zu betrachten.

Kapitel 11

beschreibt dies. Weitere fortgeschrittenere Themen, etwa Reflection, Annotations und Garbage Collection, werden in

Kapitel 12

behandelt. Das Thema Internationalisierung und damit die Besonderheiten, die bei der Unterstützung verschiedener Länder und Sprachen zu beachten sind, werden in

Kapitel 13

thematisiert.

Teil III

»

Wichtige Neuerungen in Java 12 bis 15

«

– In diesem Teil gebe ich einen Überblick zu den Neuerungen aus verschiedenen Java-Versionen bis hin zu dem im September 2020 aktuellen Release 15. Dazu startet

Kapitel 14

mit Erweiterungen in der Syntax. Danach werden diverse Ergänzungen in verschiedenen APIs sowie in der JVM vorgestellt. Insbesondere beschreibe ich auch das JMH-Framework zum Erstellen und Durchführen von Microbenchmarks.

Teil IV

»

Modularisierung

«

– Die umfangreichste Neuerung in Java 9 war wohl die Modularisierung: Sowohl das JDK als auch eigene Programme lassen sich damit strukturieren und in Module untergliedern.

Kapitel 15

behandelt dieses Themengebiet.

Nach der Lektüre dieser Teile sind Sie programmiertechnisch fit und bereit für das Schreiben eigener Anwendungen mit komplexeren Aufgabenstellungen. Auf dem Weg zu guter Software werden Sie aber vermutlich über das eine oder andere Problem stolpern. Wie Sie mögliche Fallstricke erkennen und beheben, ist Thema der folgenden Teile.

Teil V

»

Fallstricke und Lösungen im Praxisalltag

«

– Der fünfte Teil beschreibt anhand von Beispielen mögliche Probleme aus dem Praxisalltag und stellt passende Lösungen vor. Auf diese Weise wird ein tieferes Verständnis für einen guten Softwareentwurf erlangt.

Kapitel 16

betrachtet zunächst ausführlich mögliche Programmierprobleme, sogenannte »Bad Smells«. Diese werden analysiert und Lösungsmöglichkeiten dazu aufgezeigt. Diverse Umbaumaßnahmen werden in

Kapitel 17

als Refactorings vorgestellt.

Kapitel 18

rundet diesen Teil mit der Präsentation einiger für den Softwareentwurf wichtiger Lösungsideen, sogenannter Entwurfsmuster, ab. Diese sorgen zum einen dafür, ein Problem auf eine dokumentierte Art zu lösen, und zum anderen, Missverständnisse zu vermeiden, da die Entwickler eine eigene, gemeinsame Designsprache sprechen.

Teil VI

»

Qualitätssicherungsmaßnahmen

«

– Qualitätssicherung ist für gute Software elementar wichtig und wird in diesem

Teil VI

vorgestellt. Einige im Kapitel zu Bad Smells gewonnene Erkenntnisse werden in

Kapitel 19

zu einem Regelwerk beim Programmieren, sogenannten Coding Conventions, zusammengefasst. Um neue Funktionalität und Programmänderungen abzusichern, schreiben wir Unit Tests. Nur durch eine breite Basis an Testfällen haben wir die Sicherheit, Änderungen ohne Nebenwirkungen auszuführen.

Kapitel 20

geht detailliert darauf ein. Eine Qualitätskontrolle über Codereviews wird in

Kapitel 21

thematisiert. Zu einer guten Qualität gehören aber auch nicht funktionale Anforderungen. Diese betreffen unter anderem die Performance eines Programms. In

Kapitel 22

stelle ich daher einige Techniken zur Performance-Steigerung vor.

Anhang

– Zum besseren Verständnis der Abläufe beim Ausführen eines Java-Programms stellt Anhang A einige Grundlagen zur Java Virtual Machine vor.

1.3Konventionen und ausführbare Programme

Verwendete Zeichensätze

Im gesamten Text gelten folgende Konventionen bezüglich der Schriftart: Der normale Text erscheint in der vorliegenden Schriftart. Dabei werden wichtige Textpassagen kursiv oder kursiv und fett markiert. Englische Fachbegriffe werden eingedeutscht großgeschrieben. Zusammensetzungen aus englischen und deutschen (oder eingedeutschten) Begriffen werden mit Bindestrich verbunden, z. B. Plugin-Manager. Namen von Refactorings, Bad Smells, Idiomen sowie Entwurfsmustern u. Ä. werden bei ihrer Verwendung in KAPITÄLCHEN dargestellt. Sourcecode-Listings sind in der Schrift courier gesetzt, um zu verdeutlichen, dass dieser Text einen Ausschnitt aus einem realen Java-Programm wiedergibt. Auch im normalen Text werden Klassen, Methoden, Konstanten und Übergabeparameter in dieser Schriftart dargestellt.

Verwendete Abkürzungen

Im Buch verwende ich die in Tabelle 1-1 aufgelisteten Abkürzungen. Weitere Abkürzungen werden im laufenden Text in Klammern nach ihrer ersten Definition aufgeführt.

Tabelle 1-1 Verwendete Abkürzungen

Abkürzung

Bedeutung

API

Application Programming Interface

ASCII

American Standard Code for Information Interchange

GUI/UI

(Graphical) User Interface

IDE

Integrated Development Environment

JDK

Java Development Kit

JLS

Java Language Specification

JRE

Java Runtime Environment

JSR

Java Specification Request

JVM

Java Virtual Machine

OO

Objektorientierung

TDD

Test-Driven Development

UML

Unified Modeling Language

XML

Extensible Markup Language

Verwendete Java-Umgebungen und -Versionen

Weil aber ein Großteil der kommerziellen Java-Projekte auf LTS-Versionen beruht, bildet JDK 11 die Grundlage für die Beispiele im Buch – natürlich abgesehen von den Kapiteln zu den neueren Java-Versionen 12 bis 15.

Verwendete Klassen aus dem JDK

Werden Klassen des JDKs zum ersten Mal im Text erwähnt, so wird deren voll qualifizierter Name, d. h. inklusive der Package-Struktur, angegeben: Für die Klasse String würde dann etwa java.lang.String notiert. Dies erleichtert ein Auffinden im JDK. Im darauffolgenden Text wird zur besseren Lesbarkeit auf diese Angabe verzichtet und nur der Klassenname genannt. Zudem sind aus Platzgründen in den Listings nur selten import-Anweisungen abgebildet.

Im Text beschriebene Methodenaufrufe enthalten in der Regel die Typen der Übergabeparameter, etwa substring(int, int). Sind die Parameter in einem Kontext nicht entscheidend, wird auf deren Angabe aus Gründen der besseren Lesbarkeit verzichtet oder aber durch die Zeichenfolge … abgekürzt.

Download, Sourcecode und ausführbare Programme

Um den Rahmen des Buchs nicht zu sprengen, stellen die abgebildeten Programmlistings häufig nur Ausschnitte aus lauffähigen Programmen dar. Deren Formatierung weicht leicht von den Coding Conventions von Oracle1 ab. Ich orientiere mich an denjenigen von Scott Ambler2, der insbesondere (öffnende) Klammern in jeweils eigenen Zeilen vorschlägt. Dazu habe ich ein spezielles Format namens Michaelis_CodeFormat erstellt, dessen Anwendung nachfolgend gezeigt ist.

Abbildung 1-1 Konfiguration von Java Code Style –> Formatter

DownloadDieser Formatter steht ebenso wie der Sourcecode der Beispiele auf der Webseite

www.dpunkt.de/java-profi

zum Download bereit und ist in ein Eclipse-Projekt integriert. Viele der Programme lassen sich mithilfe von Gradle-Tasks (die wir in Kapitel 2 kennenlernen) ausführen. Deren Name wird in Kapitälchenschrift, etwa LOCALEEXAMPLE, angegeben.

Nacharbeiten nach Projekt-ImportNach dem erstmaligen Import müssen die Abhängigkeiten auf die externen Bibliotheken im Eclipse-Projekt mit dem Kommando gradle cleanEclipse eclipse neu initialisiert und auf Ihren Rechner aktualisiert werden.

IJava-Grundlagen, Analyse und Design

2Professionelle Arbeitsumgebung

Das Bearbeiten von Sourcecode ist eine wichtige und elementare Aufgabe bei der Softwareentwicklung. Genau wie Handwerker benötigen auch wir Softwareentwickler eine gut strukturierte Werkbank (Arbeits-/Entwicklungsumgebung) mit nützlichen Werkzeugen (Tools). In diesem Kapitel werden wir damit beginnen, eine Arbeitsumgebung einzurichten, die sowohl das Entwickeln erleichtert als auch Unterstützung beim Testen bietet und dadurch hilft, Fehler zu reduzieren.

Den zentralen Anlaufpunkt, unsere Steuerzentrale, bildet eine sogenannte integrierte Entwicklungsumgebung, kurz IDE. Ich motiviere in Abschnitt 2.1 den Einsatz einer solchen und nenne drei mögliche Kandidaten, wobei in diesem Buch die Wahl auf Eclipse als frei verfügbare IDE fällt. In Abschnitt 2.2 betrachten wir zwei Vorschläge zur Organisation eines Softwareprojekts, also zur Strukturierung von Sourcecode und anderen Dateien (Bilder, Texte, Testcode usw.). Abschnitt 2.3 beschäftigt sich dann mit dem Thema Versionsverwaltungen. Diese helfen dabei, die Dateien eines Projekts sicher zu speichern und verschiedene Versionen davon abrufen zu können. Dazu werde ich einführend auf zentrale und dezentrale Versionsverwaltungen am Beispiel der Open-Source-Tools CVS, Subversion (SVN) sowie Git und Mercurial eingehen. Die professionelle Softwareentwicklung umfasst nicht nur die Implementierung und die spätere Auslieferung, sondern vor allem auch das Testen unserer Programme. In Abschnitt 2.4 werfen wir daher einen kurzen Blick auf das Erstellen von Unit Tests mithilfe von JUnit. Selbst wenn viele Unit Tests existieren und unsere Programme sehr gewissenhaft testen, so wird es doch immer mal wieder zu unerklärlichem Programmverhalten oder gar Fehlern kommen. Für solche Fälle ist es zur Fehlersuche wünschenswert und hilfreich, das Programm schrittweise ausführen zu können, es bei Bedarf an einer bestimmten Stelle zu unterbrechen und dann die Wertebelegungen von Variablen überprüfen zu können. Das Ganze ist mithilfe eines sogenannten Debuggers möglich. Eine Einführung in die Thematik bietet Abschnitt 2.5. Ausgewählte lauffähige Stände wollen wir an Kunden veröffentlichen. Abschnitt 2.6 gibt einen Überblick über die Auslieferung (Packaging und Deployment) von Java-Programmen. Dazu lernen wir JAR-Dateien (Java Archive) kennen. Abschließend stelle ich die Vorteile eines von der IDE unabhängigen Build-Prozesses heraus, mit dem es möglich ist, Programme zu kompilieren, zu testen, zu starten, Auslieferungen zu erzeugen usw. In Abschnitt 2.7 beschreibe ich dazu die Build-Tools Maven und insbesondere Gradle. Letzteres wird zur Ausführung aller im Buch vorgestellten Beispielapplikationen genutzt.

2.1Vorteile von IDEs am Beispiel von Eclipse

Zum Bearbeiten von Sourcecode empfehle ich den Einsatz einer IDE anstelle von Texteditoren. Zwar kann man für kleinere Änderungen auch mal einen Texteditor nutzen, aber dieser bietet nicht die Annehmlichkeiten einer IDE: Dort können Kompiliervorgänge und Sourcecodeanalysen automatisch und im Hintergrund stattfinden, wodurch gewisse Softwaredefekte direkt noch während des Editierens erkannt und angezeigt werden können, etwa in einer To-do-/Task-Liste. IDEs bereiten zudem vielfältige Informationen auf. Das erlaubt unter anderem die Anzeige von Ableitungshierarchien und das Auffinden von Klassen über deren Namen. Auch das Verknüpfen der JDK-Klassen mit deren Sourcecode und das Anzeigen zugehöriger Dokumentation sind Vorteile von IDEs. Weiterhin werden automatische Transformationen und Änderungen von Sourcecode, sogenannte Refactorings, unterstützt.

Für Java bieten sich verschiedene IDEs an. Sowohl Eclipse als auch NetBeans sind kostenlos. IntelliJ IDEA gibt es als kostenlose Community Edition sowie als kostenpflichtige Ultimate Edition. Alle IDEs haben ihre speziellen Vorzüge, aber auch Nachteile. Entscheiden Sie selbst und besuchen Sie dazu folgende Internetadressen:

www.eclipse.org

www.jetbrains.com/idea

www.netbeans.org

Die genannten IDEs lassen sich durch die Integration von Tools, etwa Sourcecode-Checkern, Versionsverwaltungen, XML-Editoren, Datenbank-Tools, Profiling-Tools usw., erweitern. Im folgenden Text werde ich speziell auf Eclipse und entsprechende Tools eingehen. Nach der Lektüre dieses Kapitels haben Sie dann bereits eine Arbeitsumgebung, die professionelles Entwickeln ermöglicht. Im Verlauf des Buchs werden thematisch passende, arbeitserleichternde Erweiterungen vorgestellt.

Basiskonfiguration für Eclipse

Zur Fehlervermeidung und Qualitätssicherung empfiehlt es sich, den Sourcecode regelmäßig zu analysieren und dabei die Einhaltung gewisser Regeln und Standards zu forcieren. In einem ersten Schritt kann man dazu auf die in Eclipse integrierte Sourcecode-Prüfung zurückgreifen. Umfangreichere Tests bieten Tools wie Checkstyle, FindBugs und PMD (vgl. Abschnitt 19.4).

Die in Eclipse integrierten Sourcecode-Prüfungen lassen sich im Einstellungsdialog WINDOW –> PREFERENCES konfigurieren. Dort wählen wir im Baum den Eintrag JAVA –> COMPILER –> ERRORS/WARNINGS. Im zugehörigen Dialog nehmen wir Anpassungen in den Bereichen CODE STYLE, POTENTIAL PROGRAMMING PROBLEMS, UNNECESSARY CODE sowie NULL ANALYSIS vor. Abbildung 2-1 zeigt eine mögliche, sinnvolle Einstellung der Werte im Abschnitt CODE STYLE. Auch in den anderen Sektionen können Sie bei Interesse strengere Auswertungen wählen. Experimentieren Sie ruhig ein wenig mit den Einstellungen.

Abbildung 2-1 Konfiguration von Java –> Compiler –> Errors/Warnings –> Code style

Code styleMethoden, die genauso heißen wie die Klasse selbst, also dadurch sehr leicht mit einem Konstruktor verwechselt werden können, werten wir als Error. Ein unqualifizierter Zugriff auf Attribute wird ignoriert, genauso wie nicht-externalisierte Strings und die Möglichkeit, Methoden static zu machen. Alle anderen Werte setzen wir auf Warning.

Potential programming problemsKonvertierungen mithilfe von Auto-Boxing und -Unboxing stellen wir auf Warning. Eine versehentliche Zuweisung in einer booleschen Bedingung betrachten wir als Error. Alles andere stellen wir auf Warning.

Unnecessary codeUnnötige else-Anweisungen sollen ignoriert werden, da es lediglich eine Stilfrage ist, ob man bei Auswertung einer Bedingung durch das else die Behandlung des anderen Zweiges darstellen möchte oder nicht. Einen ungenutzten Exception-Parameter setzen wir auf ignore. Die restlichen Prüfungen stellen wir auf Warning.

Null analysisUm uns vor Problemen mit unerwarteten null-Werten und Zugriffen darauf zu bewahren, stellen wir in dieser Sektion alles mindestens auf Warning.

2.2Projektorganisation

Im Sourcecode erleichtert eine einheitliche Formatierung und eine sinnvolle Namensgebung die Verständlichkeit und gute Lesbarkeit. Wenn man das Ganze auf die Dateien eines Projekts überträgt, erleichtert eine einheitliche Projektstruktur die Orientierung in fremden (und auch in eigenen) Projekten. Daher stelle ich nun zwei bewährte Varianten vor, die Sie als Vorschlag für die Verzeichnisstruktur eigener Projekte nutzen können.

Als Erstes gehe ich auf die Projektstruktur ein, die entsteht, wenn man mit Eclipse ein Java-Projekt anlegt. Als Zweites beschreibe ich eine Projektstruktur, die sich durch die Verbreitung von Maven als Build-Tool als De-facto-Standard etabliert hat. Die Beispiele dieses Buchs folgen dieser zweiten Konvention.

2.2.1Projektstruktur in Eclipse

Wenn man Projekte mit Eclipse anlegt und deren Inhalt verwaltet, so verwendet man ein Hauptverzeichnis mit dem Namen oder Synonym des Projekts. Nahezu alle anderen Daten werden in Unterordnern abgelegt. Lediglich einige (in Eclipse zunächst ausgeblendete) Metadateien (.project und .classpath) findet man im Hauptverzeichnis. Die Projektstruktur wird zunächst grafisch dargestellt und danach kurz beschrieben:

+ <project-root>

|

+---src - Sourcecode unserer Applikation

| +---ui - Grafische Oberfläche

| +---FileDialog.java - Die Klasse FileDialog

|

+---test - Sourcecode der Unit Tests

| +---ui - Tests für die grafische Oberfläche

| +---FileDialogTest.java - Tests für die Klasse FileDialog

|

+---lib - Externe Klassenbibliotheken (JARs)

| +---junit_4.11 - Ordner zur Strukturierung

| +---junit.jar - Wichtig zum Übersetzen der Unit Tests

| +---hamcrest-core.jar - Von JUnit benötigt

|

+---config - Konfigurationsdateien

| +---images - Bilder

| +---texts - Sprachressourcen

|

+---docs - Dokumentation

+---generated-reports - Erzeugte Berichte (JUnit, Checkstyle usw.)

+---bin - Kompilierte Klassen und JAR der Applikation

Sourcecode und TestsDen Sourcecode legen wir im Verzeichnis src ab. Darunter erfolgt die Aufteilung in Form von Packages. Parallel dazu werden Tests in einem Ordner test abgelegt. Dabei verwenden wir hier eine Spiegelung der Package-Struktur des src-Ordners. Das bietet zweierlei Vorteile: Erstens trennt man so Tests und Applikationscode im Dateisystem, wodurch sich ungewünschte Abhängigkeiten leicht erkennen lassen und später bei Auslieferungen die Testklassen nicht Bestandteil des Programms sein müssen. Zweitens liegen die Tests dadurch logisch in gleichen Packages wie der korrespondierende Sourcecode,1 was den Zugriff auf alle Elemente des Packages (außer den privaten) möglich macht.

Weitere DateienIn der Regel nutzt man zur Realisierung von Projekten verschiedene Klassenbibliotheken. Selbst in diesem einfachen Beispiel besitzen wir durch die Testklasse eine Abhängigkeit zur JUnit-Bibliothek. JUnit wird durch Eclipse bereits mitgeliefert und automatisch verwaltet. Andere Bibliotheken (oder eine aktuellere Version von JUnit) werden in einem Ordner lib gesammelt. Dabei erleichtert eine gut gewählte Verzeichnishierarchie die Übersicht über die verwendeten Bibliotheken und deren Versionen. Häufig sind für ein Projekt auch verschiedene Konfigurationsdateien zu verwalten. Dazu bietet sich ein Ordner namens config an. Dort können z. B. Textressourcen für Sprachvarianten und Konfigurationen für Logging usw. abgelegt werden. Verschiedene Arten von Dokumentation speichert man im Verzeichnis docs.

Tipp: Bibliotheken (JARs) in Eclipse einbinden

Wenn Sie Klassen aus Bibliotheken nutzen wollen, so liegen diese in Form von JARs (Java Archive) vor. Um diese in einem Eclipse-Projekt zu nutzen, gehen Sie wie folgt vor: Klicken Sie auf Ihr Projekt und wählen Sie im Kontextmenü BUILD PATH –> CONFIGURE BUILD PATH und in dem erscheinenden Dialog wählen Sie links den Eintrag JAVA BUILD PATH und dort den Tab LIBRARIES. Mithilfe der Buttons ADD JAR… und ADD EXTERNAL JAR… können Sie die gewünschten Bibliotheken einbinden. Ersteres wählen Sie, wenn sich die JAR-Dateien innerhalb Ihres Projekts (z. B. im Verzeichnis lib) befinden. Mithilfe von ADD EXTERNAL JAR… kann man JARs auch aus externen Verzeichnissen einbinden, etwa einem dedizierten Installationsverzeichnis einer Datenbank o. Ä.

Beim professionellen Programmieren sollte die Verwaltung von Abhängigkeiten und das Einbinden von Fremdbibliotheken über ein Build-Tool wie Maven oder Gradle erfolgen. Details dazu beschreibt Abschnitt 2.7.

Generierte DateienGemäß der Faustregel »Trenne generierte Dateien von regulärem Sourcecode« werden generierte Dateien in separaten Verzeichnissen abgelegt. Vom Compiler generierte .class-Dateien liegen im Ordner bin. Durch Tests und andere Sourcecode-Prüfungen entstehende Berichte werden in einem Verzeichnis generated-reports gesammelt. Diese Aufteilung erleichtert die Übersicht und Trennung, was wiederum die später beschriebene Versionsverwaltung sowie die Automatisierung von Build-Läufen vereinfacht.

Auslieferungen und Releases

Normalerweise wird eine Applikation nicht nur innerhalb der IDE laufen, sondern vor allem als eigenständige Applikation. Häufig sollen davon auch verschiedene Versionen, sogenannte Releases, erzeugt werden. Einige davon stellen stabile Softwarestände dar und können als offizielle Version oder Auslieferung an Kunden übergeben werden.

Für die aktuelle Programmversion bietet sich die Speicherung in einem Ordner release an. Damit die Applikation tatsächlich unabhängig von der IDE ausgeführt werden kann, müssen im Ordner release alle benötigten externen Bibliotheken, Konfigurationsdateien usw. bereitgestellt werden (z. B. durch Kopie) oder zugreifbar sein. Deren Pfade müssen in den sogenannten CLASSPATH aufgenommen werden. Dies ist die Menge von Verzeichnissen und Dateien, in der die JVM nach Klassen und anderen Ressourcen, etwa Bildern, sucht und die als Startparameter der JVM gesetzt werden kann. Auf das Classloading gehe ich kurz in Anhang A ein.

+ <project-root>

|

+---release - Release-Ordner

+---lib - Kopie des lib-Verzeichnisses

+---config - Kopie des config-Verzeichnisses

+---app.jar - Applikation als JAR

Schwachpunkte der gezeigten Projektstruktur

Die dargestellte Verzeichnisstruktur eignet sich für viele Projekte recht gut, besitzt aber Schwachstellen. Zunächst einmal muss die Verzeichnisstruktur (bzw. Teile davon) für jedes Projekt erneut von Hand angelegt und auch gepflegt werden. Dabei besteht die Gefahr, dass sich Inkonsistenzen einschleichen: Heißt der Ordner mit den entstehenden Klassen bin oder build? Und wie derjenige mit den Fremdbibliotheken? In einem Projekt etwa lib, im anderen libs. Das setzt sich bei der Vergabe der Namen von Unterordnern fort: Wird ein solcher junit4 genannt oder junit4.11 oder aber junit_4.11?

2.2.2Projektstruktur für Maven und Gradle

Nachfolgend schauen wir uns die von Maven und Gradle genutzte und weitverbreitete Verzeichnisstruktur als Alternative zu der von Eclipse standardmäßig verwendeten an.

Einheitliches Projektlayout

Das Problem möglicher Inkonsistenzen bezüglich der genutzten Verzeichnisse für kompilierte Klassen, Fremdbibliotheken oder Reports usw. wird von den beiden Build-Tools Maven und Gradle adressiert, indem diese eine einheitliche Verzeichnisstruktur für alle Projekte fordern. Dadurch ist immer klar, wo sich Dateien gewünschten Inhalts befinden, etwa für Sourcen und Tests in den Verzeichnissen src/main/java bzw. src/test/java. Darüber hinaus benötigte Ressourcendateien werden wiederum in getrennten Verzeichnissen hinterlegt, nämlich wie folgt:

+ <project-root>

|

+---src

+---main

¦ +---java - Java-Klassen

¦ +---resources - Konfigurationsdateien

¦

+---test

+---java - Testklassen

+---resources - Konfigurationsdateien für Testklassen

Projektlayout am Beispiel