Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
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 Die Funktionsbibliothek
10 Threads und nebenläufige Programmierung
11 Raum und Zeit
12 Datenstrukturen und Algorithmen
13 Dateien und Datenströme
14 Die eXtensible Markup Language (XML)
15 Grafische Oberflächen mit Swing
16 Grafikprogrammierung
17 Netzwerkprogrammierung
18 Verteilte Programmierung mit RMI und Web-Services
19 JavaServer Pages und Servlets
20 Applets
21 Midlets und die Java ME
22 Datenbankmanagement mit JDBC
23 Reflection und Annotationen
24 Logging und Monitoring
25 Sicherheitskonzepte
26 Java Native Interface (JNI)
27 Dienstprogramme für die Java-Umgebung
A Die Begleit-DVD
Stichwort

Download:
- ZIP, ca. 12,5 MB
Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel

Java ist auch eine Insel
7., aktualisierte Auflage
geb., mit DVD (November 2007)
1.492 S., 49,90 Euro
Galileo Computing
ISBN 978-3-8362-1146-8
Pfeil 2 Sprachbeschreibung
Pfeil 2.1 Elemente der Programmiersprache Java
Pfeil 2.1.1 Textkodierung durch Unicode-Zeichen
Pfeil 2.1.2 Literale
Pfeil 2.1.3 Bezeichner
Pfeil 2.1.4 Reservierte Schlüsselwörter
Pfeil 2.1.5 Token
Pfeil 2.1.6 Kommentare
Pfeil 2.2 Anweisungen formen Programme
Pfeil 2.2.1 Anweisungen
Pfeil 2.2.2 Eine Klasse bildet den Rahmen
Pfeil 2.2.3 Die Reise beginnt am main()
Pfeil 2.2.4 Programme übersetzen und starten
Pfeil 2.2.5 Funktionsaufrufe als Ausdrücke und Anweisungen
Pfeil 2.2.6 print(), println() und printf() für Bildschirmausgaben
Pfeil 2.2.7 Modifizierer
Pfeil 2.2.8 Anweisungen und Blöcke
Pfeil 2.3 Datentypen
Pfeil 2.3.1 Primitive Datentypen im Überblick
Pfeil 2.3.2 Wahrheitswerte
Pfeil 2.3.3 Variablendeklarationen
Pfeil 2.3.4 Ganzzahlige Datentypen
Pfeil 2.3.5 Die Fließkommazahlen float und double
Pfeil 2.3.6 Alphanumerische Zeichen
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 Und, Oder, Xor, Nicht
Pfeil 2.4.8 Rang der Operatoren in der Auswertungsreihenfolge
Pfeil 2.4.9 Die Typanpassung (das Casting)
Pfeil 2.4.10 Überladenes Plus für Strings
Pfeil 2.4.11 Was C(++)-Programmierer vermissen könnten
Pfeil 2.5 Bedingte Anweisungen oder Fallunterscheidungen
Pfeil 2.5.1 Die if-Anweisung
Pfeil 2.5.2 Die Alternative mit einer if/else-Anweisung wählen
Pfeil 2.5.3 Die switch-Anweisung bietet die Alternative
Pfeil 2.6 Schleifen
Pfeil 2.6.1 Die while-Schleife
Pfeil 2.6.2 Schleifenbedingungen und Vergleiche mit ==
Pfeil 2.6.3 Die do-while-Schleife
Pfeil 2.6.4 Die for-Schleife
Pfeil 2.6.5 Ausbruch planen mit break und Wiedereinstieg mit continue
Pfeil 2.6.6 break und continue mit Sprungmarken
Pfeil 2.7 Methoden einer Klasse
Pfeil 2.7.1 Bestandteil einer Funktion
Pfeil 2.7.2 Beschreibungen in der Java-API
Pfeil 2.7.3 Aufruf einer Methode
Pfeil 2.7.4 Methoden ohne Parameter
Pfeil 2.7.5 Statische Funktionen (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 Funktionen
Pfeil 2.7.9 Rückgabewerte
Pfeil 2.7.10 Methoden überladen
Pfeil 2.7.11 Vorgegebener Wert für nicht aufgeführte Argumente
Pfeil 2.7.12 Finale lokale Variablen
Pfeil 2.7.13 Rekursive Funktionen
Pfeil 2.7.14 Die Türme von Hanoi
Pfeil 2.8 Weitere Operatoren
Pfeil 2.8.1 Bits und Bytes
Pfeil 2.8.2 Operationen auf Bit-Ebene
Pfeil 2.8.3 Die Verschiebeoperatoren
Pfeil 2.8.4 Ein Bit setzen, löschen, umdrehen und testen
Pfeil 2.8.5 Bit-Funktionen der Integer- und Long-Klasse
Pfeil 2.8.6 Der Bedingungsoperator
Pfeil 2.9 Einfache Benutzereingaben
Pfeil 2.10 Zum Weiterlesen


Galileo Computing - Zum Seitenanfang

2.5 Bedingte Anweisungen oder Fallunterscheidungen Zur nächsten ÜberschriftZur vorigen Überschrift

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.


Galileo Computing - Zum Seitenanfang

2.5.1 Die if-Anweisung Zur nächsten ÜberschriftZur vorigen Überschrift

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 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-Anfragen 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:

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

Abbildung 2.3 if und Keyboard Strg +Leertaste bietet an, eine if-Anweisung mit Block anzulegen.


Galileo Computing - Zum Seitenanfang

2.5.2 Die Alternative mit einer if/else-Anweisung wählen Zur nächsten ÜberschriftZur vorigen Überschrift

Neben der einseitigen Alternative existiert die zweiseitige Alternative. Das optionale Schlüsselwort else veranlasst die Ausführung der alternativen Anweisung, wenn der Test falsch ist.


Beispiel 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 Variable 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-Anweisung 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.


Galileo Computing - Zum Seitenanfang

2.5.3 Die switch-Anweisung bietet die Alternative topZur vorigen Überschrift

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 Taschenrechner ist für einige binäre Operatoren mit switch gut implementiert:

Listing 2.10 Calculator.java, binaryOperatorOperation()

static void binaryOperatorOperation( char op, double x, double y ) 
{ 
  switch ( op ) 
  { 
    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; 
  } 
}

Zur Ausführungszeit vergleicht die Laufzeitumgebung nacheinander den bei switch angegebenen konstanten Ausdruck mit jedem einzelnen konstanten Ausdruck der Sprungziele, bis sie einen Treffer erzielt. Dann werden alle folgenden Anweisungen hinter der Sprungmarke ausgeführt, bis ein (optionales) break die Abarbeitung beendet. Es kann passieren, dass keine Anweisungen im switch-Block ausgeführt werden, wenn der switch-Ausdruck mit keinem konstanten Ausdruck übereinstimmt.

Eine Einschränkung der switch-Anweisung besteht darin, dass die Ausdrücke auf den primitiven Datentyp int beschränkt sind. (Elemente vom Datentyp byte, char und short sind auch 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 und 8.) Es können keine größeren Typen wie long oder Fließkommazahlen oder gar Objekt-Typen wie String benutzt werden. Als Alternative bleiben angehäufte if-Anweisungen. Dies ist auch der einzige Weg, um Bereiche abzudecken.

Alles andere mit default abdecken

Gibt es keine Übereinstimmung mit einer Konstante, so lässt sich optional (und dann nur einmalig) die Sprungmarke default einsetzen. Soll zum Beispiel im Fall eines unbekannten Operators das Programm eine Ausnahme auslösen, schreiben wir:

switch ( op ) 
{ 
  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: 
    throw new IllegalArgumentException( "Unknown Operator!" ); 
}

Ohne Übereinstimmung mit einem konkreten Ziel geht die Abarbeitung des Programmcodes hinter default weiter. default sollte nicht dafür verwendet werden, den letzten gültigen Fall abzudecken. Dazu ist besser ein case gedacht; die Idee von default ist, alles andere abzuhandeln. default kann auch zwischen den Konstanten eingesetzt werden, sodass case-Anweisungen vorangehen und nachfolgen. Das ist aber wenig übersichtlich.

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

public static boolean isVowel( char c ) 
{ 
  boolean vowel; 
  switch ( c ) { 
    case 'a':                    // fall-through 
    case 'e': case 'i': case 'o': case 'u': 
      vowel = true; 
      break; 
    default: 
      vowel = false; 
  } 
  return vowel; 
}

In dem Beispiel bestimmt eine case-Anweisung, ob die Variable c einen Vokal enthält. Fünf case-Anweisungen decken jeweils einen Buchstaben ab. Stimmt die Variable mit einer Konstanten überein, so »fällt« der Interpreter in den Programmcode der Zuweisung. Dieses Durchfallen über die case-Zweige ist praktisch, so wie es unser Programmcode für das Ist-Vokal-Problem zeigt. Der erste case-Zweig setzt die Boolesche Variable vowel bei einem Vokal auf wahr. Tritt die Bedingung nicht ein, so weist die Anweisung im default-Teil der Variablen vokal den Wert falsch zu.


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


Abbildung 2.4

Eclipse
switch und Keyboard Strg +Leertaste 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.






<< zurück



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