Java Programmierung
Kap.5:   ANWEISUNGEN, BLOCKSTRUKTUR

Kapitel-Index
  5.1    Zuweisung               
  5.2    Verzweigungen
  5.2.1     if-Verzweigung
  5.2.2     switch-Verzweigung  
  5.3    Schleifen                                       
  5.3.1     for-Schleife                               
  5.3.2     while-Schleife, do-Schleife                                 
  5.4    Strukturierte Sprünge
  5.4.1     break, continue, ggf. labeled
  5.4.2     exit, return, assert
  5.5    Bereichsschachtelung                   
  5.5.1     vereinbart / sichtbar     
  5.5.2     lokal / global / verdeckt 
  5.5.3     Einschränkung der Namensfreiheit
  5.6    Testfragen

  Eine Anweisung (statement) ist eine Tätigkeit, die bei Erreichen der betreffenden Programmstelle ausgeführt wird. Do/Break/Continue/ Return/Assert/Throw-Anweisungen enden mit Semikolon,
   z.B.        do x++;while(x<y);                                .
  Anweisungsausdrücke (StatementExpression), d.h. Assignment/ Crement/MethodInvocation/ClassInstanceCreationExpression, werden durch Setzen eines abschließenden Semikolons zu Ausdrucks-Anweisungen (ExpressionStatement). Der Seiteneffekt des Ausdrucks wird zum Effekt der Anweisung,
   z.B.        x=1   (Effekt:       Ausdruck x=1 erhält Wert 1) 
                     (Seiteneffekt: Variable x   erhält Wert 1) ,
               x=1;  (Effekt:       Variable x   erhält Wert 1) .
  Switch/Try/Synchronized-Anweisungen enden mit einem Block,
   z.B.        switch(x) {case 0:y=0;break;default:y=1;}        .
  If/For/While-Anweisungen enden mit Semikolon oder Block,
   z.B.        if(x==1) y=1;   (nicht empfehlenswert)           ,
               if(x==1){y=1;}        (empfehlenswert)           .

  Eine Anweisung ist nach Syntaxdiagramm 69 von der Form
069°:Statement                    Anweisung
HHHHHHHHHHHHHHHHHHHHHHHHHH,-------------,HHHHHHHHHHHHHHHHHHHHHHHHH  
H ->--------------------->| IfStatement |-----------,   ,        H
H   |        Label   | |  '-------------'           |   | Semi-  H
H   |      ,------,  | |  ,--------------,          |   | colon  H
H   '- : <-|Identi|<-' |->| ForStatement |----------|   | or     H
H          |-fier |    |  '--------------'          |   | Block  H
H          '------'    |  ,----------------,        |   | ending H
H  nested labels must  |->| WhileStatement |--------|   | State- H           
H     be different     |  '----------------'        |   ' ment   H          
H                      |  ,-------------,           |   ,        H
H                      |->| DoStatement |-----------|   |        H           
H                      |  '-------------'           |   |        H          
H                      |  ,----------------,        |   |        H
H                      |->| BreakStatement |--------|   |        H           
H                      |  '----------------'        |   |        H          
H                      |  ,-------------------,     |   |        H 
H                      |->| ContinueStatement |-----|   |        H            
H                      |  '-------------------'     |   |        H           
H                      |  ,-----------------,       |   |        H    
H                      |->| ReturnStatement |-------|   |        H            
H                      |  '-----------------'       |   |        H           
H                      |  ,-----------------,       |   |        H
H                      |->| AssertStatement |-------|   |        H           
H                      |  '-----------------'       |   | Semi-  H          
H                      |  ,----------------,        |   | colon  H
H                      |->| ThrowStatement |--------|   | ending H           
H                      |  '----------------'        |   | State- H          
H                   ,- |  ,------------,            |   | ment   H
H                   |  |->| Assignment |-----,      |   |        H           
H                   |  |  '------------'     |      |   |        H          
H                   |  |  ,---------,        |      |   |        H
H       Statement-  |  |->| Crement |--------|      |   |        H           
H       Expression -|  |  '---------'        |      |   |        H          
H                   |  |  ,----------------, |      |   |        H
H                   |  |->|MethodInvocation|-|      |   |        H           
H                   |  |  '----------------' |      |   |        H          
H                   |  |  ,----------------, |      |   |        H
H                   |  |->|Cl.Inst.Cr.Expr.|-|      |   |        H           
H                   '- |  '----------------' |      |   |        H           
H                      |->---------------------> ; -|   '        H          
H                      |  ,-----------------,       |   ,        H
H                      |->| SwitchStatement |-------|   |        H           
H                      |  '-----------------'       |   |        H          
H                      |  ,--------------,          |   |        H
H                      |->| TryStatement |----------|   | Block  H           
H                      |  '--------------'          |   | ending H          
H                      |  ,-----------------------, |   | State- H
H                      |->| SynchronizedStatement |-|   | ment   H           
H                      |  '-----------------------' |   |        H          
H                      |  ,-------,                 |   |        H
H                      '->| Block |-------------------> '        H
HHHHHHHHHHHHHHHHHHHHHHHHHH'-------'HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

5.1      Zuweisung


  Eine Zuweisung (Assignment) ohne abschließendes Semikolon ist ein Ausdruck (Expression), speziell eine Operation mit einem Zuweisungsoperator (AssignmentOperator Syntax.036), und nach Syntaxdiagramm 058 von der Form
058: Assignment                   Zuweisung
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
H                                                                H
H     L e f t H a n d S i d e                                    H
H      VariableOrField-                                          H
H        ,------,                                                H
H    --->| Name |--------,                                       H
H     |  '------'        |                                       H
H     |  ,-------------, |                                       H
H     |->| FieldAccess |-|                                       H
H     |  '-------------' |  ,-------------,                      H
H     |  ,-------------, |  | Assignment- |  ,------------,      H       
H     '->| ArrayAccess |--->| Operator    |->| Expression |->    H       
H        '-------------'    '-------------'  '------------'      H
H                                                                H
H The LeftHandSide must be a na-  Die  LinkeSeite  muss eine be- H
H med  variable,  such as a Name  nannte Variable sein, z.B. der H
H of  a  local  variable   or  a  Name  einer  lokalen Variablen H
H field,   or   results  from  a  oder  eines  Datenfelds,  oder H
H FieldAccess or an ArrayAccess.  ergibt  sich  aus einem Daten- H
H                                 feldZugriff   oder  einem Rei- H
H                                 hungsZugriff.                  H
H                                                                H
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
  Mit abschließendem Semokolon wird eine Zuweisung zu einer Zuweisungsanweisung (AssignmentStatement), d.h. zu einer Anweisung (Statement, Syntax.069),
    z.B.  c           =Math.sqrt(a*a+b*b);    // Identifier Name
          Ware.preis +=kost1*x+kost0;         // qualified  Name 
          super.color*=fact;                  // FieldAccess
          pas[n][n]   =1;                     // ArrayAccess
  Obwohl allgemeine Zuweisungen, d.h. Zuweisungen mit Operatoren * Multiplication, / Division, % Remainder, + AdditionRespConcatenation, - Subtraction, << BitwiseShiftLeft, >> BitwiseShiftRightSameSign, >>> BitwiseShiftRightZeroSign, & BitwiseRespLogicalAnd, ^ BitwiseRespLogicalNotEqual, | BitwiseRespLogicalOr, vereinfacht als Operation mit anschließender einfacher Zuweisung erklärt werden, sind doch Unterschiede zu beachten,
  z.B. int  i=0;int[] a={0,3,5};out.print(       a[++i]+=1); // 4
       int  i=0;int[] a={0,3,5};out.print(a[++i]=a[++i]+1);  // 6
       char c='c';              out.print(c+=1);             // d 
       char c='c';              out.print(c=(char)(c+1));    // d
       char c='c';              out.print(c=c+1);   // Typ-Fehler

  Vor allem ist eine allgemeine Zuweisung (Assignment),
    z.B.   x*=3
schneller als die entsprechende einfache Zuweisung (SimpleAssignment)
    z.B.   x=x*3

                      ,---------------------,
VVVVVVVVVVVVVVVVVVVVVV| Zuweisung (Prinzip) |VVVVVVVVVVVVVVVVVVVVV
VV                    '---------------------'                   VV
VV                                                              VV
VV # Aufbau:                                                    VV
VV    Links muss eine Variable stehen (siehe oben Syntax.058).  VV
VV    Rechts kann ein beliebiger Ausdruck (Expression) stehen.  VV
VV                                                              VV
VV # Typ-Übereinstimmung, implizite Konvertierung (2.1):        VV
VV    Der  Typ  rechts muss  mit dem Typ links übereinstimmen,  VV
VV       z.B. double arc; arc=2*rad*3.14;                       VV
VV    Bei numerischen  Operanden wird falls möglich der rechte  VV
VV     Operand in den Typ des linken Operanden verlustfrei oder VV
VV     erweiternd zum nächsten Gleitpunktzahl-Wert konvertiert, VV
VV     z.B. int i=123456789;float f;f=i;     // f==1.23456792E8 VV
VV    Bei konstantem Ausdruck (Syntax.060) als rechter Operand  VV
VV     und  einem linken Operanden vom Typ char/byte/short wird VV
VV     der  rechte Operand in den Typ des linken Operanden kon- VV
VV     vertiert,  wenn der konstante Ausdruck verlustfrei (ein- VV
VV     engend) im Typ der linken Seite darstellbar ist,         VV
VV     z.B. char c;c=33;                              // c=='#' VV
VV                                                              VV
VV # Berechnung des Ergebnisses (ist keine Variable):           VV
VV    Die Variable links wird bestimmt und ergibt Ergebnis-Typ. VV
VV    Der Wert des Ausdrucks rechts wird berechnet.             VV
VV    Der Variablen-Wert ist eine Kopie des Ausdrucks-Werts.    VV
VV    Der Ergebnis-Wert ist eine Kopie des Variablen-Werts.     VV
VV                                                              VV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV

  Das nachfolgende Programm Fibonaccci berechnet die Vermehrung von Individuen-Paaren in Zeitschritten von der Paar-Population alt zur Paar-Population neu aus den Start-Zuweisungen
                           alt=0;neu=1;
rekursiv bis zum größten Wert MAX_VALUE mit den Zuweisungen
                      neu=alt+neu;alt=neu-alt;
  Man beachte, dass nur zwei Variablen alt, neu benötigt werden. n dient nicht zur Indizierung, sondern nur zur Protokollierung der Zeitschritte. Wie das Ergebnis zeigt, vermehrt sich ein Paar in 46 Zeitsschritten, z.B. Kaninchen in 46 Monaten (ca. 4 Jahre), auf 1836311903 Paare. Die Berechnung der Vermehrung wird komplizierter, wenn man die Sterblichkeit mit berücksichtigt.
//************************ Fibonacci.java ************************
//  Fibonacci-Zahlen fuer die Vermehrung von (Kaninchen-) Paaren *
//        Leonardo Pisano (aus Pisa), Filius Bonacci, 13.Jh.     *
//    Regel 1: 1 Paar wird nach 1 Zeitschritt geschlechtsreif    *
//    Regel 2: 1 reifes Paar gebiert pro Zeitschritt 1 Paar      *
//  Daraus folgt fuer Paar-Populationen alt, neu die Rekursion   *
//     neu=alt+neu;alt=neu-alt; mit Startwerten alt=0;neu=1;     *
//****************************************************************

//            java.lang.                                 Object
import static java.lang.System .out;                   // |`System
import static java.lang.Integer.MAX_VALUE;             // `Integer

class Fibonacci
 {public static void main(String[] args)         // args ungenutzt
   {out.println("Zeit      Paare");  
    int          n=0,alt=0,neu=1;
    out.printf  ("%1$-10d%2$1d    Start alt\r\n",n++,alt);
    out.printf  ("%1$-10d%2$1d    Start neu\r\n",n++,neu);
    while       (neu<=MAX_VALUE-alt) // kein Ueberlauf bei alt+neu
     {           neu=alt+neu;      // Summe der Vorgaenger alt+neu
                 alt=neu-alt;           // neues alt ist altes neu
      out.printf("%1$-10d%2$-10d neu\r\n",n++,neu);
     }                                               
    out.println ("MAX_VALUE="+MAX_VALUE);
   }
 }

//****************************************************************


| Output
+------------------------
|Zeit      Paare
|0         0    Start alt
|1         1    Start neu
|2         1          neu
|3         2          neu
|4         3          neu
|5         5          neu
|6         8          neu
|7         13         neu
|...       ...        ...
|24        46368      neu
|25        75025      neu
|26        121393     neu
|...       ...        ...
|44        701408733  neu
|45        1134903170 neu
|46        1836311903 neu
|MAX_VALUE=2147483647

  Da es keine Fehlermeldungen für Überlauf bei der Ganzzahl-Arithmetik gibt (4.3), muss der drohende Überlauf bei neu=alt+neu; vom Programmierer im Kopf der while-Schleife vorher abgefangen werden.














5.2      Verzweigungen


  Bedingte Anweisungen, auch Verzweigungen genannt, bestehen aus einer "Bedingung" (hier ist nicht die Bedingung gemäß Syntax.056 gemeint) und verschiedenen Anweisungen, die dynamisch beim Erreichen der "Bedingung" ausgewählt werden. Eine Verzweigung kann je nach dem Typ ihrer "Bedingung" eine If-Anweisung (5.2.1) mit "logischer Bedingung" oder eine Switch-Anweisung (5.2.2) mit "ganzzahliger Bedingung" sein.


5.2.1    if-Verzweigung

  Eine If-Anweisung (IfStatement) ist nach ist nach Syntaxdiagramm 069 (für Statement, hier ein Auszug 069°) von der Form
069:IfStatement                  IfAnweisung
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
H            boolean or Boolean                                  H
H              ,----------,       ,---------,   -, Short-,       H
H -> if -> ( ->|Expression|-> ) ->|Statement|-,  |-If-   |       H
H              '----------'       '---------' | -' State-|       H
H                                 besser Block|    ment  | Long- H
H  ,------------------------------------------|          |-If-   H
H  |                              ,---------, v          | State-H
H  '-> else --------------------->|Statement|--->        | ment  H
H      belongs to left-next       '---------'           -'       H
H      else-free if               besser Block                   H
H                                                                H
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
                    ,--------------------------,
VVVVVVVVVVVVVVVVVVVV| if-Verzweigung (Prinzip) |VVVVVVVVVVVVVVVVVV
VV                  '--------------------------'                VV
VV # if-Langform mit else:                                      VV
VV    Je nachdem, ob der boolean bzw. Boolean Expression        VV
VV    true oder false ist,                                      VV
VV     wird der then-Block oder der else-Block durchlaufen,     VV
VV                                                              VV
VV     z.B. i=0; if(i>0)   {out.print("i>0" );}                 VV
VV               else      {out.print("i<=0");}        // i<=0  VV
VV                                                              VV
VV # if-Kurzform ohne else:                                     VV
VV    Je nachdem, ob der boolean bzw. Boolean Expression        VV
VV    true oder false ist,                                      VV
VV     wird der then-Block durchlaufen oder  übersprungen,      VV
VV                                                              VV
VV     z.B. i=0; if(i%8==0){out.println();}        // new line  VV
VV                                                              VV
VV # if-Schachtelung (leider gibt es kein endif):               VV
VV    Ein else mit seinem else-Block gehört                     VV
VV     jeweils zum links nächsten if ohne else,                 VV
VV                                                              VV
VV     z.B. i=0;if(1<2)if(3>4)if(5<6){i=7;}else{i=8;}else{i=9;} VV
VV                          out.print(i);                 // 9  VV
VV                                                              VV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV

  Nach Syntaxdiagramm Syntax.069 (siehe 5) kann ein Statement auch ein Block sein. Der Autor setzt in den Beispielen dieses Buchs stets einen then-Block und ggf. einen else-Block, um Blockstruktur zu erzeugen und "open-end-festival" zu vermeiden.
















5.2.2    switch-Verzweigung

  Eine Switch-Anweisung ist nach Syntaxdiagramm 069 (für Statement, hier ein Auszug 069°) von der Form
069: SwitchStatement             SwitchAnweisung
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
H                                                                H
H            Enum or IntegralNotLongType                         H
H            or IntegralNotLongClassType                         H
H                  ,------------,                                H
H -> switch -> ( ->| Expression |-> ) -,                         H
H                  '------------'      |                         H
H ,------------------------------------'                         H
H |   S     w     i     t     c     h     B    l    o   c   k    H
H |     ,---------------------------------------------,          H
H |     |           switch-                           |          H
H |     |           assignable                        |          H
H |     |           not null          ,-------------, |          H
H |     |          ,----------,       | ,---------, | |          H
H |     v no two   |Constant- |       | | Block-  | | |          H
H '-> { +> case -->|Expression|--> : -+>|Statement|-' | ,-> } -> H
H       |of same | '----------' |     | '---------'   | |        H
H       | value  |              |     |  e.g. break;  | |        H
H       |        | EnumConstant-|     |               | |        H
H       |        | ,----------, |     '---------------' |        H
H       |        '>|Identifier|-|                       |        H
H       |    one   '----------' |                       |        H
H       |> default -------------'                       |        H
H       |  at most                                      |        H
H       '-----------------------------------------------'        H
H                                                                H
H If code is not to fall through  Damit  das Programm nicht auch H
H subsequent  case  labels,  e.g  durch  die  nachfolgenden case H
H a   BreakStatement  should  be  Sprungziele läuft, sollte z.B. H
H used  as  the last BlockState-  eine BreakAnweisung als letzte H
H ment.                           BlockAnweisung gesetzt werden. H
H                                                                H
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

  z.B.
  import static java.lang.System.*;
  ...
  int tag=2;
  switch(tag)
   {case 0: out.print("Mo");break; case 1: out.print("Di");break;
    case 2: out.print("Mi");break; case 3: out.print("Do");break;
    case 4: out.print("Fr");break; case 5: out.print("Sa");break;
    case 6: out.print("So");break; default:out.print("??");break;
   } ...                                                    // Mi




,------------------------------, VVVVVVVVVVVVVVVVVV| switch-Verzweigung (Prinzip) |VVVVVVVVVVVVVVVV VV '------------------------------' VV VV VV VV # case-Auswahl: VV VV Je nachdem, mit welcher case-Auswahl der switch überein- VV VV stimmt, werden die Blockanweisungen nach dem betreffen- VV VV den case durchlaufen. Damit nicht auch die nachfolgenden VV VV case-Auswahlen durchlaufen werden,muss der Programmierer VV VV z.B. eine break-Anweisung (5.4.1) als letzte Blockanwei- VV VV sung setzen. Es dürfen nur solche case-Auswahlen vorkom- VV VV men, deren Typ dem Typ des switch zuweisbar ist (5.1). VV VV VV VV # default-Auswahl: VV VV Wenn keine case-Auswahl mit dem switch übereinstimmt, VV VV werden ggf. nur die Blockanweisungen der default-Auswahl VV VV durchlaufen. Es darf höchstens ein default im switch VV VV gesetzt werden. VV SS SS VV VV SS SS VV # keine Auswahl: VV VV Wenn keine case-Auswahl mit dem switch übereinstimmt VV VV und keine default-Auswahl gesetzt wurde, wirkt die VV VV switch-Anweisung wie eine leere Anweisung. VV VV VV VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
  Im folgenden Programm WochenTag wird der Wochentag aus dem Datum bestimmt. In christlicher Zeitrechrechnung ist der Tag mit der Nummer 1 der 1. Januar im Jahr 1, ein Montag. Man muss nur die Nummer des Datum-Tages in christlicher Zeitrechnung bestimmen, eine 1 subtrahieren und den Rest bei Division durch Wochenlänge 7 bestimmen. Das Ergebnis 0..6 entspricht den Wochentagen Mo..So . Bei der Bestimmung der Anzahl der Tage im Februar, 28 bzw. 29, und der Anzahl der Tage im Jahr, 365 bzw. 366, sind die Schaltjahr -Regeln zu beachten:
        j ist      Schaltjahr, wenn j durch   4 teilbar (Caesar),
   aber j ist kein Schaltjahr, wenn j durch 100 teilbar (Gregor),
   oder j ist doch Schaltjahr, wenn j durch 400 teilbar (Gregor).
   d.h.             j%4==0 && j%100!=0 || j%400==0
  Bei der switch-Anweisung
                   switch((gibZeitTag(t,m,j)-1)%7)
kann auf default-Setzung verzichtet werden, denn der Rest durch 7 liegt immer im Bereich 0 bis 6. Weil die Methode gibWochTag(int, int,int) mit Resultattyp String ein abschließendes return verlangt, setzen wir return "Sonntag"; ans Ende.

  Der Gregorianische Kalender gilt für die Jahre 1582 bis 3299. Vor 1582 galt der Julianische Kalender. Nach 3299 wird der tatsächliche Kalender vom Gregorianischen Kalender abeichen, d.h. der Sommer beginnt in den Winter zu wandern. Wir verweisen auch auf die Klasse GregorianCalendar im Paket java.util, die mit einigem Aufwand den Zugriff auf DAY_OF_WEEK ermöglicht.
//*********************** WochenTag.java *************************
//           Bestimmung des Wochentags aus dem Datum,            *
//           nach Gregorianischem Kalender 1582-3299.            *
//              Command: java WochenTag Tg Mo Jahr               *
//****************************************************************
//            java.lang.                                 Object
import static java.lang.System .out;                   // |`System
import static java.lang.Integer.parseInteger;          // `Integer

class WochenTag 
 {static final int //1  2  3  4  5  6  7  8  9 10 11 12     Monat:
       MLEN[][]={{0,31,28,31,30,31,30,31,31,30,31,30,31}, //normal
                 {0,31,29,31,30,31,30,31,31,30,31,30,31}};//schalt
  static int schalt(int j)                                  // 0,1
   {return          (j%4==0 && j%100!=0 || j%400==0 ? 1 : 0);}
  static int gibJahrTag(int t,int m,int j)              // 1..366
   {for(int          i=1;i<m;i++)
     {               t+=MLEN[schalt(j)][i];}
    return           t;
   }
  static int gibZeitTag(int t,int m,int j)           // 1..1204935
   {return           gibJahrTag(t,m,j--)+j*365+j/4-j/100+j/400;}
  static String gibWochTag(int t,int m,int j)          // Mo .. So
   {switch          ((gibZeitTag(t,m,j)-1)%7)
     {case 0: return "Montag"    ;
      case 1: return "Dienstag"  ;
      case 2: return "Mittwoch"  ;
      case 3: return "Donnerstag";
      case 4: return "Freitag"   ;
      case 5: return "Samstag"   ;
     }        return "Sonntag"   ;
   }
  public static void main(String[] args)//args[0]..args[2] genutzt         
   {int              t=parseInt(args[0]),
                     m=parseInt(args[1]),
                     j=parseInt(args[2]);
    out.print       ((schalt(j)==1?"":"kein ")+"Schaltjahr"+"\r\n"
                    +gibZeitTag(t,m,j)+"-ter Tag in Zeit"+"\r\n"
                    +gibJahrTag(t,m,j)+"-ter Tag im Jahr"+"\r\n"
                    +gibWochTag(t,m,j)+"\r\n");
 } }
//****************************************************************
| Command
+-------------------------
|java WochenTag 31 12 2007

| Output                          
+----------------------
|kein Schaltjahr 
|733041-ter Tag in Zeit
|365-ter Tag im Jahr   
|Montag     

5.3      Schleifen

  Eine Schleife (loop) mit vorangesetzter (pre) Prüfung (check) prüft jeweils vorher (precheck) , ob die Schleifen-Anweisung (action) noch einmal ausgeführt werden soll :
               ,--------------------------------,
               |   ,--------------------------, |
               |   |    _______               | |
               |   |   /       \   ,--------, | |
               | ->-->|  check  |->| action |-' |
               |       \_______/   '--------'   |
               |           |                    |
               |           v                    |
               '--------------------------------'
Fig. 5.3: precheck

  Die for-Schleife (5.3.1) und die while-Schleife (5.3.2) sind beide als precheck zu deuten, die do-Schleife (5.3.2) ist ein postcheck, d.h. der check wird erst nach der action durchgefürt. Einen incheck erhält man z.B. durch Setzen einer if-Verzweigung (5.2.1) mit Heraus-Sprung (5.4) zwischen zwei Aktionen action1/2.

5.3.1    for-Schleife
               ,----------------------------------,
VVVVVVVVVVVVVVV| for-Schleife (Zielvorstellungen) |VVVVVVVVVVVVVVV
VV             '----------------------------------'             VV
VV # so schnell wie möglich (vorberechnete Laufgrenze,Krement), VV
VV    schlecht:for(int i=0;i<max(0,3);i=i+1)                    VV
VV                                     out.print(i*i);   //014  VV
VV    effektiv:int m=max(0,3);                                  VV
VV             for(int i=0;i<m;i++)   {out.print(i*i);}  //014  VV
VV                                                              VV
VV # so lokal wie möglich (lokale Laufparameter, Block),        VV
VV    schlecht:int i=0;for(;i<3;)      out.print(i*i++); //014  VV
VV    effektiv:for(int i=0;i<3;i++)   {out.print(i*i);}  //014  VV
VV                                                              VV
VV # so übersichtlich wie möglich (trickfrei, Lauf erkennbar).  VV
VV    schlecht:for(those();who();like())trick17();    // empty  VV
VV         mit public static boolean those()   {return false;}  VV
VV             public static boolean who()     {return false;}  VV
VV             public static boolean like()    {return false;}  VV
VV             public static boolean trick17() {return false;}  VV
VV         mit int[] a={0,1,2};                          //014  VV
VV    schlecht:for(int i=0;i<a.length;)out.print(a[i]*a[i++]);  VV
VV    effektiv:for(int each:a)        {out.print(each*each);}   VV
VV                                                       //014  VV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV

  Eine for-Anweisung (ForStatement) ist nach Syntaxdiagramm 066 (für ForControl) und Syntaxdiagramm 069 (für Statement, hier zusammengefasst zu 069°) von der Form
069:ForStatement                 ForAnweisung
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
H                                                                H                        
H -> for -,                                                      H
H ,-------'                                                      H
H |      F   o   r   E   a   c   h  C  o  n  t  r  o  l          H
H |       ,---------------------,                                H
H |       |  ,----------------, |                                H
H |    ,->+->|VariableModifier|-'           ArrayType or         H
H |    |  |  '----------------'              ClassType           H                
H |    |  |                                 implementing         H                
H |    |  |              Iterator            Iterable            H
H |    |  | ,----,      ,----------,        ,----------,         H
H |    |  '>|Type|----->|Identifier|--> : ->|Expression|,        H
H |    |    '----'      '----------'        '----------'|        H
H |    |                                                |        H
H |    | B   a   s   i  c  F  o  r  C  o  n  t  r  o  l |        H
H |    | ,-------,      ,------------,      ,---------, |        H
H '> ( +>|ForInit|> ; ->|ForCondition|> ; ->|ForUpdate|-+-> ) -, H 
H      | '-------'      '------------'      '---------' |      | H
H      |                                                |      | H
H      | F  o   r   E   v  e   r   C   o  n  t  r  o  l |      | H
H      '----------> ; ----------------> ; --------------'      | H
H                                             ,----------------' H
H                                             |  ,-----------,   H
H                                             '->| Statement |-> H
H                                                '-----------'   H
H                                                 besser Block   H
H                                                                H
H Iterators  or variables decla-  In  der  ForKontrolle  verein- H
H red  in the ForControl are lo-  barte  Iteratoren oder Variab- H
H cal  to  the  right and in the  len  sind  lokal  nach  rechts H
H following Statement.            und  in  der nachfolgenden An- H
H                                 weisung.                       H
H Iterators or variables in nes-  Iteratoren  oder  Variablen in H
H ted   ForStatement(s)  must be  geschachtelten    ForAnweisung H
H different.                      (en)  müssen verschieden sein. H
H                                                                H
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

  z.B.             int[] a={0,1,2};

  ForEachControl:  for(int each:a)     {out.print(each);} // 012
  BasicForControl: for(int i=0;i<3;i++){out.print(a[i]);} // 012
  ForEverControl:  for(;;)             {out.print(  0 );} // 0...



  Die ForEachControl erlaubt nicht nur das Durchlaufen von Komponenten einer Reihung, sondern auch das Durchlaufen von Objekten, die in einer Klasse zusammengefasst sind, welche die Schnittstelle Iterable des Pakets java.lang implementiert. Wir verweisen auf die Klasse java.util.Vector im Beispiel Net (13.3.2). Der unendliche Lauf einer for-Schleife mit ForEverControl for(;;){...} kann z.B. mit einer if-Verzweigung (5.2.1) und Sprung (5.4) gestoppt werden.
     ,-----------------------------------------------------,
VVVVV| Gewöhnliche for-Schleife (BasicForControl, Prinzip) |VVVVVV
VV   '-----------------------------------------------------'    VV
VV                                                              VV
VV # ForInit (for-Initialisierung) nur einmal zu Anfang:        VV
VV    Wird ein Laufparameter lokal in der for-Schleife verein-  VV
VV    bart (siehe Syntax.066), dann darf global unter gleichem  VV
VV    Namen keine andere Größe vereinbart sein  (Einschränkung  VV
VV    der  Namensfreiheit 5.5.3).  Dem Laufparameter wird sein  VV
VV    Anfangswert  zugewiesen (siehe  Syntax.066).  Weiter mit  VV
VV    ForCondition.                                             VV
VV                                                              VV
VV # ForCondition (for-Bedingung) vor jedem Block-Durchgang:    VV
VV    Die  ForCondition  wird  ausgewertet (siehe Syntax.066),  VV
VV    bei  true  folgt  ein  neuer Block-Durchgang,  bei false  VV
VV    brichtdie Schleife ab.                                    VV
VV                                                              VV
VV # ForUpdate (for-Weiterzählung) nach jedem Block-Durchgang:  VV
VV    Das ForUpdate weist (siehe Syntax.066) dem Laufparameter  VV
VV    den nächsten Wert zu. Weiter mit ForCondition.            VV
VV                                                              VV
VV     z.B.  for(int i=0;i<3;i++){out.print(i+",");} // 0,1,2,  VV
VV                                                              VV
VV # InCheck (Abbruchprüfung aus dem for-Block heraus):         VV
VV    Schleifen  jeder  Art  können  aus dem Block heraus z.B.  VV
VV    durch if-Verzweigung (5.2.1) und Sprünge continue, break  VV
VV    (5.4.1),  exit, return,  assert  (5.4.2)  oder Auswerfen  VV
VV    throw (11.1.1) von Ausnahmen abgebrochen werden,          VV
VV                                                              VV
VV     z.B.  for(int i=0;i<10;i++)                              VV
VV            {out.print(i); if(i>=2){break;} out.print(",");}  VV
VV                                                    // 0,1,2  VV
VV                                                              VV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV

  Im folgenden Beispiel PrimZahl wird die größte int Primzahl bestimmt. Man könnte das Beispiel erweitern auf long Primzahlen oder mit BigInteger Zahlen aus dem Paket java.math rechnen, die in der Kryptographie beim Verfahren von Rivest, Shamir, Adleman verwendet werden.



  Zur Prüfung einer ganzen Zahl i>0 auf Primzahl-Eigenschaft untersucht man, ob i durch Divisoren div=2..(i-1) teilbar ist, d.h. i%div==0. Zur Beschleunigung des Verfahrens beschränkt man sich auf div=2 und sonst div ungerade.

  Auch braucht man nicht bis zu div=i-1 , sondern nur bis zu div=(int)sqrt(i) zu suchen:

  Gäbe es oberhalb der Wurzel aus i einen Teiler divOben, dann müsste es bereits unterhalb der Wurzel aus i einen Teiler divUnten geben mit divUnten*divOben=i.

  Die Methode sqrt(double) zum Ziehen der Quadratwurzel ist static vereinbart in der Klasse Math des Standard-Pakets java.lang.
//************************* PrimZahl.java ************************
// Prueft natuerliche (pos. ganze) Zahl auf Primzahl-Eigenschaft *
//            Command: java PrimZahl NatZahl                     *
//****************************************************************

//            java.lang.                                Object
import static java.lang.System .out;                  // ||`System
import static java.lang.Integer.parseInt;             // |`Integer
import static java.lang.Math   .sqrt;                 // `Math

class PrimZahl 
 {static boolean istPrim(int i)                             // i>0
   {if         (i!=2 && i%2==0)                    {return false;}
    if         (i<=7)                              {return true; }
    final int   SQRT=(int)sqrt(i);                         
    for(int     div=3;div<=SQRT;div+=2)
     if        (i%div==0)                          {return false;}
                                                    return true;
   }

  public static void main(String[] args)        // args[0] genutzt
   {out.println((istPrim(parseInt(args[0]))?"":"nicht ")+"prim");
   }
 }

//****************************************************************

| Command                                        Kommentar:
+------------------------
|java PrimZahl 2147483647                        Integer.MAX_VALUE

| Output
+-------
|prim                                            ist eine Primzahl



5.3.2    while-Schleife, do-Schleife

  Eine while-Anweisung (WhileStatement) ist nach Syntaxdiagramm 069 (für Statement, hier ein Auszug 069°) von der Form
069°:WhileStatement               WhileAnweisung
     HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
     H                                                      H
     H               boolean or Boolean                     H
     H                 ,------------,       ,-----------,   H
     H -> while -> ( ->| Expression |-> ) ->| Statement |-> H
     H                 '------------'       '-----------'   H
     H                                       besser Block   H                        
     H                                                      H                        
     HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

       z.B.  int i=0; while(i<3){out.print(i);i++;}  // 012
  Die while-Schleife entspricht einer for-Schleife (5.3.1) mit ForEverControl und Prüfung vor ihrem Statement (precheck):
           for(;;) { if(!Expression){break;} Statement }
d.h. solange der Expression den Wert true ergibt, wird das Statement wiederholt.

  Eine do-Anweisung (DoStatement) ist nach Syntaxdiagramm 069 (für Statement, hier ein Auszug 069°) von der Form
069°:DoStatement                  DoAnweisung
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
H                                   boolean or Boolean          H
H         ,-----------,                ,----------,             H
H -> do ->| Statement |-> while -> ( ->|Expression|-> ) -> ; -> H
H         '-----------'                '----------'             H
H          ggf. Block                                           H                        
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

     z.B.  int i=0; do{out.print(i);i++;}while(i<3);  // 012
  Die do-Schleife entspricht einer for-Schleife (5.3.1) mit ForEverControl und postcheck am Ende ihrer BlockStatements:
        for(;;) { BlockStatements if(!Expression){break;} }
d.h. die BlockStatements werden einmal (ungeprüft) ausgeführt und danach solange (while) wiederholt, wie der Expression den Wert true ergibt.
  while-Schleifen und do-Schleifen sind geeignet für die Abfrage von Ereignissen, die nicht durch einen Parameterlauf, wie in for -Schleifen, bestimmt werden, z.B. Einlesen einer Datei bis zum Datei-Ende (8.2)
              int chr; while((chr=inread())!=-1){...}



5.4      Strukturierte Sprünge


  Bereits 1960 warnte Dijkstra: 'goto considered harmful', aber es sollte mehr als 30 Jahre dauern, bis Java als erste Programmiersprache auf goto-Sprünge verzichten konnte.

  An die Stelle expliziter Sprünge (Spaghetti-Programme) treten strukturierte Sprünge.

  Gesprungen werden kann nur aus einem switch-Block oder aus einer Schleife. Anspringbare Marken (label) können nur vor einer Schleife stehen,
  z.B. loop:for(int a=1;a<10;a++)
             for(int b=1;b<10;b++)
              for(int c=1;c<10;c++)
         check:if(a*a+b*b==c*c)
                {out.print(a+" "+b+" "+c);break loop;} // 3 4 5
  Nicht anspringbare Marken, wie z.B. check: im obigen Beispiel, können als Kommentar dienen.










5.4.1    break, continue, ggf. labeled

  Eine break-Anweisung (BreakStatement) oder eine continue-Anweisung (ContinueStatement) ist nach Syntaxdiagramm 069 (für Statement, hier ein Auszug 069°) von der Form
069°:BreakOrContinueStatement     BreakOderContinueAnweisung
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
H                                                                H                        
H ->--> break ------,                          -,                H       
H   |   for,while,do|    surrounding            |- Break-        H       
H   |   switch      |    label-                 |   Statement    H
H   |               |  ,------------,           | -,             H
H   '-> continue ---+->| Identifier |-,         |  |- Continue-  H
H       for,while,do|  '------------' |         |  |   Statement H
H                   '-------------------> ; -> -' -'             H
H                                                                H                        
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

                 ,------------------------------,
VVVVVVVVVVVVVVVVV| break und continue (Prinzip) |VVVVVVVVVVVVVVVVV
VV               '------------------------------'               VV
VV # break                                                      VV
VV                                                              VV
VV    ohne Label in einer Schleife oder einem switch zulässig,  VV
VV     springt  über  den  Rest  der  Schleife bzw. des switch  VV
VV     zum Abbruch (ohne Bedingung),                            VV
VV      z.B. for(int i=0;i<3;i++)                               VV
VV            {if(i%2!=0){out.print(i);break;}}           // 1  VV
VV                                                              VV
VV    mit Label in einer Schleife zulässig,                     VV
VV     springt  über  den Rest aller inneren Schleifen zum Ab-  VV
VV     bruch (ohne Bedingung) der äußeren umgebenden Schleife,  VV
VV     die mit diesem Label markiert ist,                       VV
VV      z.B. loop:for(int a=1;a<10;a++)                         VV
VV                 for(int b=1;b<10;b++)                        VV
VV                  for(int c=1;c<10;c++)                       VV
VV                   if(a*a+b*b==c*c)                           VV
VV           {out.println(a+" "+b+" "+c);break loop;} // 3 4 5  VV
VV                                                              VV
VV # continue                                                   VV
VV                                                              VV
VV    ohne Label in einer Schleife zulässig,                    VV
VV     springt über den Rest der Schleife zur Bedingung dieser  VV
VV     Schleife, bei for-Schleife zunächst zum Update,          VV
VV      z.B. for(int i=0;i<3;i++)                               VV
VV            {if(i%2!=0){continue;};out.print(i);}      // 02  VV
VV                                                              VV
VV    mit Label in einer Schleife zulässig,                     VV
VV     springt  über  den  Rest  aller  inneren  Schleifen zur  VV
VV     Bedingung der äußeren umgebenden Schleife, die mit die-  VV
VV     sem  Label markiert ist,  bei for-Schleife zunächst zum  VV
VV     Update,                                                  VV
VV      z.B. loop:for(int i=0;i<3;i++)                          VV
VV                 for(int j=0;j<3;j++)                         VV
VV           {if(i==j){continue loop;};out.print(i+""+j+",");}  VV
VV                                                // 10,20,21,  VV
VV                                                              VV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV

  Es ist nicht möglich, aus einem switch-Block heraus mit break an das Abbruch-Ende eines umgebenden Blocks zu springen. Der switch -block (5.2.2, Syntax.069) benötigt selbst den break zum Ausbrechen aus seiner case-Folge.






5.4.2    exit, return, assert

  Die Methode exit(int) der Klasse System kann in Anlehnung an C -Konventionen mit Parameter 0 (in C status 'normal termination') oder Parameter ungleich 0 (in C status 'abnormal termination') aufgerufen werden, terminiert jedoch in Java niemals normal und kann SecurityException werfen, wenn ein SecurityManager existiert, dessen checkExit Methode den exit-Aufruf mit dem spezifizierten Status nicht erlaubt.
  z.B. if(args.length!=2)          // vergleiche UmsatzSteuer 3.1  
        {out.println("java UmsatzSteuer USt umsatz");exit(1);}  
  Eine return-Anweisung (ReturnStatement) ist nach Syntaxdiagramm 069 (für Statement, hier ein Auszug 069°) von der Form
069°:ReturnStatement              ReturnAnweisung              
          HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
          H                     Type                  H
          H                   ,------------,          H
          H -> return ------->| Expression |-,        H
          H    from method |  '------------' |        H
          H                |                 |        H
          H                |    void         |        H
          H                '---------------->--> ; -> H
          HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
  Das englische Wort 'return' beschreibt in seiner Zweideutigkeit "zurückkehren" (return from London) und "zurückbringen" (return to sender) die zwei Bedeutungen der return-Anweisung:
                        ,------------------,
VVVVVVVVVVVVVVVVVVVVVVVV| return (Prinzip) |VVVVVVVVVVVVVVVVVVVVVV
VV                      '------------------'                    VV
VV                                                              VV
VV # allgemein bei allen Methoden (void or nonvoid method)      VV
VV    Rücksprung zum Methoden-Aufruf (MethodInvocation),        VV
VV     z.B. if(args.length!=2)       // siehe UmsatzSteuer 3.1  VV
VV       {out.println("java UmsatzSteuer USt umsatz");return;}  VV
VV                                                              VV
VV # zusätzlich speziell bei Funktionen (nonvoid method)        VV
VV    Vor dem Rücksprung Kopie des Funktionswerts (Expression,  VV
VV    siehe Syntax oben)  auf den Methoden-Aufruf (MethodInvo-  VV
VV    cation),                                                  VV
VV     z.B. static double hebSteuer  // siehe UmsatzSteuer 3.1  VV
VV           (final double prozent,final double betrag)         VV
VV             {return prozent*betrag/100.0;}                   VV
VV                                                              VV
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
  Die return-Anweisung kann als BlockStatement an jeder Stelle der Folge der Blockstatements eines Methoden-Rumpfs (Syntax.083) gesetzt werden, auch in der Methode main(String[]) als normaler Abbruch an Stelle eines abnormalen Abbruchs mit exit(1).


  Eine assert-Anweisung (AssertStatement) ist nach Syntaxdiagramm 069 (für Statement, hier ein Auszug 069°) von der Form
069°:AssertStatement              AssertAnweisung              
      HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
      H                                                 H
      H  loader of top-level  boolean or Boolean        H
      H    enables/disables     ,------------,          H
      H -------> assert ------->| Expression |-,        H
      H                         '------------' |        H
      H                       if false: throws |        H
      H                        AssertionError  |        H
      H                                        |        H
      H                 ,----------------------|        H
      H                 |                      |        H
      H                 |         non void     |        H
      H                 |       ,------------, v        H
      H                 '-> : ->| Expression |---> ; -> H
      H                         '------------'          H
      H                          converted to           H
      H                     String detail message       H
      H                       of AssertionError         H
      H                                                 H                        
      HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

  Auch eine assert-Anweisung kann als normaler Abbruch an Stelle

  eines abnormalen Abbruchs mit exit(1) gesetzt werden,
  z.B. assert(args.length==2):"java UmsatzSteuer USt umsatz";
                                   // vergleiche UmsatzSteuer 3.1
  Allerdings kann ein Programm mit assert ("absichern") nicht wie gewohnt mit dem Kommando javac übersetzt werden, dann wird '1 error, 1 warning' gemeldet, sondern verlangt die Option 'source 1.n' mit n>=4, die auf die Installation von Java in Version 1.4 oder höher hinweist:
                  java -source 1.5 AssertTest.java
  Ausserdem kann ein so übersetztes Programm nicht wie gewohnt mit dem Kommando java gestartet werden, dann ist assert nicht aktiviert, sondern verlangt eine Option 'ea' (enable assert), die assert aktiviert:
                       javac -ea AssertTest
  Vorteile bieten assert-Anweisungen bei der Fehlersuche (debugging) in neu zu erstellenden oder weiter zu entwickelnden Programmen.




5.5      Bereichsschachtelung


  Java gehört als ALGOL-Familienmitglied zu den blockstrukturierten Programmiersprachen. Die Blockschachtelung von ALGOL ist im Laufe der Entwicklung der Programmiersprachen erweitert worden zur Bereichsschachtelung. Ein Bereich (englisch region oder space) kann im einzelnen sein:

             # Block (3, Syntax.068),

             # Methode / Konstuktor (7, Syntax.083 / Syntax.089),

             # Klasse / Schnittstelle (9, Syntax.101),

             # Paket (9, Syntax.102),

             # Übersetzungseinheit (9, Syntax.104).

Bereiche können ineinander verschachtelt (nested) sein
             ,--------------------------------,
             | A                              |
             |      ist B übergeordnet        |
             |  ,--------------------------,  |
             |  | B                        |  |
             |  |   ist A untergeordnet    |  |
             |  '--------------------------'  |
             |                                |
             '--------------------------------'
bzw. nicht ineinander verschachtelt sein
             ,--------------------------------,
             |                                |
             |  ,--------------------------,  |
             |  | A                        |  |
             |  |   ist B parallelgeordnet |  |
             |  '--------------------------'  |
             |  ,--------------------------,  |
             |  | B                        |  |
             |  |   ist A parallelgeordnet |  |
             |  '--------------------------'  |
             |                                |
             '--------------------------------'

5.5.1    vereinbart / sichtbar

  Der innerste Bereich, in dem die Vereinbarung einer Größe unmittelbar vorkommt, ist dieser Größe als ihr "Vereinbarungsbereich" (declarative region or namespace) zugeordnet. In ihrem Vereinbarungsbereich heißt eine Größe "vereinbart".
  Die interne Belegung von Speicher für Bereichs-Größen erfolgt dynamisch konsekutiv zur Laufzeit bei der Vereinbarung der Größe, ausgenommen non-static Klassen, die erst bei Vereinbarung eines Objekts dieser Klasse Speicher belegen und non-final / non-static Mitglieder von Schnittstellen, die erst bei Implementaion der Schnittstelle Speicher belegen. Beim Verlassen des Vereinbarungsbereichs wird der gesamte Speicher-Keller aller in diesem Vereinbarungsbereich vereinbarten Größen wieder freigegeben.

  Der Name "Keller" (englisch stack) soll an einen Kellerschacht erinnern, in dem das zuerst gespeicherte Objekt unten liegt und das zuletzt gespeicherte Objekt oben als erstes wieder zugreifbar ist ("first in, last out").

         ,-----------------------------------------------,
     VVVV| Bereichsschachtelung spart Speicher (Prinzip) |VVVV
     VV  '-----------------------------------------------'  VV
     VV                                                     VV
     VV           Eine nicht mehr vereinbarte Größe         VV
     VV         verliert ihren Namen  und ihren Wert.       VV
     VV         Ihr Speicher wird wieder freigegeben.       VV
     VV                                                     VV
     VV                                                     VV
     VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV

  Einer Bereichs-Größe, die in einem Block oder in einer Methode/ Konstruktor vereinbart ist, wird der Teil ihres Vereinbarungsbereichs, der nach ihrer Vereinbarung liegt, als ihr "Sichtbarkeitsbereich" (scope) zugeordnet. In ihrem Sichtbarkeitsbereich heißt eine Größe "sichtbar". Nur dort ist sie im Programmtext verfügbar (available).

  Einer Bereichs-Größe, die in einer Klasse / Schnittstelle oder in einem Paket vereinbart ist, wird ihr gesamter Vereinbarungsbereich als Sichtbarkeitsbereich zugeordnet, d.h. man benötigt keine forward (Pascal) oder prototype (C, C++) Vereinbarungen in Java. Nur in Variablen-Initialisierern (Syntax.063) von Datenfeld-Verein- barungen (Syntax.073) dürfen derartige Größen erst nach ihrer Ver- einbarung verwendet werden.


  Neben Bereichs-Größen gibt es new-Größen, d.h. mit new erzeugte Objekte, auf die Referentyp-Größen (6, 8, Typ Syntax.030) verweisen. Diese new-Objekte werden in einem nicht an den Bereich ihrer Erzeugung gebundenen zentralen Halden-Speicher gehalten und sind bis zum Ende des Programmlaufs "unsterblich", sofern sie nicht von der automatischen Speicherbereinigung (garbage collection) eliminiert werden, wenn festgestellt wird, dass keine Referenz (Zeiger) mehr auf das new-Objekt verweist. Die Zeiger selbst sind "sterbliche" Bereichs-Größen.

  Der Name "Halde" (englisch heap) soll an eine Sand-Halde erinnern, die bei Entnahme von Sand aus der Halde an beliebiger Stelle wieder lückenlos zu einer neuen Sand-Halde zusammenfließt.



5.5.2    lokal / global / verdeckt

  Ein "Lokalbereich" (local decalarative region) entsteht aus einem Vereinbarungsbereich (5.5.1) durch Ausschluß aller ihm untergeordneten Bereiche. In ihrem Lokalbereich heißt eine Größe "lokal". In einem Lokalbereich dürfen nicht zwei verschiedene Größen gleichen Namens lokal sein,
   z.B. inkorrekt   int inkorrekt;double inkorrekt; 
ausgenommen Überladen (7.3) von Methoden-Namen, z.B. println(),
   z.B. korrekt     int    i=1   ;out.println(i);       // 1
                    double x=3.14;out.println(x);       // 3.14
  Auch Überladen von Namen durch Unterscheidung nach Variable, Datenfeld, Methode, Klasse/Schnittstelle oder Paket (8.3) ist möglich, sollte aber gemäß Namenskonventionen (1.3.3) vermieden werden.

  Marken (label) sind keine Größen im Sinne dieses Abschnitts, sondern mit Kommentar vergleichbar. Bei strukturierten Sprüngen (5.4) hat nur das innerste umgebende von mehreren gleichnamigen Sprungzielen Bedeutung.

  Eine Bereichs-Größe heißt "global" in jedem untergeordneten Be- reich ihres Vereinbarungsbereichs,
   z.B.  class Klasse  
          {int global=2;     // global ist "global" in method()
           void method()
            {double local=3.14;out.print(local*global); // 6.28
            }
          }
  Eine globale Größe heißt "verdeckt" (hidden) in einem untergeordneten Bereich ihres Vereinbarungsbereichs, wenn sie dort sichtbar wäre, aber dort eine Größe gleichen Namens lokal vereinbart ist. Der Name der verdeckten Größe ist in diesem untergeordneten Bereich nicht zugänglich. Statt dessen ist der gleichlautende Name der sie verdeckenden Größe zugänglich. Name und Wert der verdeckten Größe bleiben erhalten und sind wieder verfügbar, wenn der dynamische Fluß des Programms den Unterbereich verläßt, in dem die Größe verdeckt war.
         ,----------------------------------------------,
    VVVVV| Bereichsschachtelung schützt Namen (Prinzip) |VVVVV
    VV   '----------------------------------------------'   VV
    VV                                                      VV
    VV  Eine (vorübergehend) verdeckte Größe behält ihren   VV
    VV während der Verdeckung unzugänglichen Namen und Wert.VV
    VV                                                      VV
    VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
  Jede verdeckte Größe ist global, aber nicht jede globale Größe ist verdeckt.
  Die Verdeckung einer Größe kann durch zusätzliche Qualifikation des Namens der Größe, d.h. durch Auflösung der Namens-Mehrdeutigkeiten (scope resolution), wieder aufgehoben werden,
 z.B. class Klasse
       {       int i;    // i global verdeckt im Konstruktor 
        Klasse(int i)    // i lokal im Konstruktor
           {this.i=i;}   // i sichtbar, this.i sichtbar
       }




5.5.3    Einschränkung der Namensfreiheit

  Während man in ALGOL noch Wert darauf legte, durch Blockschachtelung den gleichen Namen in inneren Blöcken wieder neu verwenden zu können ("Namensfreiheit"), wird dies in modularen Programmiersprachen wegen der Vielfalt der Namen nicht mehr als erstrebenswert angesehen ('name confusion considered harmful') und deshalb eingeschränkt:
          ,--------------------------------------------,
   VVVVVVV| Einschränkung der Namensfreiheit (Prinzip) |VVVVVVV
   VV     '--------------------------------------------'     VV
   VV                                                        VV
   VV  # Bereichs-Größen in einem übergeordneten Block,      VV
   VV  # Type-Parameter  in einem übergeordneten ForBlock    VV
   VV  # und  Parameter  in einem übergeordneten CatchBlock  VV
   VV       können nicht verdeckt werden, d.h. es muss       VV
   VV         lokal ein anderer Name gewählt werden.         VV
   VV                                                        VV
   VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV

 z.B. class AnotherName 
       {public static void main(String[] args) // args ungenutzt
         {     int x=0;                  // übergeordneter Block
          for( int xfor=0;xfor<10;xfor++)            // ForBlock
           {try{if(xfor==5){throw new RuntimeException("");}}
            catch(RuntimeException xcatch)         // CatchBlock
             {{int xlocal=5;out.print(xlocal);}}            // 5
           }
         }
       }      // x, xfor, xcatch, xlocal sind verschiedene Namen





5.6      Testfragen

zu    Frage                                  | abdeckbare Antwort
---------------------------------------------+--------------------
                                             |
5.1      Kann  im  AssignmentStatement  L=E; | ja, z.B. i=j=4; von
      E wieder ein AssignmentExpression sein?| rechts abgearbeitet
                                             |
5.1      Welche Werte haben a,b ?            |
                                             | a hat den Wert 'a'
      a='b';b=a;a='a';                       | b hat den Wert 'b'
                                             |
         Welche  der folgenden sind korrekte |
      Anweisungen?                           |
                                             |
4.2.5              sign=(x<0?-1:(x==0?0:1)); | beide
                                             |
5.2.1    if(x< 0) {sign=-1;} else            |
         if(x==0) {sign= 0;} else {sign=1;}  |
                                             |
5.2.1    Bestimme den Wert von i in          |                                                     |
                                             |
      i=0;if(1<2){}else if(3<4){}else{i=5}   | i==0
                                             |
      i=0;if(1>2){}else if(3>4){}else{i=5}   | i==5
                                             |
5.3      Was wird ausgedruckt?               |
                                             |
      for(int i=1;i<3;i++)                   |
       while(i%2!=0){out.print(i);}          | 111...
                                             |
      i=1;while(i%2!=0)                      |
           for(;;){out.print(i++);}          | 123...
                                             |
5.3.1    Berechne mit einer for-Schleife die | 
      Näherungssumme für e:                  |
                                             | double e=1.0;
               1     1           1           | long fak=1;
      e = 1 + --- + --- + ... + --- + ...    | for(int   
               1!    2!         12!          |     i=1;i<13;i++)
                                             |  {e+=1.0/(fak*=i);}
                                             |
5.4      Kann man mit break; aus einer Metho-| nein,  eine Methode
      de herausspringen?                     |  ist  kein  switch-        
                                             |  Block und keine
                                             |  Schleife
                                             |
5.5      Können folgende Bereiche direkt (!) |
      ineinander geschachtelt sein?          |
                                             |
      Block   in Block                       | alle
      Klasse  in Klasse                      |
      Paket   in Paket                       |
                                             |
      Methode in Methode                     | keine
      Methode in Block                       |     
                                             |
5.5    Wo z.B. können aufeinanderfolgen?     |  
                                             | zulässig:
      {{                                     |  Block im Block 
      }}                                     |  Block im Block 
      {}                                     |  leerer Block
      ;;                                     |  freie for-Schleife
      ;}                                     |  Anweisung im Block
                                             | nicht empfohlen:
      {;                                     |  leere Anweisung 
      };                                     |  Anweisung mit };
                                             |
5.5.2    Sind Type Parameter von for-Schlei- | ja
      fen  lokal im ForInit/Condition/Update |
      und im Block der for-Schleife?         |
                                             |
5.5.2    Überschreibt  die verdeckende Größe |
      den Wert der von ihr verdeckten Größe? | nein
                                             |
5.5.3    Welche  der folgenden sind korrekte |
      Bereiche?                              |
                                             |
      {int i=1;{int i=1;out.print(i);}}      | keiner
                                             |
      for(int i=1;i<2;i++)                   |
       {{int i=1;out.print(i);}}             |
                                             |
      try{throw RuntimeException("");}       |
       catch(RuntimeException i)             |
        {{int i=1;out.print(i);}}            |
                                             |
      void method(int i)                     |
       {{int i=1;out.print(i);}}             |
                                             |
                                             |
      class C{C(int i){this.i=i}int i;}      | korrekt
                                             |
    Java Progammierung
  Kap.06