Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Generics, innere Klassen
10 Die Klassenbibliothek
11 Threads und nebenläufige Programmierung
12 Datenstrukturen und Algorithmen
13 Raum und Zeit
14 Dateien und Datenströme
15 Die eXtensible Markup Language (XML)
16 Grafische Oberflächen mit Swing
17 Grafikprogrammierung
18 Netzwerkprogrammierung
19 Verteilte Programmierung mit RMI und Web–Services
20 JavaServer Pages und Servlets
21 Applets
22 Midlets und die Java ME
23 Datenbankmanagement mit JDBC
24 Reflection und Annotationen
25 Logging und Monitoring
26 Sicherheitskonzepte
27 Java Native Interface (JNI)
28 Dienstprogramme für die Java-Umgebung
Stichwort
Download: - ZIP, ca. 14,1 MB
Buch bestellen
Ihre Meinung?
<< zurück | Galileo Computing / <openbook> / Java-Insel | vor >>
Java ist auch eine Insel (8. Auflage) von Christian Ullenboom Programmieren mit der Java Standard Edition Version 6
Java ist auch eine Insel (8. Aufl.) 8., aktual. Auflage, geb., mit DVD 1.475 S., 49,90 Euro Galileo Computing ISBN 978-3-8362-1371-4 |
| 2 Sprachbeschreibung
|  | 2.1 Elemente der Programmiersprache Java
|  |  | 2.1.1 Token
|  |  | 2.1.2 Textkodierung durch Unicode-Zeichen
|  |  | 2.1.3 Literale
|  |  | 2.1.4 Bezeichner
|  |  | 2.1.5 Reservierte Schlüsselwörter
|  |  | 2.1.6 Kommentare
|  |  | 2.1.7 Die API-Dokumentation
|  | 2.2 Anweisungen formen Programme
|  |  | 2.2.1 Anweisungen
|  |  | 2.2.2 Eine Klasse bildet den Rahmen
|  |  | 2.2.3 Die Reise beginnt am main()
|  |  | 2.2.4 Funktionsaufrufe als Anweisungen
|  |  | 2.2.5 print(), println() und printf() für Bildschirmausgaben
|  |  | 2.2.6 Ausdrucksanweisung
|  |  | 2.2.7 Erste Idee der Objektorientierung
|  |  | 2.2.8 Modifizierer
|  |  | 2.2.9 Anweisungen und Blöcke
|  | 2.3 Datentypen, Typisierung, Variablen und Zuweisungen
|  |  | 2.3.1 Primitive Datentypen im Überblick
|  |  | 2.3.2 Variablendeklarationen
|  |  | 2.3.3 Zuweisungsoperator
|  |  | 2.3.4 Variablendeklaration mit Wertinitialisierung
|  |  | 2.3.5 Wahrheitswerte
|  |  | 2.3.6 Ganzzahlige Datentypen
|  |  | 2.3.7 Die Fließkommazahlen float und double
|  |  | 2.3.8 Alphanumerische Zeichen
|  |  | 2.3.9 Gute Namen, schlechte Namen
|  | 2.4 Blöcke, Initialisierung und Sichtbarkeit
|  |  | 2.4.1 Blöcke und Anweisungen
|  |  | 2.4.2 Initialisierung von lokalen Variablen
|  |  | 2.4.3 Sichtbarkeit und Gültigkeitsbereich
|  | 2.5 Ausdrücke, Operanden und Operatoren
|  |  | 2.5.1 Arithmetische Operatoren
|  |  | 2.5.2 Unäres Minus und Plus
|  |  | 2.5.3 Zuweisung mit Operation
|  |  | 2.5.4 Präfix- oder Postfix-Inkrement und -Dekrement
|  |  | 2.5.5 Die relationalen Operatoren und die Gleichheitsoperatoren
|  |  | 2.5.6 Logische Operatoren Und, Oder, Xor, Nicht
|  |  | 2.5.7 Rang der Operatoren in der Auswertungsreihenfolge
|  |  | 2.5.8 Die Typanpassung (das Casting)
|  |  | 2.5.9 Überladenes Plus für Strings
|  | 2.6 Bedingte Anweisungen oder Fallunterscheidungen
|  |  | 2.6.1 Die if-Anweisung
|  |  | 2.6.2 Die Alternative mit einer if/else-Anweisung wählen
|  |  | 2.6.3 Die switch-Anweisung bietet die Alternative
|  | 2.7 Schleifen
|  |  | 2.7.1 Die while-Schleife
|  |  | 2.7.2 Die do-while-Schleife
|  |  | 2.7.3 Die for-Schleife
|  |  | 2.7.4 Schleifenbedingungen und Vergleiche mit ==
|  |  | 2.7.5 Ausbruch planen mit break und Wiedereinstieg mit continue
|  |  | 2.7.6 break und continue mit Sprungmarken
|  | 2.8 Methoden einer Klasse
|  |  | 2.8.1 Bestandteil einer Funktion
|  |  | 2.8.2 Signatur-Beschreibung in der Java-API
|  |  | 2.8.3 Aufruf einer Methode
|  |  | 2.8.4 Methoden ohne Parameter deklarieren
|  |  | 2.8.5 Statische Methoden (Klassenmethoden)
|  |  | 2.8.6 Parameter, Argument und Wertübergabe
|  |  | 2.8.7 Methoden vorzeitig mit return beenden
|  |  | 2.8.8 Nicht erreichbarer Quellcode bei Funktionen
|  |  | 2.8.9 Rückgabewerte
|  |  | 2.8.10 Methoden überladen
|  |  | 2.8.11 Vorgegebener Wert für nicht aufgeführte Argumente
|  |  | 2.8.12 Finale lokale Variablen
|  |  | 2.8.13 Rekursive Methoden
|  | 2.9 Weitere Operatoren
|  |  | 2.9.1 Bits und Bytes
|  |  | 2.9.2 Operationen auf Bit-Ebene
|  |  | 2.9.3 Die Verschiebeoperatoren
|  |  | 2.9.4 Ein Bit setzen, löschen, umdrehen und testen
|  |  | 2.9.5 Bit-Funktionen der Integer- und Long-Klasse
|  |  | 2.9.6 Der Bedingungsoperator
|  |  | 2.9.7 Operator vermisst
|  | 2.10 Einfache Benutzereingaben
|  | 2.11 Zum Weiterlesen
## 2.6 Bedingte Anweisungen oder Fallunterscheidungen Kontrollstrukturen dienen in einer Programmiersprache dazu, Programmteile unter bestimmten Bedingungen auszuführen. Java bietet zum Ausführen verschiedener Programmteile eine if- und if/else-Anweisung sowie die switch-Anweisung. Neben der Verzweigung dienen Schleifen dazu, Programmteile mehrmals auszuführen. Bedeutend im Wort »Kontrollstrukturen« ist der Teil »Struktur«, denn die Struktur zeigt sich schon durch das bloße Hinsehen. Als es noch keine Schleifen und »hochwertige« Kontrollstrukturen gab, sondern nur ein Wenn/Dann und einen Sprung, war die Logik des Programms nicht offensichtlich; das Resultat nannte sich Spaghetticode. Obwohl ein allgemeiner Sprung in Java mit goto nicht möglich ist, besitzt die Sprache dennoch eine spezielle Sprungvariante. In Schleifen erlauben continue und break definierte Sprungziele. ### 2.6.1 Die if-Anweisung Die if-Anweisung besteht aus dem Schlüsselwort if, dem zwingend ein Ausdruck mit dem Typ boolean in Klammern folgt. Es folgt eine Anweisung, die oft eine Blockanweisung ist.
Beispiel Ein relationaler Vergleich, ob der Inhalt der Variablen age gleich 14 ist:
    if ( age == 14 )
      System.out.println( "Durchschnittlich 15.000 Gewaltakte im TV gesehen." );
Die weitere Abarbeitung der Anweisungen hängt vom Ausdruck im if ab. Ist das Ergebnis des Ausdrucks wahr (true), wird die Anweisung ausgeführt; ist das Ergebnis des Ausdrucks falsch (false), so wird mit der ersten Anweisung nach der if-Anweisung fortgefahren. Im Gegensatz zu C(++) und vielen Skriptsprachen muss der Testausdruck für die Bedingung der if-Anweisung ohne Ausnahme vom Typ boolean sein – für Schleifen gilt das Gleiche. Soll zum Beispiel die if-Anweisung testen, ob eine Referenzvariable ref ein Objekt referenziert, dann ist die Variable mit null zu vergleichen.
    String ref = null;
    if ( ref != null )
    {
      ...
    }
C(++) bewertet einen numerischen Ausdruck als wahr, wenn das Ergebnis des Ausdrucks ungleich 0 ist. [In C(++) ist auch if (ref) gültig.] #### if-Abfragen und Blöcke Hinter dem if und der Bedingung erwartet der Compiler eine Anweisung. Sind mehrere Anweisungen in Abhängigkeit von der Bedingung auszuführen, ist ein Block zu setzen; andernfalls ordnet der Compiler nur die nächstfolgende Anweisung der Fallunterscheidung zu, auch wenn mehrere Anweisungen optisch abgesetzt sind. [In der Programmiersprache Python bestimmt die Einrückung die Zugehörigkeit.] Dies ist eine große Gefahr für Programmierer, die optisch Zusammenhänge schaffen wollen, die in Wirklichkeit nicht existieren. Dazu ein Beispiel: Eine if-Anweisung soll testen, ob die Variable y den Wert 0 hat. In dem Fall soll sie die Variable x auf 0 setzen und zusätzlich auf dem Bildschirm »Null« anzeigen. Zunächst die semantisch falsche Variante:
    if ( y == 0 )
      x = 0;
      System.out.println( "Null" );
Sie ist semantisch falsch, da unabhängig von y immer eine Ausgabe erscheint. Der Compiler interpretiert die Anweisungen in folgendem Zusammenhang, wobei die Einrückung hier korrekt ist und den Sinn richtig widerspiegelt:
    if ( y == 0 )
      x = 0;
    System.out.println( "Null" );
Für unser Programm gibt demnach der korrekt geklammerte Ausdruck die gewünschte Ausgabe:
    if ( y == 0 ) {
      x = 0;
      System.out.println( "Null" );
    }
Tipp Einrückungen ändern nicht die Semantik des Programms! Einschübe können das Verständnis nur empfindlich stören. Damit das Programm korrekt wird, müssen wir einen Block verwenden und die Anweisungen zusammensetzen. Einrückungen sollten Entwickler konsistent zur Verdeutlichung von Abhängigkeiten nutzen.
#### Zusammengesetzte Bedingungen Die bisherigen Abfragen waren sehr einfach, doch kommen in der Praxis viel komplexere Bedingungen vor. Oft im Einsatz sind die logischen Operatoren &&, ||, !. Wenn wir etwa testen wollen, ob eine Zahl x entweder gleich 7 oder größer gleich 10 ist, schreiben wir die zusammengesetzte Bedingung:
    if ( x == 7 || x >= 10 )
      ...
Sind die logisch verknüpften Ausdrücke komplexer, so sollten zur Unterstützung der Lesbarkeit die einzelnen Bedingungen in Klammern gesetzt werden, da nicht jeder sofort die Tabelle mit den Vorrangregeln für die Operatoren im Kopf hat. Hier klicken, um das Bild zu vergrößern Abbildung 2.4 if und + bietet an, eine if-Anweisung mit Block anzulegen. ### 2.6.2 Die Alternative mit einer if/else-Anweisung wählen Neben der einseitigen Alternative existiert die zweiseitige Alternative. Das optionale Schlüsselwort else mit angehängter Anweisung veranlasst die Ausführung einer Alternative, wenn der if-Test falsch ist.
Beispiel Gibt abhängig von der Relation x zu y eine Meldung aus:
    if ( x < y )
      System.out.println( "x ist echt kleiner als y." );
    else
      System.out.println( "x ist größer oder gleich y." );
Falls der Ausdruck wahr ist, wird die erste Anweisung ausgeführt, andernfalls die zweite Anweisung. Somit ist sichergestellt, dass in jedem Fall eine Anweisung ausgeführt wird. #### Dangling-Else-Problem Bei Verzweigungen mit else gibt es ein bekanntes Problem, das Dangling-Else-Problem genannt wird. Zu welcher Anweisung gehört das folgende else?
    if ( Ausdruck1 )
      if ( Ausdruck2 )
        Anweisung1;
    else
      Anweisung2;
Die Einrückung suggeriert, dass das else die Alternative zur ersten if-Anweisung ist. Dies ist aber nicht richtig. Die Semantik von Java (und auch fast aller anderen Programmiersprachen) ist so definiert, dass das else zum innersten if gehört. Daher lässt sich nur der Programmiertipp geben, die if-Anweisungen zu klammern:
    if ( Ausdruck1 )
    {
      if ( Ausdruck2 )
      {
        Anweisung1;
      }
    }
    else
    {
      Anweisung2;
    }
So kann eine Verwechslung gar nicht erst aufkommen. Wenn das else immer zum innersten if gehört und das nicht erwünscht ist, können wir, wie gerade gezeigt, mit geschweiften Klammern arbeiten oder auch eine leere Anweisung im else-Zweig hinzufügen:
    if ( x >= 0 )
      if ( x != 0 )
        System.out.println( "x echt größer null" );
      else
        ; // x ist gleich null
    else
      System.out.println( "x echt kleiner null" );
#### Das böse Semikolon An dieser Stelle ist ein Hinweis angebracht: Ein Programmieranfänger schreibt gerne hinter die schließende Klammer der if-Anweisung ein Semikolon. Das führt zu einer ganz anderen Ausführungsfolge. Ein Beispiel:
    int age = 29;
    if ( age < 0 ) ;
      System.out.println( "Aha, noch im Mutterleib" );
    if ( age > 150 ) ;
      System.out.println( "Aha, ein neuer Moses" );
Das Semikolon führt dazu, dass die leere Anweisung in Abhängigkeit von der Bedingung ausgeführt wird und unabhängig vom Inhalt der Variablen age immer die Ausgabe »Aha, noch im Mutterleib« und »Aha, ein neuer Moses« erzeugt. Das ist sicherlich nicht beabsichtigt. Das Beispiel soll ein warnender Hinweis sein, in jeder Zeile nur eine Anweisung zu schreiben – und die leere Anweisung durch das Semikolon ist eine Anweisung. Folgen hinter einer if-Anweisung zwei Anweisungen, die durch keine Blockanweisung zusammengefasst sind, dann wird die eine folgende else-Anweisung als Fehler bemängelt, da der zugehörige if-Zweig fehlt. Der Grund ist, dass der if-Zweig nach der ersten Anweisung ohne else zu Ende ist.
    int age = 29;
    if ( age < 0 )
      ;
    System.out.println( "Aha, noch im Mutterleib" );
    else if ( age > 150 ) ;
      System.out.println( "Aha, ein neuer Moses" );
Das führt zu der Fehlermeldung 'else' without 'if'. #### Mehrfachverzweigung beziehungsweise geschachtelte Alternativen if-Anweisungen zur Programmführung kommen sehr häufig in Programmen vor, und noch häufiger ist es, eine Variable auf einen bestimmten Wert zu prüfen. Dazu werden if- und if/else-Anweisungen gerne geschachtelt (kaskadiert). Wenn eine Variable einem Wert entspricht, dann wird eine Anweisung ausgeführt, sonst wird die Variable mit einem anderen Wert getestet und so weiter. Kaskadierte if-Anweisungen sollen uns helfen, die Variable tage passend nach dem Monat zu belegen:
    if ( monat == 4 )
      tage = 30;
    else if ( monat == 6 )
      tage = 30;
    else if ( monat == 9 )
      tage = 30;
    else if ( monat == 11 )
      tage = 30;
    else if ( monat == 2 )
      if ( schaltjahr )
        tage = 29;
      else
        tage = 28;
      else
        tage = 31;
Die eingerückten Verzweigungen nennen sich auch angehäufte if-Anweisungen oder if-Kaskade, da jede else-Anweisung ihrerseits weitere if-Anweisungen enthält, bis alle Abfragen gemacht sind. ### 2.6.3 Die switch-Anweisung bietet die Alternative Eine Kurzform für speziell gebaute, angehäufte if-Anweisungen bietet switch. Im switch-Block gibt es eine Reihe von unterschiedlichen Sprungzielen, die mit case markiert sind. Ein einfacher Taschenrechner für vier binäre Operatoren ist mit switch schnell implementiert: Listing 2.10 Calculator.java, main
    char operator=javax.swing.JOptionPane.showInputDialog("Operator").charAt( 0 );
    double x=Double.parseDouble(javax.swing.JOptionPane.showInputDialog("Zahl 1"));
    double y=Double.parseDouble(javax.swing.JOptionPane.showInputDialog("Zahl 2"));

    switch ( operator )
    {
      case '+':
        System.out.println( x + y );
        break;
      case '-':
        System.out.println( x – y );
        break;
      case '*':
        System.out.println( x * y );
        break;
      case '/':
        System.out.println( x / y );
        break;
    }
Die Laufzeitumgebung sucht eine bei case genannte Konstante, die mit dem in switch angegebenen Ausdruck übereinstimmt. Gibt es einen Treffer, so werden alle beim case folgenden Anweisungen ausgeführt, bis ein (optionales) break die Abarbeitung beendet. (Ohne break geht die Ausführung im nächsten case-Block automatisch weiter. Mehr zu diesen »It’s not a bug, it’s a feature!« später.) Stimmt keine Konstante eines case-Blocks mit dem switch-Ausdruck überein, werden erst einmal keine Anweisungen im switch-Block ausgeführt. Die switch-Anweisung hat einige Einschränkungen: Ausdrücke sind auf den primitiven Datentyp int beschränkt. Elemente vom Datentyp byte, char und short sind somit erlaubt, da der Compiler den Typ automatisch auf int anpasst. (Ebenso sind die Aufzählungen und die Wrapper-Objekte Character, Byte, Short, Integer möglich, da Java automatisch die Werte entnimmt – mehr dazu in Kapitel 6, »Eigene Klassen schreiben«, und Kapitel 8, »Exceptions«.) Es können nicht die Datentypen boolean, long, float, double benutzt werden. Auch Objekt-Typen – wozu Strings gehören– sind nicht erlaubt. Da Zeichenkettenvergleiche nicht möglich sind, fallen auch Überprüfungen auf reguläre Ausdrücke heraus, die insbesondere Skriptsprachen anbieten. Die bei switch genannten Werte müssen konstant sein. Dynamische Ausdrücke, etwa Rückgaben aus Funktionsaufrufen, sind nicht möglich. Es sind keine Bereichsangaben möglich. Das wäre etwa bei Altersangaben nützlich, um zum Beispiel die Bereiche 0–18, 19–60, 60–99 zu definieren. Als Lösung bleiben nur angehäufte if-Anweisungen.
Hinweis Obwohl ein fehlendes break zu lästigen Programmierfehlern führt, haben die Java-Entwickler dieses Verhalten vom syntaktischen Vorgänger C übernommen. Eine interessante Lösung wäre gewesen, das Verhalten genau umzudrehen und das Durchfallen explizit einzufordern, zum Beispiel mit einem Schlüsselwort. C# wählt hier auch eine andere Lösung.
#### Alles andere mit default abdecken Soll ein Programmteil in genau dem Fall abgearbeitet werden, in dem es keine Übereinstimmung mit irgendeiner case-Konstanten gibt, so lässt sich die besondere Sprungmarke default einsetzen. Soll zum Beispiel im Fall eines unbekannten Operators das Programm eine Fehlermeldung ausgeben, schreiben wir:
    switch ( operator )
    {
      case '+':
        System.out.println( x + y );
        break;
      case '-':
        System.out.println( x – y );
        break;
      case '*':
        System.out.println( x * y );
        break;
      case '/':
        System.out.println( x / y );
        break;
      default:
        System.err.println( "Unknown operator " + operator );
      }
    }
Der Nutzen von default ist der, falsch eingegebene Operatoren zu erkennen, denn die Anweisungen hinter default werden immer dann ausgeführt, wenn keine case-Konstante gleich dem switch-Ausdruck war. default kann auch zwischen den case-Blöcken auftauchen, doch das ist wenig übersichtlich und nicht für allgemeine Anwendungen zu empfehlen. Somit würde der default-Programmteil auch abgearbeitet, wenn ein dem default vorangehender case-Teil kein break hat. #### switch hat Durchfall Bisher haben wir in die letzte Zeile eine break-Anweisung gesetzt. Ohne ein break würden nach einer Übereinstimmung alle nachfolgenden Anweisungen ausgeführt. Sie laufen somit in einen neuen Abschnitt herein, bis ein break oder das Ende von switch erreicht ist. Da dies vergleichbar mit einem Spielzeug ist, bei dem Kugeln von oben nach unten durchfallen, nennt sich dieses auch Fall-Through. Ein häufiger Programmierfehler ist, das break zu vergessen, und daher sollte ein beabsichtigter Fall-Through immer als Kommentar angegeben werden. Über dieses Durchfallen ist es möglich, bei unterschiedlichen Werten immer die gleiche Anweisung ausführen zu lassen: Listing 2.11 VowelTest.java, main()
    char charToTestIfVowel = 'u';

    switch ( charToTestIfVowel )
    {
      case 'a': // fall through
      case 'e':
      case 'i':
      case 'o':
      case 'u':
        System.out.println( charToTestIfVowel + " is vowel" );
        break;
      default:
        System.out.println( charToTestIfVowel + " is no vowel" );
    }
In dem Beispiel bestimmt eine case-Anweisung, ob die Variable charToTestIfVowel einen Vokal enthält. Fünf case-Anweisungen decken jeweils einen Buchstaben (Vokal) ab. Stimmt der Inhalt von charToTestIfVowel mit einer der Vokal-Konstanten überein, so »fällt« das Programm in den Zweig mit der Ausgabe, dass charToTestIfVowel ein Vokal ist. Dieses Durchfallen über die case-Zweige ist sehr praktisch, da der Programmcode für die Ausgabe so nicht dupliziert werden muss. Tritt auf der anderen Seite keine Bedingung im switch-Teil ein, so gibt die Anweisung im default-Teil die Ausgabe aus, dass charToTestIfVowel kein Vokal ist. Stehen mehrere case-Blöcke untereinander, um damit Bereiche abzubilden, nennt sich das auch Stack-Case-Labels. Hier klicken, um das Bild zu vergrößern Abbildung 2.5 switch und + bietet an, ein Grundgerüst für eine switch-Fallunterscheidung anzulegen. ### Ihr Kommentar Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück | <top> | vor >>
Zum Katalog
Java ist auch eine Insel Jetzt bestellen
Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen? Ihre Meinung
Tipp
| Coding for Fun
Buchempfehlungen
| Objektorientierte Programmierung
| Einstieg in Eclipse 3.4
| Java 6 lernen mit Eclipse
| NetBeans Platform 6
| Java und XML
| Visual C# 2008
| IT-Handbuch für Fachinformatiker
| C++ von A bis Z
Shopping
Versandkostenfrei bestellen in Deutschland und Österreich Info

Copyright © Galileo Press 2009
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.

[Galileo Computing]
Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de