Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 
Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Eigene Klassen schreiben
6 Objektorientierte Beziehungsfragen
7 Ausnahmen müssen sein
8 Äußere.innere Klassen
9 Besondere Typen der Java SE
10 Generics<T>
11 Lambda-Ausdrücke und funktionale Programmierung
12 Architektur, Design und angewandte Objektorientierung
13 Komponenten, JavaBeans und Module
14 Die Klassenbibliothek
15 Einführung in die nebenläufige Programmierung
16 Einführung in Datenstrukturen und Algorithmen
17 Einführung in grafische Oberflächen
18 Einführung in Dateien und Datenströme
19 Einführung ins Datenbankmanagement mit JDBC
20 Einführung in <XML>
21 Testen mit JUnit
22 Bits und Bytes und Mathematisches
23 Die Werkzeuge des JDK
A Java SE-Paketübersicht
Stichwortverzeichnis


Download:

- Beispielprogramme, ca. 35,4 MB


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil 2 Imperative Sprachkonzepte
Pfeil 2.1 Elemente der Programmiersprache Java
Pfeil 2.1.1 Token
Pfeil 2.1.2 Textkodierung durch Unicode-Zeichen
Pfeil 2.1.3 Bezeichner
Pfeil 2.1.4 Literale
Pfeil 2.1.5 Reservierte Schlüsselwörter
Pfeil 2.1.6 Zusammenfassung der lexikalischen Analyse
Pfeil 2.1.7 Kommentare
Pfeil 2.2 Von der Klasse zur Anweisung
Pfeil 2.2.1 Was sind Anweisungen?
Pfeil 2.2.2 Klassendeklaration
Pfeil 2.2.3 Die Reise beginnt am main(String[])
Pfeil 2.2.4 Der erste Methodenaufruf: println(…)
Pfeil 2.2.5 Atomare Anweisungen und Anweisungssequenzen
Pfeil 2.2.6 Mehr zu print(…), println(…) und printf(…) für Bildschirmausgaben
Pfeil 2.2.7 Die API-Dokumentation
Pfeil 2.2.8 Ausdrücke
Pfeil 2.2.9 Ausdrucksanweisung
Pfeil 2.2.10 Erste Idee der Objektorientierung
Pfeil 2.2.11 Modifizierer
Pfeil 2.2.12 Gruppieren von Anweisungen mit Blöcken
Pfeil 2.3 Datentypen, Typisierung, Variablen und Zuweisungen
Pfeil 2.3.1 Primitive Datentypen im Überblick
Pfeil 2.3.2 Variablendeklarationen
Pfeil 2.3.3 Konsoleneingaben
Pfeil 2.3.4 Fließkommazahlen mit den Datentypen float und double
Pfeil 2.3.5 Ganzzahlige Datentypen
Pfeil 2.3.6 Wahrheitswerte
Pfeil 2.3.7 Unterstriche in Zahlen *
Pfeil 2.3.8 Alphanumerische Zeichen
Pfeil 2.3.9 Gute Namen, schlechte Namen
Pfeil 2.3.10 Initialisierung von lokalen Variablen
Pfeil 2.4 Ausdrücke, Operanden und Operatoren
Pfeil 2.4.1 Zuweisungsoperator
Pfeil 2.4.2 Arithmetische Operatoren
Pfeil 2.4.3 Unäres Minus und Plus
Pfeil 2.4.4 Zuweisung mit Operation
Pfeil 2.4.5 Präfix- oder Postfix-Inkrement und -Dekrement
Pfeil 2.4.6 Die relationalen Operatoren und die Gleichheitsoperatoren
Pfeil 2.4.7 Logische Operatoren: Nicht, Und, Oder, XOR
Pfeil 2.4.8 Kurzschluss-Operatoren
Pfeil 2.4.9 Der Rang der Operatoren in der Auswertungsreihenfolge
Pfeil 2.4.10 Die Typumwandlung (das Casting)
Pfeil 2.4.11 Überladenes Plus für Strings
Pfeil 2.4.12 Operator vermisst *
Pfeil 2.5 Bedingte Anweisungen oder Fallunterscheidungen
Pfeil 2.5.1 Verzweigung mit der if-Anweisung
Pfeil 2.5.2 Die Alternative mit einer if-else-Anweisung wählen
Pfeil 2.5.3 Der Bedingungsoperator
Pfeil 2.5.4 Die switch-Anweisung bietet die Alternative
Pfeil 2.6 Immer das Gleiche mit den Schleifen
Pfeil 2.6.1 Die while-Schleife
Pfeil 2.6.2 Die do-while-Schleife
Pfeil 2.6.3 Die for-Schleife
Pfeil 2.6.4 Schleifenbedingungen und Vergleiche mit ==
Pfeil 2.6.5 Ausbruch planen mit break und Wiedereinstieg mit continue
Pfeil 2.6.6 break und continue mit Marken *
Pfeil 2.7 Methoden einer Klasse
Pfeil 2.7.1 Bestandteil einer Methode
Pfeil 2.7.2 Signatur-Beschreibung in der Java-API
Pfeil 2.7.3 Aufruf einer Methode
Pfeil 2.7.4 Methoden ohne Parameter deklarieren
Pfeil 2.7.5 Statische Methoden (Klassenmethoden)
Pfeil 2.7.6 Parameter, Argument und Wertübergabe
Pfeil 2.7.7 Methoden vorzeitig mit return beenden
Pfeil 2.7.8 Nicht erreichbarer Quellcode bei Methoden *
Pfeil 2.7.9 Methoden mit Rückgaben
Pfeil 2.7.10 Methoden überladen
Pfeil 2.7.11 Sichtbarkeit und Gültigkeitsbereich
Pfeil 2.7.12 Vorgegebener Wert für nicht aufgeführte Argumente *
Pfeil 2.7.13 Finale lokale Variablen
Pfeil 2.7.14 Rekursive Methoden *
Pfeil 2.7.15 Die Türme von Hanoi *
Pfeil 2.8 Zum Weiterlesen
 

Zum Seitenanfang

2.3Datentypen, Typisierung, Variablen und Zuweisungen Zur vorigen ÜberschriftZur nächsten Überschrift

Java nutzt, wie es für imperative Programmiersprachen typisch ist, Variablen zum Ablegen von Daten. Eine Variable ist ein reservierter Speicherbereich und belegt – abhängig vom Inhalt – eine feste Anzahl von Bytes. Alle Variablen (und auch Ausdrücke) haben einen Typ, der zur Übersetzungszeit bekannt ist. Der Typ wird auch Datentyp genannt, da eine Variable einen Datenwert, auch Datum genannt, enthält. Beispiele für einfache Datentypen sind: Ganzzahlen, Fließkommazahlen, Wahrheitswerte und Zeichen. Der Typ bestimmt auch die zulässigen Operationen, denn Wahrheitswerte lassen sich nicht addieren, Ganzzahlen schon. Dagegen lassen sich Fließkommazahlen addieren, aber nicht XOR-verknüpfen. Da jede Variable einen vom Programmierer vorgegebenen festen Datentyp hat, der zur Übersetzungszeit bekannt ist und sich später nicht mehr ändern lässt, und Java stark darauf achtet, welche Operationen erlaubt sind, und auch von jedem Ausdruck spätestens zur Laufzeit den Typ kennt, ist Java eine statisch typisierte und streng (stark) typisierte Programmiersprache.[ 62 ](Während in der Literatur bei den Begriffen statisch getypt und dynamisch getypt mehr oder weniger Einigkeit herrscht, haben verschiedene Autoren unterschiedliche Vorstellungen von den Begriffen streng (stark) typisiert und schwach typisiert.)

[»]Hinweis

In Java muss der Datentyp einer Variablen zur Übersetzungszeit bekannt sein. Das nennt sich dann statisch typisiert. Das Gegenteil ist eine dynamische Typisierung, wie sie etwa JavaScript verwendet. Hier kann sich der Typ einer Variablen zur Laufzeit ändern, je nachdem, was die Variable enthält.

Primitiv- oder Verweistyp

Die Datentypen in Java zerfallen in zwei Kategorien:

  • Primitive Typen: Die primitiven (einfachen) Typen sind die eingebauten Datentypen für Zahlen, Unicode-Zeichen und Wahrheitswerte.

  • Referenztypen: Mit diesem Datentyp lassen sich Objektverweise etwa auf Zeichenketten, Datenstrukturen oder Zwergpinscher verwalten.

Warum sich damals Sun für diese Teilung entschied, lässt sich mit einem einfachen Grund erklären: Java wurde als Programmiersprache entworfen, die kleine, schwache Geräte unterstützen sollte, und auf denen musste die Java-Software, die am Anfang noch interpretiert wurde, so schnell wie möglich laufen. Unterscheidet der Compiler zwischen primitiven Typen und Referenztypen, so kann er relativ leicht Bytecode erzeugen, der ebenfalls zwischen den beiden Typen unterscheidet. Damit kann die Laufzeitumgebung auch den Programmcode viel schneller ausführen, und das mit einem relativen einfachen Compiler. Das war für die Anfangszeit ein wichtiges Kriterium.

Sprachvergleich mit Smalltalk und .NET *

In Smalltalk ist alles ein Objekt, auch die eingebauten Sprachdatentypen. Für Zahlen gibt es einen Basistyp Number und Integer, Float, Fraction als Untertypen. Immer noch gibt es arithmetische Operatoren (+, -, *, /, //, \\, um sie alle aufzuzählen), aber das sind nur Methoden der Klasse Number.[ 63 ](Die Dokumentation für das GNU Smalltalk zeigt auf: http://www.gnu.org/software/smalltalk/manual-base/html_node/Number_002darithmetic.html#Number_002darithmetic) Für Java-Entwickler sind Methodennamen wie + oder - ungewöhnlich, doch in Smalltalk sind sie das nicht. Syntaktisch unterscheidet sich ein 1 + 2 in Java und Smalltalk nicht, nur in Smalltalk ist die Addition ein Nachrichtenaufruf an das Integer-Objekt 1 und an die Methode + mit dem Argument 2, das wiederum ein Integer-Objekt ist – die Objekte baut der Compiler selbstständig aus den Literalen auf. Eine Klasse Integer für Ganzzahlen besitzt weitere Methoden wie asCharacter und floor.[ 64 ](http://www.gnu.org/software/smalltalk/manual-base/html_node/Integer.html) Es ist wichtig zu verstehen, dass dies nur das semantische Modell auf der Sprachseite ist; das hat nichts damit zu tun, wie später die Laufzeitumgebung diese speziellen Nachrichtenaufrufe optimiert. Moderne Smalltalk-Laufzeitumgebungen mit Just-in-time-Compilation sind bei arithmetischen Operationen auf einem ähnlichen Level wie C oder Java. Durch die Einteilung von Java in primitive Datentypen und Referenztypen haben die Sprachschöpfer einen objektorientierten Bruch in Kauf genommen, um die interpretierte Laufzeit Anfang der 1990er zu optimieren – eine Optimierung, die aus heutiger Sicht unnötig war.

In .NET ist es eher wie in Java. Der Compiler kennt die eingebauten Datentypen und gibt ihnen eine Sonderbehandlung, es sind keine Methodenaufrufe. Auch im Bytecode (Common Intermediate Language, kurz CIL in .NET genannt) finden sich Anweisungen wie Addition und Subtraktion wieder. Doch es gibt noch einen Unterschied zu Java: Der Compiler bildet Datentypen der .NET-Sprachen auf .NET-Klassen ab, und diese Klassen haben Methoden. In C# ist der eingebaute Datentyp float mit dem Datentyp Single (aus dem .NET-Paket System) identisch, und es ist egal, ob Entwickler float f oder Single f schreiben. Doch Single (respektive float) hat im Vergleich zu Smalltalk keine mathematischen Operationen, aber dennoch ein paar wenige Methoden wie ToString().[ 65 ](http://msdn.microsoft.com/en-us/library/system.int32_members(v=vs.71).aspx) In .NET verhalten sich folglich die eingebauten Datentypen wie Objekte, sie haben Methoden, haben aber die gleiche Wertsemantik, zum Beispiel bei Methodenaufrufen, wie in Java, und sehen auch im Bytecode ähnlich aus, was ihnen die gleiche gute Performance verleiht.

Wir werden uns im Folgenden erst mit primitiven Datentypen beschäftigen. Referenzen werden nur dann eingesetzt, wenn Objekte ins Spiel kommen. Die nehmen wir uns in Kapitel 3, »Klassen und Objekte«, vor.

 

Zum Seitenanfang

2.3.1Primitive Datentypen im Überblick Zur vorigen ÜberschriftZur nächsten Überschrift

In Java gibt es zwei Arten eingebauter primitiver Datentypen:

  • arithmetische Typen (ganze Zahlen – auch integrale Typen genannt –, Fließkommazahlen, Unicode-Zeichen)

  • Wahrheitswerte für die Zustände wahr und falsch

Die folgende Tabelle vermittelt dazu einen Überblick. Anschließend betrachten wir jeden Datentyp präziser.

Typ

Belegung (Wertebereich)

boolean

true oder false

char

16-Bit-Unicode-Zeichen (0x0000 … 0xFFFF)

byte

–2^7 bis 2^7 – 1 (–128 … 127)

short

–2^15 bis 2^15 – 1 (–32.768 … 32.767)

int

–2^31 bis 2^31 – 1 (–2.147.483.648 … 2.147.483.647)

long

–2^63 bis 2^63 – 1 (–9.223.372.036.854.775.808 … 9.223.372.036.854.775.807)

float

1,40239846E–45f … 3,40282347E+38f

double

4,94065645841246544E–324 … 1,79769131486231570E+308

Tabelle 2.5Java-Datentypen und ihre Wertebereiche

Bei den Ganzzahlen fällt auf, dass es eine positive Zahl »weniger« gibt als negative.

Für float und double ist das Vorzeichen nicht angegeben, da die kleinsten und größten darstellbaren Zahlen sowohl positiv als auch negativ sein können. Mit anderen Worten: Die Wertebereiche unterscheiden sich nicht – anders als etwa bei int – in Abhängigkeit vom Vorzeichen. Wer eine »klassische« Darstellung wünscht, der kann sich das so vorstellen: Der Wertebereich (vom double) ist 4,94065645841246544E–324 bis 1,79769131486231570E+308 bzw. mit dem Vorzeichen von etwa –1.8E308 (über –4,9E-324 und +4,9E-324) bis +1.8E308.[ 66 ](Es gibt bei Fließkommazahlen noch »Sonderzahlen«, wie plus oder minus unendlich, aber dazu im Kapitel 22 später mehr. )

Detailwissen

Genau genommen sieht die Sprachgrammatik von Java keine negativen Zahlenliterale vor. Bei einer Zahl wie -1.2 oder -1 ist das Minus der unäre Operator und gehört nicht zur Zahl. Im Bytecode selbst sind die negativen Zahlen wieder abgebildet.

Die folgende Tabelle zeigt eine etwas andere Darstellung:

Typ

Größe

Format

Ganzzahlen

byte

8 Bit

Zweierkomplement

short

16 Bit

Zweierkomplement

int

32 Bit

Zweierkomplement

long

64 Bit

Zweierkomplement

Fließkommazahlen

float

32 Bit

IEEE 754

double

64 Bit

IEEE 754

Weitere Datentypen

boolean

1 Bit

true, false

char

16 Bit

16-Bit-Unicode

Tabelle 2.6Java-Datentypen und ihre Größen und Formate

[»]Hinweis

Strings werden bevorzugt behandelt, sind aber lediglich Verweise auf Objekte und kein primitiver Datentyp.

Zwei wesentliche Punkte zeichnen die primitiven Datentypen aus:

  • Alle Datentypen haben eine festgesetzte Länge, die sich unter keinen Umständen ändert. Der Nachteil, dass sich bei einigen Hochsprachen die Länge eines Datentyps ändern kann, besteht in Java nicht. In den Sprachen C(++) bleibt dies immer unsicher, und die Umstellung auf 64-Bit-Maschinen bringt viele Probleme mit sich. Der Datentyp char ist 16 Bit lang.

  • Die numerischen Datentypen byte, short, int und long sind vorzeichenbehaftet, Fließkommazahlen sowieso. Dies ist leider nicht immer praktisch, aber wir müssen stets daran denken. Probleme gibt es, wenn wir einem Byte zum Beispiel den Wert 240 zuweisen wollen, denn 240 liegt außerhalb des Wertebereichs, der von –128 bis 127 reicht. Ein char ist im Prinzip ein vorzeichenloser Ganzzahltyp.

Wenn wir die numerischen Datentypen (lassen wir hier char außen vor) nach ihrer Größe sortieren wollten, könnten wir zwei Linien für Ganzzahlen und Fließkommazahlen aufbauen:

byte < short < int < long

float < double

[»]Hinweis

Die Klassen Byte, Integer, Long, Short, Character, Double und Float deklarieren die Konstanten MAX_VALUE und MIN_VALUE, die den größten und kleinsten zulässigen Wert des jeweiligen Wertebereichs bzw. die Grenzen der Wertebereiche der jeweiligen Datentypen angeben.

System.out.println( Byte.MIN_VALUE ); // –128

System.out.println( Byte.MAX_VALUE ); // 127

System.out.println( Character.MIN_VALUE ); // '\u0000'

System.out.println( Character.MAX_VALUE ); // '\uFFFF'

System.out.println( Double.MIN_VALUE ); // 4.9E-324

System.out.println( Double.MAX_VALUE ); // 1.7976931348623157E308

Es gibt für jeden primitiven Datentyp eine eigene Klasse mit Hilfsmethoden rund um diesen Datentyp. Mehr zu diesen besonderen Klassen folgt in Kapitel 9, »Besondere Typen der Java SE«.

 

Zum Seitenanfang

2.3.2Variablendeklarationen Zur vorigen ÜberschriftZur nächsten Überschrift

Mit Variablen lassen sich Daten speichern, die vom Programm gelesen und geschrieben werden können. Um Variablen zu nutzen, müssen sie deklariert (definiert[ 67 ](In C(++) bedeuten »Definition« und »Deklaration« etwas Verschiedenes. In Java kennen wir diesen Unterschied nicht und betrachten daher beide Begriffe als gleichwertig. Die Spezifikation spricht nur von Deklarationen. )) werden. Die Schreibweise einer Variablendeklaration ist immer die gleiche: Hinter dem Typnamen folgt der Name der Variablen. Die Deklaration ist eine Anweisung und wird daher mit einem Semikolon abgeschlossen. In Java kennt der Compiler von jeder Variablen und jedem Ausdruck genau den Typ.

Deklarieren wir ein paar (lokale) Variablen in der main(…)-Methode:

Listing 2.6FirstVariable.java

public class FirstVariable {



public static void main( String[] args ) {

String name; // Name

int age; // Alter

double income; // Einkommen

char gender; // Geschlecht ('f' oder 'm')

boolean isPresident; // Ist Präsident (true oder false)

boolean isVegetarian; // Ist die Person Vegetarier?

}

}

Der Typname ist entweder ein einfacher Typ (wie int) oder ein Referenztyp. Viel schwieriger ist eine Deklaration nicht – kryptische Angaben wie in C gibt es in Java nicht.[ 68 ](Das ist natürlich eine Anspielung auf C, in dem Deklarationen wie char (*(*a[2])())[2] möglich sind. Gut, dass es mit cdecl ein Programm zum »Vorlesen« solcher Definitionen gibt. ) Ein Variablenname (der dann Bezeichner ist) kann alle Buchstaben und Ziffern des Unicode-Zeichensatzes beinhalten, mit der Ausnahme, dass am Anfang des Bezeichners keine Ziffer stehen darf. Auch darf der Bezeichnername mit keinem reservierten Schlüsselwort identisch sein.

Mehrere Variablen kompakt deklarieren

Im vorangehenden Listing sind zwei Variablen vom gleichen Typ: isPresident und isVegetarian.

boolean isPresident;

boolean isVegetarian;

Immer dann, wenn der Variablentyp der gleiche ist, lässt sich die Deklaration verkürzen – Variablen werden mit Komma getrennt:

boolean isPresident, isVegetarian;

Variablendeklaration mit Wertinitialisierung

Gleich bei der Deklaration lassen sich Variablen mit einem Anfangswert initialisieren. Hinter einem Gleichheitszeichen steht der Wert, der oft ein Literal ist. Ein Beispielprogramm:

Listing 2.7Obama.java

public class Obama {



public static void main( String[] args ) {

String name = "Barack Hussein Obama II";

int age = 48;

double income = 400000;

char gender = 'm';

boolean isPresident = true;

}

}

Wir haben gesehen, dass bei der Deklaration mehrerer Variablen gleichen Typs ein Komma die Bezeichner trennt. Das überträgt sich auch auf die Initialisierung. Ein Beispiel:

boolean sendSms = true,

bungaBungaParty = true;

String person1 = "Silvio",

person2 = "Ruby the Heart Stealer";

double x, y,

bodyHeight = 165 /* cm */;

Die Zeilen deklarieren mehrere Variablen auf einen Schlag. x und y am Schluss bleiben uninitialisiert.

Zinsen berechnen als Beispiel zur Variablendeklaration, -initialisierung und -ausgabe

Zusammen mit der Konsolenausgabe können wir schon einen einfachen Zinsrechner programmieren. Er soll uns ausgeben, wie hoch die Zinsen für ein gegebenes Kapital bei einem gegebenen Zinssatz (engl. interest rate) nach einem Jahr sind.

Listing 2.8InterestRates.java

public class InterestRates {

public static void main( String[] args ) {

double capital = 20000 /* Euro */;

double interestRate = 3.6 /* Prozent */;

double totalInterestRate = capital * interestRate / 100; // Jahr 1

System.out.print( "Zinsen: " );

System.out.println( totalInterestRate ); // 720.0

}

}

[+]Tipp

Strings können mit einem Plus aneinandergehängt werden; ist ein Segment kein String, so wird es in einen String konvertiert und dann angehängt.

System.out.println( "Zinsen: " + totalInterestRate ); // Zinsen: 720.0
 

Zum Seitenanfang

2.3.3Konsoleneingaben Zur vorigen ÜberschriftZur nächsten Überschrift

Bisher haben wir Methoden zur Ausgabe kennengelernt und random(). Die println(…)-Methoden »hängen« am System.out- bzw. System.err-Objekt, und random() »hängt« am Math-Objekt.

Der Gegenpol zu printXXX(…) ist eine Konsoleneingabe. Hier gibt es unterschiedliche Varianten. Die einfachste ist die mit der Klasse java.util.Scanner. In Kapitel 4, »Der Umgang mit Zeichenketten«, wird die Klasse noch viel genauer untersucht. Es reicht aber an dieser Stelle, zu wissen, wie Strings, Ganzzahlen und Fließkommazahlen eingelesen werden.

Eingabe lesen vom Typ

Anweisung

String

String s = new java.util.Scanner(System.in).nextLine();

int

int i = new java.util.Scanner(System.in).nextInt();

double

double d = new java.util.Scanner(System.in).nextDouble();

Tabelle 2.7Einlesen einer Zeichenkette, Ganz- und Fließkommazahl von der Konsole

Verbinden wir die drei Möglichkeiten zu einem Beispiel. Zunächst soll der Name eingelesen werden, dann das Alter und anschließend eine Fließkommazahl.

Listing 2.9SmallConversation.java

public class SmallConversation {



public static void main( String[] args ) {

System.out.println( "Moin! Wie heißt denn du?" );

String name = new java.util.Scanner( System.in ).nextLine();

System.out.printf( "Hallo %s. Wie alt bist du?%n", name );

int age = new java.util.Scanner( System.in ).nextInt();

System.out.printf( "Aha, %s Jahre, das ist ja die Hälfte von %s.%n",

age, age * 2 );

System.out.println( "Sag mal, was ist deine Lieblingsfließkommazahl?" );

double value = new java.util.Scanner( System.in ).nextDouble();

System.out.printf( "%s? Aha, meine ist %s.%n",

value, Math.random() * 100000 );

}

}

Eine Konversation sieht somit etwa so aus:

Moin! Wie heißt denn du?

Christian

Hallo Christian. Wie alt bist du?

37

Aha, 37 Jahre, das ist ja die Hälfte von 74.

Sag mal, was ist deine Lieblingsfließkommazahl?

9,7

9.7? Aha, meine ist 60769.81705995359.

Die Eingabe der Fließkommazahl muss mit Komma erfolgen, wenn die JVM auf einem deutschsprachigen Betriebssystem läuft. Die Ausgabe über printf(…) kann ebenfalls lokalisierte Fließkommazahlen schreiben, dann muss jedoch statt des Platzhalters %s die Kennung %f oder %g verwendet werden. Das wollen wir in einem zweiten Beispiel nutzen.

Zinsberechnung mit der Benutzereingabe

Die Zinsberechnung, die vorher feste Werte im Programm hatte, soll eine Benutzereingabe bekommen. Des Weiteren erwarten wir die Dauer in Monaten statt Jahren. Zinseszinsen berücksichtigt das Programm nicht.

Listing 2.10MyInterestRates.java

public class MyInterestRates {



public static void main( String[] args ) {

System.out.println( "Kapital?" );

double capital = new java.util.Scanner( System.in ).nextDouble();



System.out.println( "Zinssatz?" );

double interestRate = new java.util.Scanner( System.in ).nextDouble();



System.out.println( "Anlagedauer in Monaten?" );

int month = new java.util.Scanner( System.in ).nextInt();



double totalInterestRate = capital * interestRate * month / (12*100);

System.out.printf( "Zinsen: %g%n", totalInterestRate );

}

}

Die vorher fest verdrahteten Werte sind nun alle dynamisch:

Kapital?

20000

Zinssatz?

3,6

Anlagedauer in Monaten?

24

Zinsen: 1440,00

Um den Zinseszins berücksichtigen zu können, muss eine Potenz mit in die Formel gebracht werden. Die nötige Methode dazu ist Math.pow(a, b), was ab berechnet. Finanzmathematikern ist das als Übung überlassen.

[+]Tipp: Dialogeingabe

Soll die Eingabe nicht von der Konsole kommen, sondern von einem eigenen Dialog, hilft eine Klasse aus dem Swing-Paket:

String input = javax.swing.JOptionPane.showInputDialog( "Eingabe" );
 

Zum Seitenanfang

2.3.4Fließkommazahlen mit den Datentypen float und double Zur vorigen ÜberschriftZur nächsten Überschrift

Für Fließkommazahlen (auch Gleitkommazahlen genannt) einfacher und erhöhter Genauigkeit bietet Java die Datentypen float und double. Die Datentypen sind im IEEE-754-Standard beschrieben und haben eine Länge von 4 Byte für float und 8 Byte für double. Fließkommaliterale können einen Vorkommateil und einen Nachkommateil besitzen, die durch einen Dezimalpunkt (kein Komma) getrennt sind. Ein Fließkommaliteral muss keine Vor- oder Nachkommastellen besitzen, sodass auch Folgendes gültig ist:

double d = 10.0 + 20. + .11;

Nur den Punkt allein zu nutzen ist natürlich Unsinn, wobei .0 schon erlaubt ist.

[»]Hinweis

Der Datentyp float ist mit 4 Byte, also 32 Bit, ein schlechter Scherz. Der Datentyp double geht mit 64 Bit ja gerade noch, wobei in Hardware eigentlich 80 Bit üblich sind.

Der Datentyp float *

Standardmäßig sind die Fließkommaliterale vom Typ double. Ein nachgestelltes f (oder F) zeigt dem Compiler an, dass es sich um ein float handelt.

[zB]Beispiel

Gültige Zuweisungen für Fließkommazahlen vom Typ double und float:

double pi = 3.1415, delta = .001;

float ratio = 4.33F;

Auch für den Datentyp double lässt sich ein d (oder D) nachstellen, was allerdings nicht nötig ist, wenn Literale für Kommazahlen im Quellcode stehen; Zahlen wie 3.1415 sind automatisch vom Typ double. Während jedoch bei 1 + 2 + 4.0 erst 1 und 2 als int addiert werden, dann das Ereignis in double konvertiert wird und anschließend 4.0 addiert wird, würde 1D + 2 + 4.0 gleich mit der Fließkommazahl 1 beginnen. So ist auch 1D gleich 1. bzw. 1.0.[ 69 ](Ein Literal wie 1D macht deutlich, warum Bezeichner nicht mit einer Ziffer anfangen können. Denn wenn eine Variablendeklaration wie double 1D = 2; erlaubt wäre, dann wüsste der Compiler bei println(1D) ja gar nicht, ob 1D für das Literal steht oder für die Variable. )

Frage

Was ist das Ergebnis der Ausgabe?

System.out.println( 20000000000F == 20000000000F+1 );

System.out.println( 20000000000D == 20000000000D+1 );

Tipp: Was sind die Wertebereiche von float und double?

Noch genauere Auflösung bei Fließkommazahlen *

Einen höher auflösenden bzw. präziseren Datentyp für Fließkommazahlen als double gibt es nicht. Die Standardbibliothek bietet für diese Aufgabe in java.math die Klasse BigDecimal an, die in Kapitel 22, »Bits und Bytes und Mathematisches«, näher beschrieben ist. Das ist sinnvoll für Daten, die eine sehr gute Genauigkeit aufweisen sollen, wie zum Beispiel Währungen.[ 70 ](Einige Programmiersprachen besitzen für Währungen eingebaute Datentypen, wie LotusScript mit Currency, das mit 8 Byte einen sehr großen und genauen Wertebereich abdeckt. Erstaunlicherweise gab es einmal in C# den Datentyp currency für ganzzahlige Währungen. )

Sprachvergleich

In C# gibt es den Datentyp decimal, der mit 128 Bit (also 16 Byte) auch genügend Präzision bietet, um eine Zahl wie 0,000000000000000000000000001 auszudrücken.

 

Zum Seitenanfang

2.3.5Ganzzahlige Datentypen Zur vorigen ÜberschriftZur nächsten Überschrift

Java stellt fünf ganzzahlige Datentypen zur Verfügung: byte, short, char, int und long. Die feste Länge von jeweils 1, 2, 2, 4 und 8 Byte ist eine wesentliche Eigenschaft von Java. Ganzzahlige Typen sind in Java immer vorzeichenbehaftet (mit der Ausnahme von char); einen Modifizierer unsigned wie in C(++) gibt es nicht.[ 71 ](In Java bilden long und short einen eigenen Datentyp. Sie dienen nicht wie in C(++) als Modifizierer. Eine Deklaration wie long int i ist also genauso falsch wie long long time_ago. ) Negative Zahlen werden durch Voranstellen eines Minuszeichens gebildet. Ein Pluszeichen für positive Zeichen ist möglich. int und long sind die bevorzugten Typen. byte kommt selten vor und short nur in wirklich sehr seltenen Fällen, etwa bei Array mit Bilddaten.

Ganzzahlen sind standardmäßig vom Typ int

Betrachten wir folgende Zeile, so ist auf den ersten Blick kein Fehler zu erkennen:

System.out.println( 123456789012345 ); // inline

Dennoch übersetzt der Compiler die Zeile nicht, da er ein Ganzzahlliteral ohne explizite Größenangabe als 32 Bit langes int annimmt. Die obige Zeile führt daher zu einem Compilerfehler, da unsere Zahl nicht im gültigen int-Wertebereich von –2.147.483.648 … +2.147.483.647 liegt, sondern weit außerhalb: 2147483647 < 123456789012345. Java reserviert also nicht so viele Bits, wie benötigt, und wählt nicht automatisch den passenden Wertebereich.

Wer wird mehrfacher Milliardär? Der Datentyp long

Der Compiler betrachtet jede Ganzzahl automatisch als int. Sollte der Wertebereich von etwa plus/minus 2 Milliarden nicht reichen, greifen Entwickler zum nächsthöheren Datentyp. Dass eine Zahl long ist, muss ausdrücklich angegeben werden. Dazu wird an das Ende von Ganzzahlliteralen vom Typ long ein l oder L gesetzt. Um die Zahl 123456789012345 gültig ausgeben zu lassen, ist Folgendes zu schreiben:

System.out.println( 123456789012345L );

[+]Tipp

Das kleine »l« hat sehr viel Ähnlichkeit mit der Ziffer Eins. Daher sollte bei Längenangaben immer ein großes »L« eingefügt werden.

Frage

Was gibt die folgende Anweisung aus?

System.out.println( 123456789 + 5432l );

Der Datentyp byte

Ein byte ist ein Datentyp mit einem Wertebereich von –128 bis +127. Eine Initialisierung wie

byte b = 200; // inline

ist also nicht erlaubt, da 200 > 127 ist. Somit fallen alle Zahlen von 128 bis 255 (hexadezimal 8016 – FF16) raus. In der Datenverarbeitung ist das Java-byte, weil es ein Vorzeichen trägt, nur mittelprächtig brauchbar, da insbesondere in der Dateiverarbeitung Wertebereiche von 0 bis 255 gewünscht sind.

Java erlaubt zwar keine vorzeichenlosen Ganzzahlen, aber mit einer expliziten Typumwandlung lassen sich doch Zahlen wie 200 in einem byte speichern.

byte b = (byte) 200;

Der Java-Compiler nimmt dazu einfach die Bitbelegung von 200 und interpretiert das oberste dann gesetzte Bit als Vorzeichen-Bit. Bei der Ausgabe fällt das auf:

byte b = (byte) 200;

System.out.println( b ); // –56

Mehr zur Typumwandlung folgt an anderer Stelle: in Abschnitt 2.4.10, »Die Typumwandlung (das Casting)«.

Der Datentyp short *

Der Datentyp short ist selten anzutreffen. Mit seinen 2 Byte kann er einen Wertebereich von –32.768 bis +32.767 darstellen. Das Vorzeichen »kostet« wie bei den anderen Ganzzahlen 1 Bit, sodass nicht 16 Bit, sondern nur 15 Bit für Zahlen zu Verfügung stehen. Allerdings gilt wie beim byte, dass auch ein short ohne Vorzeichen auf zwei Arten initialisiert werden kann:

short s = (short) 33000;

System.out.println( s ); // –32536
 

Zum Seitenanfang

2.3.6Wahrheitswerte Zur vorigen ÜberschriftZur nächsten Überschrift

Der Datentyp boolean beschreibt einen Wahrheitswert, der entweder true oder false ist. Die Zeichenketten true und false sind reservierte Wörter und bilden neben konstanten Strings und primitiven Datentypen Literale. Kein anderer Wert ist für Wahrheitswerte möglich, insbesondere werden numerische Werte nicht als Wahrheitswerte interpretiert.

Der boolesche Typ wird beispielsweise bei Bedingungen, Verzweigungen oder Schleifen benötigt. In der Regel ergibt sich ein Wahrheitswert aus Vergleichen.

 

Zum Seitenanfang

2.3.7Unterstriche in Zahlen * Zur vorigen ÜberschriftZur nächsten Überschrift

Um eine Anzahl von Millisekunden in Tage zu konvertieren, muss einfach eine Division vorgenommen werden. Um Millisekunden in Sekunden umzurechnen, brauchen wir eine Division durch 1.000, von Sekunden auf Minuten eine Division durch 60, von Minuten auf Stunden eine Division durch 60, und die Stunden auf Tage bringt die letzte Division durch 24. Schreiben wir das auf:

long millis = 10 * 24 * 60 * 60 * 1000L;

long days = millis / 86400000L;

System.out.println( days ); // 10

Eine Sache fällt bei der Zahl 86.400.000 auf: Besonders gut lesbar ist sie nicht. Die eine Lösung ist, es erst gar nicht zu so einer Zahl kommen zu lassen und sie wie in der ersten Zeile durch eine Reihe von Multiplikationen aufzubauen – mehr Laufzeit kostet das nicht, da dieser konstante Ausdruck zur Übersetzungszeit feststeht.

Die zweite Variante macht durch Unterstriche Zahlen besser lesbar, denn der Unterstrich gliedert die Zahl in Blöcke. Anstatt ein numerisches Literal als 86.400.000 zu schreiben, ist auch Folgendes erlaubt:

long millis = 10 * 86_400_000L;

long days = millis / 86_400_000L;

System.out.println( days ); // 10

Die Unterstriche machen die 1.000er-Blöcke gut sichtbar.[ 72 ](Bei Umrechnungen zwischen Stunden, Minuten usw. hilft auch die Klasse TimeUnit mit einigen statischen toXXX()-Methoden. )

[zB]Beispiel

Hilfreich ist die Schreibweise auch bei Literalen in Binär- und Hexadezimaldarstellung, da die Unterstriche hier ebenfalls Blöcke absetzen können:

int i = 0b01101001_01001101_11100101_01011110;

long l = 0x7fff_ffff_ffff_ffffL;

Mit 0b beginnt ein Literal in Binärschreibweise, mit 0x in Hexadezimalschreibweise (weitere Details in Kapitel 22, »Bits und Bytes und Mathematisches«).

Der Unterstrich darf in jedem Literal stehen, zwei aufeinanderfolgende Unterstriche sind aber nicht erlaubt.

[»]Hinweis

Die Unterstriche in Literalen sind nur eine Hilfe wie Leerzeichen zur Einrückung. Im Bytecode ist davon nichts mehr zu lesen. In der Klassendatei sehen 0b01101001_01001101_11100101_01011110 und 0b01101001010011011110010101011110 identisch aus, insbesondere weil sie sowieso als Ganzzahl 1766712670 abgelegt sind.

 

Zum Seitenanfang

2.3.8Alphanumerische Zeichen Zur vorigen ÜberschriftZur nächsten Überschrift

Der alphanumerische Datentyp char (von engl. character, Zeichen) ist 2 Byte groß und nimmt ein Unicode-Zeichen auf. Ein char ist nicht vorzeichenbehaftet. Die Literale für Zeichen werden in einfache Hochkommata gesetzt. Spracheinsteiger verwechseln häufig die einfachen Hochkommata mit den Anführungszeichen der Zeichenketten (Strings). Die einfache Merkregel lautet: ein Zeichen – ein Hochkomma, mehrere Zeichen – zwei Hochkommata (Gänsefüßchen).

[zB]Beispiel

Korrekte Hochkommata für Zeichen und Zeichenketten:

char c = 'a';

String s = "Heut' schon gebeckert?";

Da der Compiler ein char automatisch in ein int konvertieren kann, ist auch int c = 'a'; gültig.

 

Zum Seitenanfang

2.3.9Gute Namen, schlechte Namen Zur vorigen ÜberschriftZur nächsten Überschrift

Für die optimale Lesbarkeit und Verständlichkeit eines Programmcodes sollten Entwickler beim Schreiben einige Punkte berücksichtigen:

  • Ein konsistentes Namensschema ist wichtig. Heißt ein Zähler no, nr, cnr oder counter? Auch sollten wir korrekt schreiben und auf Rechtschreibfehler achten, denn leicht wird aus necessaryConnection sonst nesesarryConnection. Variablen ähnlicher Schreibweise, etwa counter und counters, sind zu vermeiden.

  • Abstrakte Bezeichner sind ebenfalls zu vermeiden. Die Deklaration int TEN = 10; ist absurd. Eine unsinnige Idee ist auch die folgende: boolean FALSE = true, TRUE = false;. Im Programmcode würde dann mit FALSE und TRUE gearbeitet. Einer der obersten Plätze bei einem Wettbewerb für die verpfuschtesten Java-Programme wäre uns gewiss.

  • Unicode-Sequenzen können zwar in Bezeichnern aufgenommen werden, doch sollten sie vermieden werden. In double übelkübel, \u00FCbelk\u00FCbel; sind beide Bezeichnernamen gleich, und der Compiler meldet einen Fehler.

  • 0 und O und 1 und l sind leicht zu verwechseln. Die Kombination »rn« ist schwer zu lesen und je nach Zeichensatz leicht mit »m« zu verwechseln.[ 73 ](Eine Software wie Mathematica warnt vor Variablen mit fast identischem Namen. ) Gültig – aber böse – ist auch: int ínt, ìnt, înt; boolean bôõleañ;

Bemerkung

In China gibt es 90 Millionen Familien mit dem Nachnamen Li. Das wäre so, als ob wir jede Variable temp1, temp2 … nennen würden.

inline Ist ein Bezeichnername unglücklich gewählt (pneumonoultramicroscopicsilicovolcanoconiosis ist schon etwas lang), so lässt er sich problemlos konsistent umbenennen. Dazu wählen wir im Menü RefactorRename – oder auch kurz (Alt) + (ª) + (R); der Cursor muss auf dem Bezeichner stehen. Eine optionale Vorschau (engl. preview) zeigt an, welche Änderungen die Umbenennung nach sich ziehen wird. Neben Rename gibt es auch noch eine andere Möglichkeit: Dazu lässt sich auf der Variablen mit (Strg) + (1) ein Popup-Fenster mit Local Rename öffnen. Der Bezeichner wird selektiert und lässt sich ändern. Gleichzeitig ändern sich alle Bezüge auf die Variable mit.

 

Zum Seitenanfang

2.3.10Initialisierung von lokalen Variablen Zur vorigen ÜberschriftZur nächsten Überschrift

Die Laufzeitumgebung – bzw. der Compiler – initialisiert lokale Variablen nicht automatisch mit einem Nullwert bzw. Wahrheitsvarianten nicht mit false. Vor dem Lesen müssen lokale Variablen von Hand initialisiert werden, andernfalls gibt der Compiler eine Fehlermeldung aus.[ 74 ](Anders ist das bei Objektvariablen (und statischen Variablen sowie Feldern). Sie sind standardmäßig mit null (Referenzen), 0 (bei Zahlen) oder false belegt. )

Im folgenden Beispiel seien die beiden lokalen Variablen age und adult nicht automatisch initialisiert, und so kommt es bei der versuchten Ausgabe von age zu einem Compilerfehler. Der Grund ist, dass ein Lesezugriff nötig ist, aber vorher noch kein Schreibzugriff stattfand.

int age;

boolean adult;

System.out.println( age ); // inline Local variable age may not

// have been initialized.

age = 18;

if ( age >= 18 ) // Fallunterscheidung: wenn-dann

adult = true;

System.out.println( adult ); // inline Local variable adult may not

// have been initialized.

Weil Zuweisungen in bedingten Anweisungen vielleicht nicht ausgeführt werden, meldet der Compiler auch bei System.out.println(adult) einen Fehler, da er analysiert, dass es einen Programmfluss ohne die Zuweisung gibt. Da adult nur nach der if-Abfrage auf den Wert true gesetzt wird, wäre nur unter der Bedingung, dass age größer gleich 18 ist, ein Schreibzugriff auf adult erfolgt und ein folgender Lesezugriff möglich. Doch da der Compiler annimmt, dass es andere Fälle geben kann, wäre ein Zugriff auf eine nicht initialisierte Variable ein Fehler.

inline Eclipse zeigt einen Hinweis und einen Verbesserungsvorschlag an, wenn eine lokale Variable nicht initialisiert ist.

 


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
 Zum Katalog
Zum Katalog: Java ist auch eine Insel Java ist auch eine Insel

Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?

Ihre Meinung



 Buchempfehlungen
Zum Katalog: Java ist auch eine Insel

Java ist auch eine Insel




Zum Katalog: Java SE 9-Standard-Bibliothek

Java SE 9-Standard-Bibliothek




Zum Katalog: Professionell entwickeln mit Java EE 8

Professionell entwickeln mit Java EE 8




Zum Katalog: Entwurfsmuster

Entwurfsmuster




Zum Katalog: IT-Projektmanagement

IT-Projektmanagement




 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2017

Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de