Objekte Tools Essentials  Band 1: Objekte - Wolfgang Rinser - E-Book

Objekte Tools Essentials Band 1: Objekte E-Book

Wolfgang Rinser

0,0
33,50 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.
Mehr erfahren.
Beschreibung

Ein Buch für Leute, die Spaß am Coding haben. Es basiert auf Java 9 und erklärt Syntax und Konzepte der Kernthemen. Es zeigt zudem einen Ansatz, den man als 'rationale Vorgehensweise' verstehen kann. Dieser wird als Rapid-Coding bezeichnet. Rapid-Coding umfasst eine Reihe von Techniken, die ein rasches und verlässliches Erstellen von hochwertigem Code ermöglichen. Die Objektorientierung selbst dient hier als Beispiel. Das Buch erklärt wie bei anderen Themen Syntax und involvierte Konstrukte, also alles, was ein Java-Entwickler in diesem Themenumfeld braucht. Es zeigt anhand einer schon bearbeiteten Aufga-benstellung, welche Tools die Aufgabe vereinfachen. Es demonstriert die Lösung der Aufgabe und ihre Kürze bei Verwendung dieser Tools. Sodann werden die Tools entwickelt. Das ist sozusagen Objektorientierung live. Aber der eigentliche Punkt ist die systematische Effizienz und Produktivität, die hier sichtbar werden und womit Softwareentwicklung allgemein betrieben werden kann. Der potentielle Leser sei allerdings gewarnt. In großen Teilen wird lediglich solide Entwicklungstechnik behandelt. Aber genau dies ist der Ausgangspunkt von Rapid-Coding. AUS DEM INHALT *** Eine kleine Java-Rundreise: Schritt-für-Schritt-Einführung der wichtigsten Sprachelemente und Syntaxkonstrukte *** Intro zu Rapid-Coding: Die Verteilung von Code, das Potential von Routine, die Trennung von Typ und Implementierung *** Objektorientierung: Das Denken in Objekten und das Konstruieren mit Objekten *** Module: Alles, was man darüber wissen muss und noch etwas mehr *** Lambdas: Von den anonymen Klassen zu Functionals und Methodenreferenzen *** Tools, ohne die es nicht geht: Exceptions, Threads, IO-Streams, Files.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB

Seitenzahl: 1355

Veröffentlichungsjahr: 2017

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.



Wolfgang Rinser

2. Auflage

Objekte Tools Essentials

Band 1: Objekte

Softwarekonstruktion mit Java 9

© 2017 Wolfgang Rinser

Verlag: tredition GmbH, Hamburg

978-3-7439-4057-4 (Paperback)

978-3-7439-4058-1 (Hardcover)

978-3-7439-4059-8 (e-Book)

Juli 2017:2. Auflage

Das Werk, einschließlich seiner Teile, ist urheberrechtlich geschützt. Jede Verwertung ohne Zustimmung des Autors ist unzulässig. Dies gilt insbesondere für die elektronische oder sonstige Vervielfältigung, Übersetzung, Verbreitung und öffentliche Zugänglichmachung.

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.

Inhalt

ÜBERSICHT

Fahrplan und Rapid-Coding

Das erste Anliegen - Verständliche Texte

Konventionen und Verabredungen

DAS SOFTWARE-UNIVERSUM

1. Das Buch der unbrauchbaren Softwareteile

2. Ein Anfang – aber nicht mehr

EINE KLEINE JAVA-RUNDREISE – TEIL 1

1. Intro

2. 90 Prozent - Ein Plan und ein Stück Code - Was ein Entwickler wissen muss

3. Methoden

3.1. Die Signatur von Methoden

3.2. Werden Argumente und Returnwerte kopiert?

3.3. Returntyp und return Statement

3.4. Aufteilung von Code in Methoden

3.5. Variabel lange Argumentlisten

3.6. Argumentprüfung

4. Lokale Variable, Blöcke, Scope und final

5. Die Grundregel für zusammengesetzte Ausdrücke

6. Weitere elementare Regeln und Begriffe

7. Zuweisung

8. Kombinierte Zuweisungen

9. Inkrement und Dekrement

10. Stringverknüpfung (+)

11. Bedingung (if/else)

12. Verzweigung (switch)

13. Der new-Operator

14. Gleichheits- und Identitäts-Operator

15. Logische Operatoren, Vergleiche, Verknüpfung von Bedingungen

16. Der Conditional-Operator

17. Zusammenfassung der Operatoren

17.1. Auswertungsreihenfolge

17.2. Auflistung nach Priorität

17.3. Bit-Operatoren, Bit-Komplement-Operator und Bit-Shift-Operatoren

18. Iterationen

18.1. Übersicht

18.2. Bedingungen und Zähler

18.3. Ablaufschema

18.4. break und continue

18.5. Iteration und robuste Programmierung

18.6. for/in

19. Elementare Programmiertechnik anhand eines Beispiels

19.1. Die Aufgabe

19.2. Start ohne Skrupel

19.3. Übersichtlicher Code

19.4. Zerlegung in Methoden

19.5. Welche Anforderungen bestehen und wer überprüft sie?

19.6. Aufsammeln der Zahlen

19.7. Abspaltung der Benutzereingabe

20. Objekte*

20.1. Bausteine

20.2. Methodenaufrufe

20.3. Anatomie von Klassen und Objekten

20.4. Statische Elemente

20.5. Referenzen, Nirvana und this

21. Typen und Interfaces*

21.1. Ein leichtgewichtiges Tool

21.2. Ableitung und Vererbung

21.3. Das Verbergen und das Abgreifen von Information

21.4. Upcast und Downcast

21.5. Typen

21.6. Interfaces erweitern Interfaces

22. Allgemeine Vererbung*

23. Packages, Import und private Typen

23.1. Packages

23.2. Nicht-public Typen

23.3. Package-Sichtbarkeit

23.4. Import-Statements

23.5. Static Imports

24. Module*

25. Exceptions*

26. Elementare Typen und ihre Verpackung in Objekten – Wrappers

27. Zahlen und Zufallszahlen

27.1. Literale und Arithmetik

27.2. Große Zahlen

27.3. Der Zahlengenerator Random

28. Konstanten, Konstanz und Unveränderbarkeit

29. Enums*

30. Threads*

31. Datum und Uhrzeit

31.1. Zeitstempel und Zeitdauer

31.2. Zusammensetzen, Beschränken und Kopieren

31.3. Tageszeit - LocalTime

31.4. Datum – LocalDate

31.5. Zeitzonen – ZonedDateTime

31.6. Alt - Date und Calendar

31.7. Formatieren von Datums- und Zeitangaben

31.8. Parsen

32. Performancemessung

33. Strings*

34. Arrays

34.1. Basics

34.2. Initialisierung, elementare Elementtypen und Referenzelemente

34.3. Elementtyp, Vergleichbarkeit und das Tool Arrays

34.4. Mehrdimensionale Arrays

35. Collections*

36. Generische Klassen*

37. Generische Methoden*

38. Maps*

39. Essentials

40. Guidelines

RAPID-CODING EINSCHUB 1

1. Was ist Rapid-Coding

2. Der Zeitfaktor

3. Die Aufgabe

4. Zerlegung und Verteilung

5. Alt-Bekanntes

5.1. Iterationen

5.2. Argumentprüfungen

5.3. Exceptions werfen

5.4. Konstanten vereinbaren

5.5. Es gibt sehr viel mehr

6. Ein kleiner Schritt

7. Ein großer Schritt

OBJEKTE

1. Einige kurze Fakten zu Objekten, die das Verständnis erleichtern

1.1. Man kann Java auch ohne Objekte nutzen

1.2. Man kann Java mit Objekten und ohne Objektorientierung betreiben

1.3. Instanzen und Objekte sind dasselbe

1.4. Wir konstruieren keine Objekte, sondern Klassen

1.5. Auch mit Objekten kann man Mist bauen

1.6. Klassen sind Typen

1.7. ‚Abstrakt’ bedeutet ‚nicht implementiert’

2. Fange einfach irgendwo an

2.1. Straight-forward

2.2. Einsatz der üblichen Tools

2.3. Behandlung der Eingabefehler

2.4. Kommentare

2.5. Der gesamte Code

2.6. Das prozedurale Denken

2.7. Zäher Code

3. Die Klarheit der Objekte

3.1. Spielerischer Einstieg

3.2. Details der Komponenten

3.3. Resümee

3.4. Die Lottostatistik

4. Die Basics

4.1. Der Blick auf das Ganze

4.2. Instanzdaten und Kapselung

4.3. Wege, um die Kapselung zu brechen

4.4. Klassen-Elemente

4.5. Interface-Elemente

4.6. Konstruktoren

4.7. Object

4.8. Probleme mit equals() und hashCode()

5. Implementierung der Lotto-Applikation

5.1. LottoTicket

5.2. Win

5.3. LottoDrawing

5.4. RealLottery

5.5. Zustandsprogrammierung bei RealLottery

5.6. Objekte als robuste Maschinen

6. Statische Elemente

6.1. Syntax und Übersicht

6.2. Baustein ohne Instanzen

6.3. Singleton

6.4. Verwaltung von Instanzen

7. Vererbung

7.1. Cube

7.2. Terminologie

7.3. Konstruktoren

7.4. Schwierigkeiten, die genaues Hinsehen erfordern

7.5. Eine Art von Superclass-Chaining

7.6. Den Typ einer Instanz kann man nicht verbergen

7.7. Overriding

7.8. Der Downcast

7.9. Konsequenzen von später Bindung

7.10. Aufbau der Instanzen

7.11. NationalLottery

7.12. Vererbung von Implementierung bricht abgeleitete Klassen

7.13. Ist ein Math ein Cube?

8. Erzwingen und Verhindern von Overriding

8.1. Abstrakte Methoden und abstrakte Klassen

8.2. final Methoden und Klassen

9. Cloneable

10. Comparable

10.1. Vergleichbarkeit und natürliche Ordnung

10.3. Comparatoren sortieren Elemente mit und ohne natürliche Ordnung

10.4. Comparatoren in der Lotto-Applikation

10.5. Nur einfache Anforderungen an Listener

11. Essentials

12. Guidelines

RAPID-CODING EINSCHUB 2

1. Das Beispiel

2. Das einfache Schema der Klassen

3. Konzept, Typ und Erfassbarkeit

4. Trennung von Typ und Implementierung

MODULE

1. Arbeiten mit und ohne Module

2. Gespräch über Module

3. Benannte Module und Kapselung

4. Freigaben

5. Module und Objekte

6. Im Kreis

7. Essentials

ANONYME KLASSEN UND LAMBDAS

1. Innere Typen

1.1. Intro

1.2. Wechselseitiger Zugriff

1.3. Noch eine neue Syntax: new

1.4. Wie der Compiler den freien wechselseitigen Zugriff sieht

1.5. Übersicht zu inneren Typen

2. Syntax und Einsatz von anonymen Klassen

2.1. Der definierende Typ

2.2. Drei oder vier Schritte zu einer Formel

2.3. Für anonyme Klassen können keine Konstruktoren geschrieben werden

2.4. Code für eine spätere Ausführung

2.5. Klasse oder Methode?

2.6. Fallbeispiel mit einer Defaultmethode

2.7. Adapter als simple Hilfsmittel

3. Essentials zu inneren Typen

4. Lambdas

4.1. Intro

4.2. Von den anonymen Klassen zu den Lambdas

4.3. Die Syntax der Lambdas

4.4. Lambda-Interfaces

4.5. Methodenreferenzen

4.6. Der nächste Schritt: Kombination von Lambdas

5. Intro zu Streams*

5.1. Was ist ein Stream?

5.2. Eine eigenartige Konzeption

5.3. Was enthält ein Stream?

5.4. Als Beispiel - Die Arbeits- und Funktionsweise von reduce()

6. Essentials zu Lambdas

7. Guidelines zu Lambdas

EXCEPTIONS

1. Wirf eine Exception

2. Eine einfache Entscheidung

3. Stack-Traces, Methodenlabyrinthe und Ariadne-Fäden

4. Die methodenübergreifende Struktur von try-catch

5. Der passende Exception-Handler

6. finally

7. Checked- und Unchecked-Exceptions

8. Mehrfach-Handler (Multi-Catch)

9. Wiederauswurf – Rethrow

10. Smarter Compiler

11. Ressourcen-Behandlung

11.2. Aufwendige Ressourcen-Freigabe mit finally

11.3. Die Automatismen von try-with-resources

12. Suppressed Exceptions

13. Selbst verfasste Exceptiontypen

14. Exceptions und Threads

15. UncaughtExceptionHandler

16. Exceptions tatsächlich behandeln

16.1. Die Wiederholung

16.2. Unterscheide Produktivzeit und Entwicklungszeit

16.3. Exceptions zur Entwicklungszeit verlässlich anzeigen

16.4. Die Unterscheidung von Checked- und Unchecked-Exceptions ist unnötig

16.5. Etwas suchen

16.6. Auf Bauteile verzichten

16.7. Jedes Bauteil braucht ein Fehlerkonzept

16.8. Bei allen Methoden Exceptions deklarieren und spezifizieren

17. Essentials

18. Guidelines

TEIL 2 DER JAVA-RUNDREISE – TOOLS, OHNE DIE ES NICHT GEHT

1. Class und Reflection

2. System-Properties

3. Logging

3.1. Der Standard-Logging-Framework

3.2. Austauschbare Implementierungen und Tag-basiertes Logging

3.3. Guidelines zum Logging

4. Intro zu Threads

4.1. Ein Ariadne Faden

4.2. Dem Faden folgen

4.3. Parallele Fäden

4.4. Threads sind leichtgewichtige Prozesse

4.5. Objektorientierung und parallele Abläufe sind zwei verschiedene Welten

4.6. Ausführung in nur einem Thread

4.7. Ausführung in zwei Threads

4.8. Threads erzeugen und starten

4.9. Auf einen Thread warten - join()

4.10. Thread-Zustände

4.11. Blockierte Threads

4.12. Eine kurze Exkursion zum Wait-Set

4.13. Einen Thread beenden

4.14. Dämonen

4.15. Zeitscheiben und kooperatives Verhalten

4.16. Priorität und Id

4.17. Auflistung der Threads

4.18. Timer

4.20. Essentials zu Threads

5. Streams

5.1. Intro

5.2. Streams verwenden

5.3. Einzelne Zeichen und Arrays

5.4. Streams können blockieren

5.5. Eingangs-Streams

5.6. Übersicht der Byte-Streams

5.7. Übersicht der Character-Streams

5.8. Ausgangs-Streams

5.9. Typische Stream-Verwendungen

5.10. Daten-Streams

5.11. Essentials zu Streams

6. Files

6.1. Pfade

6.2. Die Klasse File

6.3. Absolute und relative Pfade

6.4. Path

6.5. Files lesen

6.6. Files schreiben

6.7. Ressource-Pfade

6.8. Ein kleiner Test zu den Ressource-Pfaden

6.9. Standardcode: Files lesen

6.10. Standardcode: Files schreiben

6.11. Directory Iterator und list()

6.12. Mehr über Files: copy(), move(), find() und walk()

6.13. Files und das Visitor-Pattern

6.14. Übersicht der Files-Methoden

6.15. Essentials zu Files

ANHANG

1. Die erste Klasse

2. Java und der JDK

2.1. Sourcecode, Bytecode und Virtuelle Maschine

2.2. Java-Versionen

2.3. Download des JDK

2.4. Installation des JDK

2.5. Die Path-Umgebungsvariable

2.6. Einige Tools

2.7. Entwicklung ohne und mit Entwicklungsumgebung

3. Modulepath und Classpath

3.1. Eine Liste von Orten, um nach referenzierten Typen zu suchen

3.2. Modulepath und Modulesourcepath

3.3. Disassembler

3.4. Vermeintliche und tatsächliche Classpath-Probleme

4. Compiler

4.1. Einfache Aufrufe

4.2. Module

5. Archive

5.1. Übersicht

5.2. Modulare Jar-Files

6. Interpreter

7. Eclipse-Intro

8. Das Richtige tun

INDEX

Abbildungen

Abbildung 1: Java-Arrays und Indizes

Abbildung 2: Einige Oberflächenelemente der Lotto-Applikation

Abbildung 3: Die Idee des Drawing-Bausteins

Abbildung 4: Leistung des Drawing-Bausteins

Abbildung 5: Bausteine und ihr Zusammenwirken

Abbildung 6: Der Typ Gambler

Abbildung 7: Der Typ Person

Abbildung 8: Ein ClassRoom für BirthDayPersons

Abbildung 9: Der Basistyp steht per Konvention oben, der abgeleitete Typ unten

Abbildung 10: Drei Example-Instanzen mit der Instanz ihrer Klasse

Abbildung 11: Die Standard-Log-Handler

Abbildung 12: Logger und Handler sind die Hauptakteure beim Logging

Abbildung 13: Zwei Welten: Character-Rohre und Byte-Rohre

Abbildung 14: Vier unabhängige Grundtypen: InputStream, OutputStream, Reader und Writer

Abbildung 15: Die vier Stream-Grundtypen und zugeordnete Interfaces

Abbildung 16: Filter - Streams werden als Rohre ineinander gesteckt

Abbildung 17: Reader und InputStream

Abbildung 18: Die Byte-Klassen des Stream-Frameworks

Abbildung 19: ByteArrayInputStreams werden zu einer Sequenz von Streams verknüpft

Abbildung 20: Die Character-Klassen des Stream-Frameworks

Abbildung 21: Writer und OutputStream

Abbildung 22: DataInputStream und DataOutputStream

Übersicht

Fahrplan und Rapid-Coding

Gute Konstruktionen basieren auf gutem Coding. Das Anliegen dieses Buches heißt Coding. Wir wollen gute Lesbarkeit, Stabilität, Einfachheit, Effizienz und Schnelligkeit. Wir wollen, dass Code solide gebaut ist und nicht bei kleinsten Änderungen im Umfeld wieder nachgearbeitet werden muss. Wir wollen, dass sein Aufbau einfach zu verstehen ist und seine Strukturen und Prinzipien leicht zu erfassen sind. Und wir wollen einen Ansatz, der uns systematisch und auf Dauer gestattet, Code schnell und sehr effizient zu erstellen. Das Stichwort dafür lautet: Rapid-Coding.

Rapid Coding umfasst eine Reihe von Techniken und Vorgehensweisen, die ein rasches und verlässliches Erstellen von hochwertigem Code ermöglichen. Neben der Grundschnelligkeit der Code-Erstellung sind Lesbarkeit und Verständlichkeit weitere Punkte, die uns interessieren. Die Verteilung von Code auf Methoden gehört zu den ersten und elementarsten Hilfsmitteln für verständliche Formulierungen. Man kann diese und andere robuste Techniken, die zu gutem Coding führen, anhand von simplen Beispielen darstellen. Und man könnte sich lange und mit Vergnügen bei den einfachen Beispielen und ihren Implikationen für Coding-Technik) aufhalten. Man würde viel dabei erfahren, was andern Orts - mit dem Fokus auf bloße Syntax - zu kurz kommt.

Es wartet jedoch mit der Objektorientierung ein Ansatz auf uns, dessen Leistungsfähigkeit die der prozeduralen Programmierung bei Weitem übersteigt. Der Schritt in die objektorientierte Welt ändert unsere Sichtweise auf Software und Coding – und die Änderung ist radikal. Es ergeben sich sowohl für das Denken über Probleme und Modelle als auch bei Konzeptionen und Strukturen ganz andere Möglichkeiten. Objektorientierung und Rapid-Coding sind zudem keine Gegensätze, sondern verschmelzen zu einer wunderbaren Einheit.

Entwickler werden Lambdas und Exceptions mit unterschiedlicher Zuneigung betrachten. Wir haben aber nur bei den Lambdas die Wahl, ob wir sie in unseren Programmen einsetzen. Hat man sich jedoch einmal an sie gewöhnt, wird man sie nicht mehr missen wollen. Bei den Exceptions haben wir diese Wahl nicht. Ohne Fehler-Behandlung läuft kein Java-Programm. Die vermeintlichen Alternativen haben allesamt große Handicaps. Aus diesen Gründen werden beide Techniken - Lambdas und Exceptions – sehr ausführlich behandelt.

Das vorliegende Buch setzt den Fokus auf elementare Programmierung, objektorientierte Programmierung und die Lambdas. Das erste braucht man, weil alles andere darauf aufbaut, das zweite, weil die Objekte Konstruktionen und Modelle eigentlich erst greifbar machen, und die Lambdas braucht man, weil sie viele Implementierungsaufgaben vereinfachen. Dieses Grundmaterial wird ergänzt durch die Module, die Java 9 etwas brisant machen, die Behandlung der Exceptions, um die man nicht herumkommt, und die Vorstellung einer Reihe von Tools, um die man gleichfalls nicht herumkommt. Rapid-Coding wird in diesem Buch vorbereitet. Es gibt zwei kleine Einschübe dazu, aber zunächst nicht mehr. Stattdessen kommen Klarheit der Formulierung, Standards, Präzision und selbst Einfachheit als unterschwellige Themen immer wieder zur Sprache. Diese Punkte sind zentral im Rapid-Coding-Ansatz und treiben ihn voran.

Die erste Java-Rundreise

-Ein Plan und ein Stück Code - Was ein Entwickler wissen muss

-Aufteilung von Code in Methoden

-Iteration und robuste Programmierung

-Elementare Programmiertechnik anhand eines Beispiels

-Objekte, Referenzen, Nirvana und this

-Erste Übersicht zu Typen, Interfaces und Vererbung

-Die bekannten Tools: Exceptions, Enums, Threads, Strings, Arrays, Collections, Maps und Generics

Die erste Rundreise macht Leserinnen und Leser mit den Java-Grundlagen vertraut. Sie lernen dabei alles an Syntax kennen, was Sie für das Schreiben von prozeduralem Code brauchen. Unterstützt wird dieses Kapitel vom Anhang, der weitere Informationen zum JDK und zum allgemeinen Arbeiten mit Java bietet. Die erste Rundreise enthält neben der grundlegenden Syntax einführendes Material zu vielen Themenpunkten, die häufig benötigt werden, so dass die Einführung relativ breit angelegt ist. Leserinnen und Leser werden dabei auch mit Aspekten und Themen bekannt gemacht, die erst in späteren Kapiteln tiefer ausgeführt werden. Derartige Themen sind mit einem Stern (*) gekennzeichnet.

Objekte

-Warum Objekte Klarheit bringen und wie sie dies tun

-Die Aufgaben einer Klasse

-Der Sprung in eine andere Art von Software – Das Denken in Objekten

-Der in sich abgeschlossene Baustein

-Objektorientierung übersetzt Konzepte in Objekte

-Diesmal vertieft: Typen, Interfaces und Vererbung

Das Kapitel zur Objektorientierung führt in das Denken mit Bausteinen ein und behandelt die zugehörige Java-Syntax. Mit vorhandenen Bausteinen zu arbeiten, ist manchmal trivial. Bausteine richtig zu erstellen, ist weniger trivial, aber auch nicht unbedingt schwierig. Mit Bausteinen zu konstruieren, die noch nicht vorhanden sind, ist zunächst etwas eigen, passt aber gut in das typische objektorientierte Vorgehen. Das Kapitel zeigt die Eigenheiten dieser Konstruktions- und Denkform. Es erklärt die Grundlagen und vermittelt vor allem die mentale Haltung, welche die Objektorientierung prägt.

Module

-Module sind das zentrale Thema in Java 9. Markus und Sonja, ein Freak und eine eigenwillige Entwicklerin, erschließen die Bedeutung der Module in einigen Gesprächen

-Wozu brauchen wir Module?

-Von der Abschließung der Module bis zu starker Kapselung und deep Reflection

-Alles, was Sie über Module wissen müssen, zusammengefasst in den Essentials dieses Kapitels

Das Thema der Module rumort in Java und berührt viele Detailthemen. Ihre Einführung hat fundamentalere Auswirkungen als seinerzeit die Einführung der Generics in Java 5 oder die der Lambdas in Java 8. Auch die JDK-Tools wie Compiler, Archiv-Tool und Interpreter sind stark betroffen. Sie sollten in Java 9 anders bedient werden als in Java 8. Viele Infos zu den Modulen findet man deshalb auch im Anhang, in dem der JDK und seine Tools beschrieben werden.

Lambdas

-Lambdas sind anonyme Klassen mit einer einfacheren Verwendung als diese

-Lambda-Interfaces

-Functionals

-Methodenreferenzen

-Eine kleine Einführung in eine neue Welt: Die Behandlung von Mengen durch Streams

Das Teilkapitel über anonyme Klassen behandelt zunächst ein Thema, für das sich typische Java-Entwickler nicht wirklich interessieren. Dennoch wird die Syntax ausführlich erklärt. Das Kapitel erarbeitet einige wichtige und merkbare Aussagen und kommt dann zum eigentlichen Grund für die ganze Mühe, nämlich zu den Lambdas. Dort wird der Stoff aber keineswegs leichter – ganz im Gegenteil. Die Abhandlung der Lambdas ist für Leserinnen und Leser sicherlich anstrengend. Diejenigen unter Ihnen, die zu Anfang des Buches noch Java-Neulinge sind und das Buch ohne Praxisbegleitung bearbeiten, stehen an dieser Stelle möglicherweise vor einer großen Herausforderung. Das vorliegende Buch bietet jedoch genügend Anregungen und Codebeispiele, mit denen man selbständig weiterarbeiten und sich damit beliebig viel praktische Erfahrung verschaffen kann.

Exceptions

-Wirf eine Exception

-Stack-Traces, Methodenlabyrinthe und Ariadne-Fäden

-Ein Code-Wächter

-Checked- und Unchecked-Exceptions

-Try-With-Resources und Suppressed-Exceptions

-Exceptions tatsächlich behandeln

Die Exceptions sind Standard-Java-Stoff und sozusagen eine Pflichtveranstaltung. Das Thema ist nicht so kurzweilig wie die erste Rundreise, es ist nicht so interessant wie die Objektorientierung, nicht so aufregend wie Lambdas und nicht so neu wie die Module. Aber die Exceptions sind unumgänglich. Man muss da einfach durch. Und man muss da auch mit guter Aufmerksamkeit durch. Das Kapitel enthält einiges Material, wie man Code mit Exception-Handling schreibt. Da gibt es sehr viel mehr als nur Syntax. Man schreibt in der Praxis kaum einmal eine Seite Code, ohne mit Exceptions in Berührung zu kommen. Und sobald man es mit Exceptions tatsächlich zu tun hat, sollte man wissen, was es über sie zu wissen gibt und wie man sie handhabt.

Die zweite Java-Rundreise

-Kurze Intros zu Class, Reflection und System-Properties

-Sichtbarmachung von Abläufen mit Standard-Logging

-Das Notwendigste zu den Threads

-Ebenfalls unverzichtbare Tools: Die sehr eigene Welt der IO-Streams

-Files, Ressource-Pfade und das Standardvorgehen beim Lesen und Schreiben von Dateien

Die zweite Rundreise ist das, wonach es sich anhört: ein bequemer Ausflug. Mit Class und Reflection wird ein abseitiges Thema angeschnitten, weil man hin und wieder damit zu tun hat. Das Ganze bleibt aber ohne viel Tiefgang, weil Reflection (zum Glück) nicht zum essentiellen Konstruktionswissen zählt. Beim Thema Logging ist das anders, dies kann durchaus nützlich sein. Entsprechend gründlich wird es auch behandelt. Bei den Threads hingegen sind wir zufrieden, wenn wir hinterher ungefähr wissen, mit was man es da eigentlich zu tun hat. Demgemäß ist dieses Teilkapitel auch als ‚Intro’ betitelt. Anders ist es wiederum bei Streams und Files. Diese Themen werden gründlich und abschließend (wenn auch nicht erschöpfend) behandelt.

Anhang

-Falls alles andere versagt: Eine besondere Hilfestellung beim Schreiben der ersten Klasse

-Der JDK und seine Versionen – Eine Übersicht auf einer Seite

-Modulepath und Classpath

-Compiler, Interpreter und das Archiv-Tool

-Eine sehr kurze Intro zu Eclipse

Das erste Anliegen - Verständliche Texte

Betrachten Sie das folgende Stück Code. Auf seinen genauen Inhalt kommt es hier nicht so sehr an:

Dieses kleine Beispiel zeigt Java-Code. Um diesen zu schreiben, muss man einige Regeln beachten, mit denen wir uns befassen werden. Aber dieser Code ist kein besonders gut verständlicher Text. Man könnte sagen: Software sieht nun mal so aus. Doch das ist Nonsense. Wir können Software in völlig unlesbarer Form schreiben und wir können sie in gut verständlicher Form produzieren. Beides geht und das obige Beispiel ist keines von beiden. Wir sind damit nicht zufrieden. Denn wir wollen und brauchen grundsätzlich gut verständlichen Code. Wir wollen kleine und größere Systeme in Software erstellen. Und je umfangreicher die Systeme werden, desto größer ist die Notwendigkeit von verständlichen Texten. Wir brauchen Codeformulierungen, die super einfach lesbar und erstellbar sind. Etwa Code in dieser Art:

Ob die Bedeutung des Ausdruck: ‚PrimeTester.isPrime(number)’ tatsächlich jedermann zugänglich ist, ist hier nicht die richtige Fragestellung. Selbstverständlich setzen wir bei unseren Konstruktionen eine fachliche Voreingenommenheit voraus, die beispielsweise die Leistung von isPrime() einordnen kann. Aber darüber hinaus erheben wir beim Schreiben von Software grundsätzlich den Anspruch, dass wir mit lesbaren Texten operieren. Die Implementierung von isPrime() könnte dieses Aussehen haben:

Die hypothetischen Komponenten Eratosthenes, Atkin und Fermat werden hier als gegeben vorausgesetzt. Sie sehen nun den Unterschied zum ersten Codebeispiel. Der Code von PrimeTester.isPrime() ist gut lesbar. Für jemand, der fachlich versiert ist, ist diese Implementierung wie ein offenes Buch. Es ist verständlicher Text, der in Java verfasst ist. Und der Leser muss noch nicht einmal Java können, um ihn zu verstehen. Uns ist klar, dass Code wie der im ersten Beispiel nicht immer vermieden werden kann. Aber prinzipiell kann jedes Stück Code entweder verständlich formuliert oder verständlich verpackt werden.

Die Forderung, mit verständlichen Texten zu arbeiten, ist in diesem Buch für lange Zeit eine unserer Leitlinien und eine Vision, die uns führt. Oftmals ist sie nur implizit vorhanden, sozusagen versteckt in unserem Hinterkopf, denn wir sind auf weiten Strecken – im Grunde große Teile des Buches hindurch – auch mit anderen Themen befasst. Wir müssen lernen, wie man elementaren Java-Code schreibt. Dann müssen wir sehen, wie wir zu umfassenderen Konstruktionen kommen, ohne die Sicherheit und Stabilität von elementarem Code aufzugeben. Und gelegentlich arbeiten wir auch daran, wie man dies auf verlässliche und schnelle Art macht (Rapid Coding).

Wir werden bei der Verfolgung unserer Vision Schritt für Schritt Techniken und Strategien entfalten, die uns die großen Konstruktionen erschließen. Aber dabei geht es sehr langsam voran. Denn das elementare Coding steht immer wieder im Zentrum unserer Bemühungen. Dieses ist die Basis und muss besonders gut beherrscht werden. Wir lernen Techniken, die uns Sicherheit geben, mit denen wir verlässlich konstruieren können, die uns schnell (sehr schnell) machen und die uns nachts gut schlafen lassen. Aber das elementare Coding wird dabei im Fokus bleiben und ein wichtiges Fundament bilden.

Konventionen und Verabredungen

Guidelines, Essentials und Merksätze

Zu den meisten Themen gibt es Essentials. Diese stellen den Inhalt des vorangehenden Kapitels in Kurzform dar. Die Essentials haben zwei Zielsetzungen. Zum einen ist das die Zusammenfassung, zum anderen die Kürze. Eine Zusammenfassung (in anderen Worten) soll zudem die Wahrscheinlichkeit für den Leser erhöhen, eine verständliche Erklärung zu den gerade aktuellen Punkten zu finden. Die Essentials sind dafür gedacht, zu einem gegebenen Stoff Zusammenhänge zu rekapitulieren oder auf knappem Raum nach bestimmten Informationen suchen zu können.

In den Text sind zuweilen kurze und im Layout hervorgehobene Statements eingestreut. Diese kann man als Merker, Merksätze oder Grundaussagen auffassen. Ihr Zweck ist es, die Aufmerksamkeit auf einen Zusammenhang zu richten, der das Erfassen einer Thematik erleichtert. Merker sind auf das erste Kennenlernen eines Themas ausgerichtet. Sie wollen einen Pflock einschlagen und eine feste Aussage auf einem noch schwankenden Boden machen. Sie wollen die Aufmerksamkeit auf einen Punkt fokussieren. Bei wiederholtem Lesen werden die Merker - anders als die Essentials - überflüssig.

Zu einigen Themen gibt es Guidelines. Diese stehen wie die Essentials am Ende eines Kapitels und enthalten Ratschläge und Empfehlungen.

Die *-Kapitel

Hauptsächlich in der ersten Rundreise befinden sich Kapitel, die mit einem Stern (*) gekennzeichnet sind. Sie besprechen Themen, die zu einem späteren Zeitpunkt ausführlich behandelt werden. Verständnisprobleme in diesen Kapiteln sollte man deshalb nicht allzu ernst nehmen, sondern eher als Anregung betrachten. Aber auch sonst ist Geduld eine schöne Tugend. Gerade auf der ersten Rundreise treffen Sie öfters auf Syntax, die erst später genauer erklärt wird. Zwei Quellen für schnelle Erklärungen, die man bei Schwierigkeiten als erstes konsultieren sollte, sind allgemein das Glossar und im Speziellen die Essentials des betreffenden Kapitels. Zu einigen der mit einem * gekennzeichneten Kapitel gibt es die ausführliche Behandlung nicht in diesem Buch, sondern im dem Folgeband ‚Tools’.

Das Glossar

Im Anhang dieses Buches sollte sich ein relativ umfangreiches Glossar befinden. Das war der Plan. Der ursprüngliche einleitende Text zum Glossar war dieser:

„Der Leser kann dort Begriffe nachschlagen oder sich zu Stichworten weitere Informationen besorgen. Das Glossar ist zusammen mit den Essentials der einzelnen Kapitel eine Alternative zu erklärendem Text. Leserinnen und Leser sollen mit dem Glossar über eine Möglichkeit verfügen, zu allen neu auftauchenden Begriffen eine kurze erste Erklärung zu erhalten. Wenn man beispielsweise in den einführenden Abschnitten auf die Begriffe ‚abstrakt’, ‚Referenzvariable’ oder ‚Nirvana’ stößt und damit nicht viel anfangen kann, so ist das ein Fall für das Glossar.“

Dass es das Glossar in diesem Buch nun doch nicht gibt, hat vor allem Platzgründe. Das Glossar wird stattdessen als eigene Publikation parallel zu diesem Buch erscheinen.

Konventionen

In diesem Buch werden Methodennamen durchgehend mit runden Klammern geschrieben. ‚main’ beispielsweise kann eine Variable sein oder vielleicht auch ein Threadname. Mit ‚main’ ist jedoch keine Klasse gemeint, denn Typnamen werden durchgehend groß geschrieben (wie etwa Example oder String). Und mit ‚main’ ist auch keine Methode gemeint, denn die würde als main() geschrieben werden.

Eine kleinere Schwierigkeit beim Schreiben über Software besteht in der Unterscheidung zwischen Standardtypen (die mit dem JDK mitgeliefert werden) und den selbst-verfassten Typen des Autors. Aus dem Kontext heraus ist die Unterscheidung zumeist klar. Standardtypen werden in der Regel bei der ersten Erwähnung als solche bezeichnet. Das zweite Hilfsmittel der Unterscheidung ist die Angabe der Packages. Standardtypen residieren grundsätzlich in den Packages java oder javax. Selbst-verfassten Typen residieren niemals in diesen Packages.

Es gibt einige wenige Grafiken. Kursive Schrift in Grafiken für Typ- oder Methodennamen hat gemäß UML grundsätzlich die Bedeutung von ‚abstrakt’, also von nicht-implementiert.

Codebeispiele

Ein Buch über Software lebt von Codebeispielen. Bei deren Darstellung im Buch wird darauf geachtet, dass die seitenverschlingende Wiederholung von ähnlichen Codepassagen vermieden wird. Vor allem auf die nochmalige Darstellung eines präsentierten Beispiels als Ganzes am Kapitelende wird verzichtet. Dennoch kommt es vor, dass einander ähnlich sehende Codestücke gezeigt werden, um im Vergleich irgendwelche Besonderheiten hervorzuheben.

Bei der Darstellung von Code in diesem Buch werden Schlüsselwörter durch Fettdruck hervorgehoben. Schlüsselwörter sind Elemente der Sprache, die für den Compiler eine besondere Bedeutung haben und die deshalb als Bezeichner für Variable, Typnamen oder Methodennamen nicht verwendet werden dürfen.

Obwohl der Autor die Meinung vertritt, dass Leserinnen und Leser dann am meisten von den Beispielen profitieren, wenn Sie deren Code selbst schreiben, sind die größeren Beispiele dieses Buches in einem .zip-File verfügbar. Der Sourcecode kann auf der Seite www.rinser.info heruntergeladen werden siehe dort den Link „Downloads“). Das .zip-File entpacken Sie durch Doppelklick. Das .jar-File, das Sie dann erhalten, müssen Sie mit dem Archiv-Tool des JDK entpacken.

Wer soll dieses Buch lesen?

Jeder Entwickler, der schon einmal in irgendeiner Sprache Code geschrieben hat, sollte dieses Buch lesen können. Leute mit Java- und C/C++-Kenntnissen werden sich dabei leichter tun als andere.

Gefundene Fehler

Meldungen von gefundenen Fehlern sind sehr willkommen, egal ob es sich um Rechtschreibfehler, inhaltliche Fehler oder um Fehler im dargestellten Code handelt. Hilfreich ist eine Mail an [email protected] mit Angabe des Kapitels, der Seite und der Abschnittsnummer (vom Beginn der Seite an gezählt) und einer kurzen Beschreibung des Fehlers. Die Mail sollte idealerweise den Betreff: ‚Objekte’ enthalten und eine Klassifizierung nach ‚Tippfehler’, ‚Inhaltlicher Fehler’ oder Codefehler’.

Das Software-Universum

Legen Sie sich ein Tagebuch zu. Nennen Sie es das „Buch der unbrauchbaren Softwareteile“ (BUST). Notieren Sie darin jede Komponente, die Sie erstellt haben und die nicht mehrfach verwendbar ist. Und notieren Sie jeweils sorgfältig den Grund, warum Sie schon wieder ein Stück Code für den Müll geschrieben haben

Nicht-dokumentierte Software ist nicht wiederverwendbar

Software, von der man den Code lesen muss, um zu wissen, was sie tut, ist nicht wirklich wiederverwendbar

Vor allem müssen wir aufhören, in Lösungen zu denken. Lösungen sind nahezu niemals wiederverwendbar

1.Das Buch der unbrauchbaren Softwareteile

2.Ein Anfang – aber nicht mehr

 

1. Das Buch der unbrauchbaren Softwareteile

Software bietet tausend Möglichkeiten. Es gibt mannigfache Wege, etwas zu konstruieren. Die Freiheit, was wir bauen und wie wir es bauen, ist unbegrenzt. Wir können raffinierte Algorithmen ersinnen, um gegebene Probleme zu lösen oder um bestehende Lösungen zu verbessern. Wir können jeden gewünschten Aspekt eines gegebenen Systems in Software übertragen. Und wir können Systeme in Software erfinden, die es in der realen, fassbaren Welt nicht gibt. Die Vielfalt an Programmen, Maschinen, Bauteilen, Konstruktions-Ideen, Techniken und Vorgehensweisen ist kaum zu benennen.

Ob wir mittelalterliche Handschriften analysieren, die Dynamik von physikalischen Abläufen berechnen oder Verkehrsströme simulieren, wie auch immer die zu erstellenden Systeme aussehen, jeder Softwareentwickler, der fachliches Wissen mit technischem Geschick kombiniert, kann sie bauen. Dies geschieht selbstverständlich mit unterschiedlichem Erfolg, in allen Qualitätsabstufungen und mit sehr verschiedenem zeitlichen Aufwand. Aber es gibt für die Konstruktion eines beliebigen Systems in Software keine prinzipiellen Voraussetzungen. Man braucht dazu keine besonderen Maschinen und keine teuren Werkzeuge. Ein Entwickler, der eine bestimmte Idee hat, kann unmittelbar damit beginnen, sie umzusetzen. Und er muss dazu keineswegs die bekannten Techniken und Ideengebäude verwenden. Software ist beliebig formbar und konstruierbar.

Im September 1990 veröffentlichte die amerikanische Kolumnistin Marilyn vos Savant das Ziegenproblem:

„Stellen Sie sich vor, Sie müssten als Teilnehmer an einer Gameshow eine von drei Türen auswählen. Hinter einer Tür befindet sich der Gewinn, ein Auto, hinter den beiden anderen befinden sich dagegen Ziegen. Sie wählen Tür Nr. 1 und der Showmaster, welcher weiß, was sich hinter den jeweiligen Türen befindet, öffnet eine andere Tür, z. B. Tür Nr. 3, hinter der eine Ziege erscheint. Nun fragt er Sie, ob Sie bei Tür Nr. 1 bleiben oder ob Sie stattdessen Tür Nr. 2 wählen wollen. Sollte man besser wechseln“ Frei nach de.wikipedia.org, Ziegenproblem)

Stellen Sie sich weiter vor, dass Sie sich mit Ihren Kolleginnen und Kollegen über die Beantwortung der Frage und die korrekte Lösung des Problems nicht einig werden. Eine Ihrer möglichen Optionen besteht darin, das Problem durch Software zu lösen. Man verfährt dabei nach dem Monte-Carlo-Verfahren. Man macht Tausend oder auch eine Million Versuche und verteilt Fahrzeug und Ziegen jedes Mal zufällig hinter den drei Türen. Dann zählt man die Treffer (für den Gewinn des Fahrzeugs), die man hat, wenn man von Tür 1 wechselt, und die Treffer, wenn man nicht wechselt. Teilt man die Zahl der Treffer ohne Türwechsel durch die Zahl der Versuche, so erhält man eine Quote von etwa 33 Prozent, wenn nur die Zahl der Versuche groß genug ist. Für die Trefferquote bei einem Wechsel der Tür liefert ein Durchlauf der Simulation diese Daten:

Doors: 3 trials: 1000000000 winRate: 0.66666967 Duration: 35.431s

Der springende Punkt ist hier nicht das Ergebnis des Tests. Der springende Punkt ist, dass wir im Handumdrehen zu einer Fragestellung ein kleines Programm schreiben können. Und so wie wir in relativ kurzer Zeit zu diesem Problem ein Stück Software erstellen, so können wir zu jedem Thema, das uns interessiert, Software schreiben, die etwas behandelt, berechnet, analysiert oder einfach nur grafisch darstellt.

Software ist ein eigenes Universum und mit Software werden eigene Welten geschaffen. Software ist ein Betätigungsfeld mit einem extremen Potential. Wir haben darin alle Freiheiten. Wir können nahezu alles in Software konstruieren, was uns einfällt, und wir können es auf tausend verschiedene Weisen tun. Diesen unglaublichen Möglichkeiten, die Software auf der einen Seite jedem einzelnen Entwickler bietet, steht auf der anderen Seite ein gewisser sanfter aber dennoch nachdrücklicher und dauerhafter Zwang gegenüber. Nämlich der Zwang, Software möglichst rational und effizient zu entwickeln. Dabei handelt es sich nicht wirklich um einen Gegensatz. Die potentielle Freiheit, beliebige Systeme bauen zu können, wird erst dann zu einer tatsächlichen Möglichkeit, wenn wir es schaffen, unsere Konstruktionen auch in begrenzter Zeit umzusetzen. Der Traum von den unbegrenzten Möglichkeiten von Software ist eng an die Bedingung geknüpft, dass wir für die Realisierung einer Konstruktion nicht beliebig lange brauchen. Um Spielräume und Bewegungsfreiheit zu haben, brauchen wir eine bestimmte Effizienz in der Umsetzung unserer Ideen und Konstrukte. Um im Software-Universum Freiräume und Gestaltungsmöglichkeiten zu haben, muss man Implementierungen mit hoher Produktivität erstellen können. Wenn man sich im Schneckentempo bewegt, ist Bewegungsfreiheit nicht wirklich gegeben.

Es liegt auf der Hand, dass uns erst die Geschwindigkeit der Umsetzung die Potentiale von Software eigentlich erschließt. Effizienz und Produktivität sind Schlüsselfaktoren in der Softwareentwicklung. Dabei ist es nicht so, dass wir bei der Erstellung von Code keine Zeit haben. Es geht nicht darum, permanent mit Höchstgeschwindigkeit unterwegs zu sein. Im Gegenteil: Gelassenheit ist in der Erstellung von Software ein guter Begleiter. Es geht um die Grundschnelligkeit, mit der man sich bewegt.

Und es gibt weitere Faktoren, die eine Rolle spielen. Wenn Sie beispielsweise zum Ziegenproblem nicht nur eine einfache Simulation wollen, sondern auch eine Benutzeroberfläche, um etwa Gesetzmäßigkeiten anschaulich zu machen, oder um zu zeigen, wie die Wahrscheinlichkeit sich mit der Zahl der Türen verändert, brauchen Sie dazu einen Oberflächenbaukasten. Dabei reden wir nicht von Swing oder JavaFX oder einer der etablierten Browser-basierten Oberflächentechniken. Wir reden von einem Baukasten, der Ihnen das Anlegen der gewünschten Oberfläche in wirklich kurzer Zeit erlaubt. Denn als halbwegs erfahrene Entwickler wissen wir, dass Sie keine Lust mehr auf eine anschauliche Darstellung des Ziegenproblems haben, wenn Sie diese auf der Basis von Swing oder JavaFX von Grund auf neu erstellen müssen. Denn die Erfahrung lehrt uns, dass wir damit Tage oder Wochen beschäftigt sind. Was wir brauchen, ist eine Art generelle Wiederverwendung. Wenn wir Software mit hoher Produktivität erstellen wollen, müssen wir als erstes damit aufhören, Software zu bauen, die nur einmal verwendet wird - beziehungsweise nur einmal verwendbar ist.

Wenn Ihnen das Thema Effizienz wichtig erscheint, dann kaufen Sie sich ein Notizbuch von nicht ganz kleinem Umfang und notieren Sie in diesem zukünftig jedes Stück Software, das Sie für den Müll produziert haben, das also nicht mehrfach verwendbar ist. Das ist ein ernst gemeinter Vorschlag. Vielleicht ist es hilfreich, wenn Sie sich systematisch damit befassen, wann und warum Sie Software auf eine einmalige Nutzung hin erstellen.

Legen Sie sich ein Tagebuch zu. Nennen Sie es das „Buch der unbrauchbaren Softwareteile“ (BUST). Notieren Sie darin jede Komponente, die Sie erstellt haben und die nicht mehrfach verwendbar ist. Und notieren Sie jeweils sorgfältig den Grund, warum Sie schon wieder ein Stück Code für den Müll geschrieben haben

Dieses Tagebuch wird Ihnen vermutlich zeigen, warum so viel Software nicht wiederverwendbar ist. Der allererste Grund ist fehlende Qualität. Damit ein Stück Software ein Bauteil wird, das man ohne Bauchschmerzen wieder einsetzen kann, muss es über eine gewisse Mindestqualität verfügen. Aber selbst wenn wir nun anfangen, unsere Softwareteile mit hoher Sorgfalt zu schreiben (was den Zeitaufwand möglicherweise erhöht, vielleicht aber auch nicht), sind wir von einer praktikablen Wiederverwendbarkeit noch weit entfernt. Damit wir ein Stück Code, das wir irgendwann einmal verfasst haben, wiederverwenden können, müssen wir es erst einmal wiederfinden. Dazu muss es a) geeignet abgelegt und b) geeignet beschrieben sein.

Nicht-dokumentierte Software ist nicht wiederverwendbar

An dieser Stelle eröffnet sich nun ein noch größeres Problemfeld. Denn welche Softwareteile haben eine vernünftige Dokumentation, vor allem eine solche, die wir glauben, selbst wenn es unsere eigene ist? Haben Sie tatsächlich schon öfters Softwareteile gesehen, die nicht zu offiziell vertriebenen Bibliotheken gehören und für die eine brauchbare Beschreibung existiert? In der Regel sind Dokumentationen zu Softwareteilen unbrauchbar, wenn diese nicht aus anerkannten Bibliotheken stammen. Denn selbst wenn Beschreibungen existieren, gibt es zwei Seiten: Das, was in der Beschreibung steht, und das, was tatsächlich realisiert ist. Um Software, die nicht aus anerkannten Bibliotheken stammt, wiederverwenden zu können, muss man sich oftmals zuerst mit dem Sourcecode befassen, oder die Software erproben – was ebenfalls mühsam ist. Das heißt, wir müssen Code lesen, um ihn verwenden zu können, weil Beschreibungen entweder nicht existieren, oder nicht präzis genug sind, oder mit der Software, die sie beschreiben, nicht wirklich viel zu tun haben. Auch das ist ein Qualitätsproblem und wir alle wissen, dass es sich dabei um ein real existierendes und häufiges Qualitätsproblem handelt.

Software, von der man den Code lesen muss, um zu wissen, was sie tut, ist nicht wirklich wiederverwendbar

Wenn Sie sich nun aus purem Spaß an der Sache entschließen, trotz des hohen Aufwands eine Benutzeroberfläche für das Ziegenproblem zu schreiben, werden Sie anschließend einige Einträge in Ihr Buch der unbrauchbaren Softwareteile stellen. Denn die Oberfläche, die Sie da schreiben, ist höchstwahrscheinlich nicht wiederverwendbar. Sie haben sich nun zwar bemüht und haben eine Dokumentation verfasst. Und das war wirklich Aufwand. Wenn Sie es einmal konsequent durchgezogen haben, wissen Sie, von was wir hier reden. Zudem mussten Sie die Dokumentation bei jeder Änderung der Software mit anpassen. Doch am Ende folgt die Erkenntnis, dass auch das für den Müll ist. Denn Sie können diese Oberfläche nicht wiederverwenden. Sie ist auf das Ziegenproblem zugeschnitten und ist für andere Zwecke nicht nutzbar.

Treten Sie Ihr Buch der unbrauchbaren Softwareteile deshalb nicht gleich ebenfalls in den Eimer. Es ist nützlich und wird Ihnen noch gute Dienste erweisen. Um Software vernünftig zu erstellen, brauchen wir nicht nur eine funktionierende Wiederverwendung, sondern auch eine andere Haltung zu der Art, wie wir Software konstruieren. Ihr Problem beim Erstellen einer Benutzeroberfläche für das Ziegenproblem ist, dass Sie Lösungen verfassen und in Lösungen denken. Um Software ‚vernünftig’ zu erstellen und um dieser Idee von einem Software-Universum näher zu kommen, in dem wir Bauteile, Maschinen, Applikationen und Konstrukte unseres Erfindungsreichtums mit einer gewissen Leichtigkeit und Grundschnelligkeit umsetzen, brauchen wir vor allem eine entsprechende mentale Haltung.

Vor allem müssen wir aufhören, in Lösungen zu denken. Lösungen sind nahezu niemals wiederverwendbar

Der rote Faden in dem umfassenden Plan, in dem das vorliegende Buch ein Anfang ist, ist die Idee von einem allgemeinen Konstruktionsansatz, mit dem wir erdachte Systeme und Konstruktionen in akzeptabler Zeit verfassen können, ohne das Buch der unbrauchbaren Softwareteile erheblich zu erweitern. Einige der Themen dieses Buches werden dabei eine Rolle spielen und sich letztlich als einfach erweisen, obwohl sie nicht von Anfang an so erscheinen. Auf andere Punkte, wie etwa auf das überragend wichtige Konstruktionsthema von Einfachheit selbst, trifft dies jedoch nicht zu.

2. Ein Anfang – aber nicht mehr

Das Buch ist mit dem Ziel geschrieben, zu zeigen, wie man sich dem Software-Universum annähern kann. Es ist jedoch keine Eintrittskarte – der Titel lautet nicht: Ingenieur in 21 Tagen. Es wird ganz im Gegenteil die Auffassung vertreten, dass das Erlernen und der Erwerb von Konstruktionstechniken sehr lange dauert. Aber es gibt diese Konstruktionstechniken und es gibt diese Vorgehensweisen, die es erlauben, Software mit relativ hoher Produktivität und hoher Qualität zu schreiben. Diese Techniken muss man sich erschließen. Man kann sie erlernen. Das vorliegende Buch ist dazu ein Anfang – aber auch nur ein Anfang. Die einzelnen Themen werden uns in der konkreten Ausführung voranbringen, weil im Konkreten immer die Möglichkeit von Zugang und Verstehen liegt. Aber unsere Themenauswahl ist in erster Linie durch naheliegende Coding-Aspekte wie elementare Syntax, Exceptions oder Streams bestimmt, die in Java zum notwendigen Handwerk gehören. Es wird sich in dem ein oder anderen Beispiel die Möglichkeit ergeben, mehr zu sehen. Und je weiter wir fortschreiten, desto klarer wird die Bedeutung von Konstruktion und ihren speziellen Prinzipien hervortreten.

Es wird im Übrigen kein Unterschied zwischen dem ‚Schreiben’ und dem ‚Konstruieren’ von Software gemacht. Das Wort Konstruieren betont einen Gegenpol zu einer verbreiteten Art der Erstellung, die ich als ‚Bastelei’ bezeichne. Wenn wir an Lösungen ‚herumbasteln’, ist die Qualität oft schlecht, die Produktivität lausig und der Zeitdruck hoch. Wenn wir Software erstellen, sollten wir nicht basteln. Wir können experimentieren, wenn wir etwas erproben wollen oder uns etwas erschließen müssen. Aber die legitime Tätigkeit des Experimentierens sollte vom Konstruieren von Software und ihren Bausteinen unterschieden werden.

Stellt man die wesentlichen Faktoren, die gerade genannt wurden, zusammen, dann geht es um Effizienz, Qualität, Einfachheit und Wiederverwendbarkeit. Diese Faktoren sind bestimmend, sie interessieren und es ist offensichtlich, dass sie zum Teil auch voneinander abhängen. Und es kommen weitere Faktoren hinzu, die im großen Plan nicht ganz so stark im Vordergrund stehen, aber dennoch Wirkung haben, wie Lesbarkeit, Robustheit, Stabilität und Kürze. Wegen dieser Faktoren und Punkte wurde das vorliegende Buch geschrieben. Aber dieses Buch handelt in erster Linie und bewusst vom Coding und nicht von Qualität oder Einfachheit. Die genannten Themen werden nebenbei aufgegriffen – zwanglos, nicht häufig, und auch nur dann, wenn das Coding-Material dazu gute Gelegenheit bietet. Das ist nicht sehr oft der Fall. Wir befassen uns mit elementarem Code, mit anspruchsvollerem Code, mit größeren Konstruktionen, mit Konstruktionsprinzipien und Vorgehensweisen. Und hin und wieder bemerkt man, dass man gerade mit einer Schlüsselsituation zu tun hat und dass der betreffende Code (oder die Konstruktionsidee) mehr beinhaltet als nur eine Illustration der aktuellen Syntax.

Es ist nicht so – wenn wir kurz den Punkt Effizienz herausgreifen – dass man zuerst lernt, was Effizienz im Coding bedeutet, und im nächsten Schritt dann Coding selbst erlernt. Es geht selbstverständlich umgekehrt. Man lernt, wie man mit gesundem Menschenverstand an Programmierung herangeht. Und auf diesem Weg kann man ab und zu auf die ein oder andere Einsicht hinweisen, die nicht ganz offensichtlich ist. Das vorliegende Buch ist ein Buch über Coding. An einigen Stellen wird man eventuell bemerken, dass es mit anderen Hintergedanken geschrieben wurde.

Eine kleine Java-Rundreise – Teil 1

Gut geschriebener Code besteht aus einer Vielzahl kleiner und kleinster Methoden

Entwickler müssen sich hin und wieder klar machen, welchen Spielraum sie durch die Gestaltung der Methoden und Methodenköpfe haben, in die sie den Code aufteilen. Die Methodenköpfe bestimmen das Vokabular, mit dem Code formuliert wird

Jeder Teilausdruck und jeder Methodenaufruf wird im Programmablauf durch seinen Ergebniswert ersetzt

Die Wirkung einer Operation und der Ergebniswert einer Operation sind nicht notwendigerweise dasselbe

‚Handgeschriebene’ Iterationen, also solche Iterationen, in denen der Entwickler die Schleifenbedingung und die Inkrementierung selbst verfasst, sind eine vermeidbare Fehlerquelle

Code erhält Struktur und Erklärung durch Aufteilung in Methoden. Methoden sind sozusagen die kleinen Bausteine, aus denen wir Code aufbauen, beziehungsweise in die wir Code zerlegen

Methodenaufrufe für Objekte haben immer dieses Standardaussehen: object.perform(). Dies liest man in dieser Weise: Schicke die Nachricht perform() an object. Das Objekt entscheidet dann, was es mit der Nachricht anfängt

Alle Objekte, die keinen elementaren Typ haben, leben im Nirvana

Traue niemals einer Aussage zur Performance. Messe grundsätzlich selbst

1.Intro

2.90 Prozent - Ein Plan und ein Stück Code - Was ein Entwickler wissen muss

3.Methoden

4.Lokale Variable, Blöcke, Scope und final

5.Die Grundregel für zusammengesetzte Ausdrücke

6.Weitere elementare Regeln und Begriffe

7.Zuweisung

8.Kombinierte Zuweisungen

9.Inkrement und Dekrement

10.Stringverknüpfung (+)

11.Bedingung (if/else)

12.Verzweigung (switch)

13.Der new-Operator

14.Gleichheits- und Identitäts-Operator

15.Logische Operatoren, Vergleiche, Verknüpfung von Bedingungen

16.Der Conditional-Operator

17.Zusammenfassung der Operatoren

18.Iterationen

19.Elementare Programmiertechnik anhand eines Beispiels

20.Objekte *

21.Typen und Interfaces *

22.Allgemeine Vererbung *

23.Packages, Import und private Typen

24.Module *

25.Exceptions *

26.Elementare Typen und ihre Verpackung in Objekten - Wrappers

27.Zahlen und Zufallszahlen

28.Konstanten, Konstanz und Unveränderbarkeit

29.Enums *

30.Threads *

31.Datum und Uhrzeit

32.Performancemessung

33.Strings *

34.Arrays

35.Collections *

36.Generische Klassen *

37.Generische Methoden *

38.Maps *

39.Essentials

40.Guidelines

1.Intro

Dieses Kapitel zeigt Statements, Operatoren und Ausdrücke, die in einer durchschnittlichen Anwendungsprogrammierung häufig vorkommen. So begegnen uns etwa kombinierte Zuweisungen, Inkrement (c++) und Dekrement (c--) oder auch Stringverknüpfungen auf Schritt und Tritt. Dieses Kapitel zeigt und erklärt all die Java-Elemente, die für das Schreiben von einfachem prozeduralen Code typisch sind. Einige Entwickler sehen die genannten Operatoren skeptisch, weil es sich um verkürzende Schreibweisen handelt. Das vorliegende Buch möchte dagegen zeigen, dass kompakte Syntax und lesbarer Code gut zusammenpassen.

Umständlich geschriebener Code erscheint vielleicht Anfängern leichter fassbar, aber er ist für Übersichtlichkeit, Lesbarkeit und klare Strukturen schädlich. Lesbarkeit von Code wird nicht mit Ausführlichkeit und einem hohen Anteil von Leerzeilen erreicht, sondern durch die beständige Nutzung von immer gleichen Redewendungen. Diese werden sozusagen als elementarer Wortschatz in diesem Kapitel behandelt. Wenn sich ein Java-Neuling mit den häufigsten Redewendungen vertraut macht, hat er vermutlich einen einfacheren Einstieg, als wenn er sich durch alle Syntaxelemente mit gleichmäßiger Anstrengung hindurcharbeitet.

Der erste Teil der Java-Rundreise ist nur wenig mehr als ein Umherschweifen in hügeligem Gelände, um die Grundausrüstung kennenzulernen. Der zweite Teil erkundet dann ein größeres Gebiet und ist entsprechend anstrengender. Dazwischen erschließen wir uns angenehme Features wie die Lambdas, schwierige Tools wie die unvermeidbaren Exceptions, und schließlich auch die Philosophie, die Seele im Code, nämlich die Objektorientierung.

2.90 Prozent - Ein Plan und ein Stück Code - Was ein Entwickler wissen muss

Wenn ein Entwickler einen Plan hat, kann er beginnen, Code zu schreiben. Die Pläne des Entwicklers im Kleinen betreffen dabei immer diese beiden Aufgaben:

Das Organisieren von Code in Methoden

Das Schreiben des Codes einer einzelnen Methode.

Die Rede ist von Funktionen. Funktionen heißen in Java Methoden. Beide Bezeichnungen werden weitgehend synonym verwendet. Das Denken eines Entwicklers dreht sich um Methoden. Jeglicher Code in Java läuft in Methoden ab. Und jede Methode ist Teil einer Klasse. Um Code zu schreiben, muss ein Entwickler eine Klasse bereitstellen und in dieser oder einer anderen Klasse eine main()-Funktion. Denn um ein Programm in Java auszuführen, braucht man eine main()-Funktion. Mit deren Aufruf wird das Programm gestartet. Ein Kopfdruck an der richtigen Stelle in der Entwicklungsumgebung und die Eingabe des Namens ‚Experiment’ in einen Dialog der Entwicklungsumgebung erzeugen eine Klasse mit der gewünschten main()-Methode (siehe den ersten Abschnitt im Anhang, wenn Sie hier Unterstützung brauchen):

public class

Experiment{

// Dieser Bezeichner ist beliebig

public static void

main(String[] args){}

// main() jedoch muss es immer geben

}

 

Ein weiterer Knopfdruck bringt die Klasse zur Ausführung. Das lässt uns natürlich kalt, denn sie tut ja nichts und folglich sehen wir auch nichts. Sollten Sie diese Klasse nicht mit einer Entwicklungsumgebung erzeugen, sondern vollständig selbst erstellen, dann achten Sie darauf, dass die Klasse in einem File mit dem Namen der Klasse und der Namenserweiterung .java steht. Die Klasse Experiment muss in dem Java-File Experiment.java gespeichert sein. Jede öffentliche Klasse muss in einem eigenen File ihres Namens stehen. Sie sollten zudem darauf achten, dass die Kopfzeile der main()-Funktion genau das gezeigte Aussehen hat. Wenn Sie vom Ablauf der Klasse etwas sehen wollen, dann stellen Sie Ausgabe-Statements wie das folgende in die main()-Funktion:

System.out.println(“Hello World”);

Den Button, dessen Betätigung dieses erste Programm zum Ablauf bringt, finden Sie ebenfalls in Ihrer Entwicklungsumgebung. In Eclipse ist dies: Run → Run As → Java Application. Wenn Sie nicht mit einer Entwicklungsumgebung arbeiten, müssen Sie das File Experiment.java zuerst in der Konsole übersetzen (javac Experiment.java). Dann können Sie den Code vom Interpreter ausführen lassen (java Experiment). Informationen über Compiler und Interpreter finden Sie im Anhang. Um sicherzustellen, dass Sie in der Lage sind, eine Klasse zu erstellen, gibt es im Anhang zudem ein kurzes Kapitel, das sich den möglichen Schwierigkeiten bei der ersten Klasse widmet. Denn ohne eigene Experimente, mit denen Sie die hier vorgestellten Beispiele und Codefragmente erproben, macht das Lesen dieses Buches wenig Sinn.

Ein Entwickler, der sich eine bevorstehende Codierung zurechtlegt, denkt entweder darüber nach, wie er den Code in Methoden aufteilt, oder wie er den Code einer einzelnen Methode schreibt. Im ersten Fall hat er etwas in dieser Art vor Augen:

Wir sehen hier ganz gut, wie der Entwickler sich die Sache denkt. Sein Plan nimmt Gestalt an und man kann den Plan lesen. Man muss sich das so vorstellen, dass wir hier zwar nur eine Klasse zeigen, dass in der Regel aber viele Klassen beteiligt sind, die allesamt sprechende Namen haben, und dass es in jeder dieser vielen Klassen viele Methoden mit ebenfalls sprechenden Namen gibt. Der Witz bei der Organisation von Code in Methoden liegt darin, dass der Code so aufgeteilt wird, dass die zu lösende Aufgabe in jeder einzelnen Methode möglichst übersichtlich und der Plan als Ganzes möglichst gut lesbar und zu verstehen ist.

Der ‚Plan als Ganzes’ ist dabei eine schöne Idee. Entwickler verfassen Pläne, wenn sie Software schreiben. Man sieht jedoch bald, dass es nicht ganz einfach ist, einen Plan zu machen und ihn aufzuschreiben. Die Schwierigkeiten beginnen bereits mit der Frage, wie ein aufgeschriebener Plan denn aussehen oder wann man ihn verfassen soll. Einen funktionierenden Plan zu erstellen, ist bedeutend schwieriger als die anschließende Umsetzung in Code. Planung und Codierung haben aber andererseits eine Menge miteinander zu tun. Sie verhalten sich etwa so wie Denken und Sprache. Das eine geht nicht ohne das andere. Niemand kann ohne fundierte Codekenntnisse einen vernünftigen Plan machen und umgekehrt ist eine Codierung ohne Plan genau das, wonach es manchmal aussieht – eben planlos.

In diesem Buch geht es sehr viel um Denken und Sprache und um Plan und Code. Man könnte auch sagen, es geht darum, wie man Software konstruiert. Für Konstruktionen braucht man mehr als die Syntax einiger Java-Statements. Wir brauchen dazu die Fähigkeit der Konzeption, das ist Planung, und wir brauchen die Fähigkeit der Umsetzung, das ist Coding. Und zudem brauchen wir eine gewisse Grundschnelligkeit. Es geht nicht nur darum, irgendwann einmal nach langer Zeit und vielen Anläufen alles in schöne Ordnung gebracht zu haben. Es geht auch um die Fähigkeit, mit einer hohen Produktivität zu konstruieren, also robuste Konstruktionen in kurzer Zeit zu erstellen. Planung und Coding und ihre Verbindung müssen so aufgesetzt sein, dass Konstruktionen rational und damit schnell, sehr schnell, durchgeführt werden können.

In diesem Hauptkapitel geht es in erster Linie um Coding. Rationalität beginnt jedoch - in kleinen Ansätzen - bereits hier. Wir müssen nicht jedes Syntaxelement in gleicher Breite beschreiben. Wir konzentrieren uns bei den Coding-Themen auf diejenige Auswahl von Syntax und Redewendungen, die geschätzte 90 Prozent des ‚durchschnittlichen’ Codes ausmachen. Wir betrachten dazu Tools wie Strings, Collections und Enums und eben elementare Syntax. Die 90-%-Regel gilt für elementare Syntax und Tools gleichermaßen. Mit einer Handvoll Tools erledigt man 90 Prozent der anfallenden Aufgaben in einer ‚durchschnittlichen’ Entwicklung. Mit der Beherrschung der wichtigsten Sprachmittel und einer guten Kombination aus Planung und Coding beginnt das minimale Konstruktionswissen, über das ein Entwickler verfügen sollte.

Sieht man nochmals auf die obige Klasse Experiment mit ihren Methoden, so verschwimmt die Grenze zwischen Planung und Code. Ist die Aufteilung in Methoden ein Mittel der Planung oder ein Mittel der Codierung? Tatsache ist, dass der Methodenaufruf eines der wichtigsten Elemente ist, um den Programmablauf zu kontrollieren. Und die Organisation von Code in Methoden ist ein elementares und zugleich wichtiges Engineering-Mittel. Wir behandeln Methoden und ihre Aufrufe deshalb als erstes. Der Java-Entwickler hat daneben aber auch alle anderen gängigen Sprachmittel zur Verfügung, die man in modernen prozeduralen und objektorientierten Sprachen kennt. Unter anderem sind das diese:

Methodenaufrufe. Um Leistungen an andere Methoden zu delegieren:

Bedingungen. Um Prüfungen durchzuführen:

Logische Operatoren. Um Bedingungen zu verknüpfen:

Verzweigungen. Um mehrwertige Bedingungen zu behandeln:

Iterationen. Um Elemente einer Menge zu durchlaufen:

Einige vorkommende Methoden wie getResults() oder getArray() sind hier nicht wesentlich und werden deshalb nicht weiter erläutert. In der Praxis müssen natürlich alle Methoden, die aufgerufen werden, an anderer Stelle vereinbart sein. Im weiteren Verlauf des Kapitels greifen wir die gezeigte Basissyntax auf, erläutern Regeln, auf die es ankommt, und zeigen an Standard-Situationen, die man häufig antrifft, was man tun und was man vermeiden sollte. Wir gehen dabei davon aus, dass die Leserinnen und Leser mit der grundsätzlichen Wirkungsweise einer Programmiersprache bereits halbwegs vertraut sind. Ein Java-Neuling, der von einer anderen Sprache her kommt, wie etwa Pascal, C oder C++, sollte mit dem gewählten Niveau gut zurecht kommen.

3.Methoden

3.1.Die Signatur von Methoden

Die Grundlage von elementarem Java sind Methoden. Methoden sind ein erster Ansatz von Engineering. Sie dienen dazu, Code zu organisieren und die zu erbringende Leistung in benennbare Einheiten aufzuteilen. Eine Methode besteht aus Methodenkopf und Methodenkörper:

public static int

printLongArray(

long

[] array, String separator)

// Methodenkopf

{

// Ab hier Methodenkörper

// Die Klasse, zu der diese Methode

}

// gehört, ist nicht dargestellt

Der Methodenkopf enthält alle formalen Deklarationen zu einer Methode und legt Ein- und Ausgang fest. Er bestimmt die Sichtbarkeit (private oder public), den Returntyp und die Argumente. Die Sichtbarkeit von printLongArray() ist public, was bedeutet, dass die Methode auch außerhalb ihrer Klasse gesehen und zugegriffen werden kann. printLongArray() hat zwei Argumente, nämlich array und separator mit den Standardtypen long[] und String. Die Argumente sind der Eingang einer Methode. Sie legen fest, was an eine Methode bei ihrem Aufruf übergeben wird. Das Gegenstück dazu ist der Returnwert. Dieser ist das Ergebnis, das eine Methode nach ihrer Ausführung an den Aufrufer zurückliefert. Der Methodenkopf von printLongArray() legt fest, dass der Returnwert den elementaren Typ int hat. Die geordnete Liste der Argumente mit ihren Typen zusammen mit Methodenname, Returntyp und Sichtbarkeit nennt man auch die Signatur einer Methode.

Eine jede Methode ist Teil einer Klasse. Auch printLongArray() muss in irgendeiner Klasse vereinbart sein. Nehmen wir an, dass es sich dabei um die Klasse Experiment handelt, die wir bereits kennen. Wie die anderen Experiment-Methoden hat auch printLongArray() den Qualifier static. Java-Methoden werden nicht grundsätzlich als static vereinbart. Bis wir die Instanzmethoden kennenlernen, die nicht statisch sind (siehe dazu im Kapitel Objekte), sollten Sie Ihre Experimente jedoch mit statischen Methoden ausführen. Die Reihenfolge der Schlüsselworte public und static spielt übrigens keine Rolle. Beide Qualifier müssen aber vor dem Returntyp stehen. Wenn eine (statische) Methode von beliebigen anderen Klassen aus aufgerufen werden soll, so muss sie dazu public sein und der Methodenaufruf muss dabei durch den Klassennamen qualifiziert werden:

Experiment.printLongArray(…);

// Aufruf über Klassengrenzen hinweg

Um eine statische Methode der eigenen Klasse aufzurufen, genügt es, den Namen der Methode zu nennen. Der Aufruf einer Methode muss in jedem Fall ihrer Signatur entsprechen. Dies bedeutet, dass alle Argumente mit dem richtigen Typ gegeben und in der richtigen Reihenfolge präsentiert werden müssen. Der Returnwert kann entgegen genommen werden oder auch nicht. Im ersteren Fall muss auch für ihn eine Variable mit dem richtigen Typ bereitgestellt werden. Hier ist eine kleine Reihe von Beispielstatements, welche die Aufrufregeln illustrieren:

Derartige im Kommentar markierte Fehler sind immer harmlos. Denn es handelt sich um Fehler, die der Compiler bemerkt. Der Compiler lehnt dann die Übersetzung des betreffenden Codes ab. Ein Fehler, den der Compiler bemerkt, ist deshalb harmlos, weil er vom Entwickler unmittelbar erkannt wird und behoben werden kann. Ein nicht-harmloser Fehler ist ein Fehler, der erst zur Laufzeit auftritt, alle Test übersteht, nur sporadisch auftritt und das erste Mal in Erscheinung tritt, wenn die Applikation gerade an 1000 Anwender verteilt worden ist.

Das Beispiel zeigt, dass beim Aufruf einer Methode die übergebenen Argumente in ihren Typen auf die deklarierten Argumente passen müssen. Ebenso muss der Returntyp zum Typ der aufnehmenden Variable passen. Dies ist in Java elementar. Der Compiler kann geringfügige Anpassungen automatisch vornehmen, etwa wenn durch den Typ eines Arguments ein long gefordert und beim Aufruf irgendein anderer ganzzahliger Typ wie short oder byte übergeben wird. Denn diese Typen lassen sich ohne Informationsverlust in ein long umwandeln (siehe unter Cast). Wenn beim Methodenaufruf die Erwartung an die Typen der Argumente und ihre Anzahl nicht erfüllt wird, lehnt der Compiler ab und übersetzt nicht. Da der Name der Methode nicht das einzige entscheidende Kriterium bei ihrem Aufruf ist, können verschiedene Methoden mit gleichem Namen vereinbart werden, wenn sie sich in Zahl, Reihenfolge oder Typ der Argumente unterscheiden. Zwei Methoden gleichen Namens in einer Klasse, die sich nur im Returntyp unterscheiden, sind dagegen nicht erlaubt.

Verschiedene Methoden können den gleichen Namen tragen, wenn sich ihre Argumente durch Anzahl, Typ oder Reihenfolge unterscheiden

Wenn mehrere Methoden mit gleichem Namen innerhalb einer Klasse vereinbart werden, so nennt man dies Overloading. Overloading (Überladen) ist etwas sehr Triviales. Gäbe es für Instanzmethoden nicht einen wichtigen ähnlichen Mechanismus, nämlich Overriding, so würde der Term ‚Overloading’ hier gar nicht erwähnt werden. Das folgende Beispiel zeigt einige mögliche Überladungen in der Klasse Experiment:

public class

Experiment{

public static void

main(String[] args) {… }

public static int

printLongArray(

long

[] array, String separator) {… }

public static int

printLongArray(

long

[] array, String separator,

boolean

useSingleLine) {… }

public static void

printLongArray(

long

[] array, String separator,

short

itemsPerLine) {… }

public static int

printLongArray(

int

[] array, String separator) { … }

}

Wir sehen einfache Überladungen, die dadurch entstehen, dass die Zahl der Argumente variiert wird oder dass ein Argument einen anderen Typ erhält. Natürlich kann man Überladungen auch dadurch erreichen, dass man die Reihenfolge der Argumente vertauscht. Allerdings sollte für den Anwender der Methoden ohne Weiteres ersichtlich sein, was diese tun und worin ihr Unterschied liegt. Im obigen Beispiel gibt es da keinerlei Schwierigkeiten. Im folgenden Beispiel ist dagegen von außen nicht zu erkennen, was die beiden printLongArray()-Methoden unterscheidet:

public class

Experiment{

// Problematische Überladung

public static void

main(String[] args) {… }

public static int

printLongArray(

int

[] array, String separator) { … }

public static int

printLongArray(String separator,

int

[] array) { … }

}

Die Möglichkeit, mehrere Methoden in einer Klasse mit gleichem Namen zu verfassen, ist nicht nur theoretisch gegeben, sondern wird in der Praxis ausgiebig genutzt. Es ist sehr hilfreich, nicht beständig neue Methodennamen erfinden zu müssen, wenn man mehrere Methoden mit einer ähnlichen Leistung anbieten möchte. Welche Namen würde man für die Menge der printLongArray()-Methoden im obigen Beispiel wählen, wenn Overloading nicht zulässig wäre. Einige von uns würden es sicher mit printLongArray1(), printLongArray2() und so fort versuchen. Bei der Anwendung dieser Methoden würde man dann den unangenehmen Effekt entdecken, dass man bei jedem Methodenaufruf erst mühsam herausfinden muss, welche Zahl, beziehungsweise welcher Name zu welcher Argumentkombination gehört. Von daher ist Overloading zwar kein großes Feature, aber sehr praktisch.

3.2.Werden Argumente und Returnwerte kopiert?

In einer der obigen Versionen von printLongArray() sind drei Argumente gegeben: ein Array, ein String und ein boolean. Was passiert mit diesen Argumenten beim Methodenaufruf? Werden die Argumente kopiert? Oder sieht die gerufene Methode das Original? Ist es für den Aufrufer relevant, wenn die gerufene Methode ein Argument ändert? Die Antwort auf diese Fragen liegt in dem Unterschied zwischen elementaren Typen wie boolean und wirklichen Objekten (Instanzen) wie String und Array. Wir beginnen diese wichtige Erläuterung mit einer Nonsense-Implementierung von printLongArray():

Möglicherweise sind Sie ein ungeduldiger Mensch und möchten sofort wissen, was denn in Java ein boolean ist oder ein long oder was elementare Typen sind. Wenn Sie öfters von dieser Ungeduld getrieben werden, so gibt es für Sie zwei einfache Optionen. Diese heißen Glossar und Essentials. Beide sind Orte der Erklärung und Teil dieses Buches und befinden sich somit in Ihrem unmittelbaren Zugriff. Die genannten Fragen haben mit dem Typsystem von Java zu tun, das in einem späteren Teil dieses Buches behandelt wird. Eine kurze Übersicht ist hier hilfreich.