Flow control

Break and Continue

  
  • break and continue are designed to stop either the entire loop (break) or just the current iteration (continue).

continue
  
  • must be inside the loop
  • causes the current iteration of the inner most loop to cease and the next to start

break
  • A break without a label breaks the current loop. No more iterations.


Labeled Statements

  
  • normally used with loops, but not always
  • often used with break and continue
  • the label is placed just before the statement it labels and ends with a colon. eg. LABEL:.

break label;
  
  • can ONLY be used to label a loop or a block. If used to label a statement the code will not compile.
  • the flow will exit out of the loop labeled by the label in the break statement.
  • if this happens within a try…catch then the control will go to the finally statement.

continue label;
  
  • the flow will continue with the next interation of the loop labeled in the continue statement.


Switch


Format:

             switch (x){
                   case 1:
                        System. out .println(x);
                         break ;
                   case 2:
                        System. out .println(x);
                         break ;
                   default :
                        System. out .println(x);
                         break ;
            }
 


The switch argument:
  • Must be a value that can become an int implicitly:
    • byte, short, char, int;
    • Byte, Short, Character, Integer;
    • an enum.
  • Can be:
    • a variable reference,
    • a method call that returns a legal type,
    • an enum.
  • Cannot be:
    • boolean, long, float or double
    • Boolean, Long, Float or Double

The case constant:
  • must be a compile time constant
    • a constant variable,
    • a final variable,
    • an enum.
  • Must evaluate to the same type as the switch argument type.

Example with enums:

       public enum Day { SUNDAY, MONDAY , TUESDAY , WEDNESDAY}

       Day d = Day.MONDAY;

       switch (d){
             case MONDAY :
                  System. out .println(x);
                   break ;
             case TUESDAY :
                  System. out .println(x);
                   break ;
             default :
                  System. out .println(x);
                   break ;
      }
 


Example: where the switch argument is an int and the case argument are capable of implicitly becoming and int.

             final char a = ‘a’;
             final char b = 1;
             final char c = ‘\u9874’;

             int x = 1;

             switch (x){
                   case a:           System. out.println( “1” ); break ;
                   case 1:           System. out.println( “1” ); break ;
                   case ‘\u9874’ :    System. out.println( “1” ); break ;
            }
 


Example: where the switch arguement is generated by a for loop:
  
 

  public static void main(String args[])
   {
      for ( int i = 0 ; i < 3 ; i++)
      {           
         switch (i)
         {
         case 0: System. out.println(i); break;
         case 1: System. out.println(i); break;
         case 2: System. out.println(i); break;
         }
      }
   }
 

Example of the use of a post increment in the switch clause.
  

   public static void main(String args[])
    {
        int i;
        LOOP: for (i=0; i<5;i ++)
        {
            switch (i++)
            {
                case ‘0’ : System. out.println( “A” );
                case 1: System. out.println( “B”); break LOOP;
                case 2: System. out.println( “C”); break ;
                case 3: System. out.println( “D”); break ;
                case 4: System. out.println( “E”);
                case ‘E’ : System. out.println( “F” );
            }
        }
    }
  
  1. the value of i used in the switch statement is 0,
  2. there is no case 0,
  3. the value of i is inceased by 1 (i=1),
  4. and the next loop of the for is executed, the for inceases the loop by 1 (i=2)
  5. the switch uses value of i = 2, and selects case 2.
  6. the value of i is increased by 1 (i=3) and the value 3 is printed,
  7. and the next loop of the for is executed, the for inceases the loop by 1 (i=4)
  8. the switch uses value of i = 4, and selects case 4.
  9. the value of i is increased by 1 (i=5) and the value 5 is printed,
  10. the loop finishes

The value of i is used to select the case before it is increased.
 




Illegal:
  • Duplicate cases:
    • final char a = ‘a’;
    • and two cases
      • case a:
      • case 97:
    • These are duplicated cases, because their integer value is the same.
  • Cases larger than the switch argument:
    • A switch argument of type byte and a case argument of 128,
    • 128 is larger than the maximum number allowed in a byte.

The default:
  • only one allowed
  • can be placed anywhere
  • does not have an argument
  • acts just like a case statement

Example of valid switch statements:
  
switch (1) { default : break; }
An empty switch block is a valid construct
 

NOTE: A variable defined within a switch statement has scope through out the block:
  
 

      switch(0)  
       {
           case 0 :
               boolean b = false; //1
               break;
    
           case 1 :
               b = true;  //2
               break;
       }

b is defined at line 1 and used after at line 2, this is not out of scope because it is within the {}. However b MUST be defined before it is used -> normal rules.
 

If statements


The if condition must evaluate to a boolean. If it evalutes to a number or String it will error.

Unusual loop/conditional constructions that ARE valid.

             for (int x = 0; x<5; x++)
                   if (true )
            System. out .println(x);

TODO: what is the output of this….
 
if (8 == 81) {}
if (true) {}
if (bool = false) {}  //assume that bool is declared as a boolean
if (x == 10 ? true:false) { } // assume that x is an int


Unusual loop/conditional constructions that ARE NOT valid.

if (true) { break ; }

Cannot have break or continue in an ‘if’ or ‘else’ block.
 

if (x = 3) {} // assume that x is an int

Because the exp. x = 3 does not return a boolean.

The ternary statement


result = testCondition ? value1 : value2
                                                       ^                  ^
                                                     true             false

The ternary statement cannot have void operator as the second and third:

System.out.println( i<20 ? out1() : out2() );
Assume that out1 and out2 have method signature: public void out1(); and public void out2();

This code snippet will not compile.

Type of the operation is ‘highest’ type of the second and third operands.

For loops


for (initialization; termination; increment) {
    statement(s)
}
  • initialization : initializes the loop;  executes once at the beginning.
  • when termination expression evaluates to false, the loop terminates.
  • increment : is invoked after each iteration through the loop.

The order of execution:
  
  1. the variable is initialized then
  2. it is checked to see if the expression is true,
  3. if true the statements are executed,
  4. then the variable is incremented,
  5. then expression is tested,
  6. if true the statements are executed…

[initialized, tested, executed, incremented, tested, executed, incremented…]


  

      for(int x=0; x<5; x++)
       for (int x=0; x<5; ++x)
 
0 to 4

Using a post- or pre-increment does not affect the number of loops.

      for(int x=0; x<=5; x++)
 

0 to 5, using = includes the number.

       for (int x=5; x>0; x–)
 

5 to 1, using < or > excludes the number.
 
 


  
Invalid
      

for (int x = 0, int z = 0 ; x < 10; x++){}

Cannot declare a second variable inside a for loop initialisation.        
Correct

for (int x = 0, z = 0 ; x < 10; x++){}

But you can initialise another variable.
 


Loops/conditions without braces:

Unusual loop/conditional constructions that ARE valid.
  

if (j == 1) break;
 

if (j == 1) break foreach;
 
      

if (true );
 

if (true );
else if ( false);
else ;
 

for (int x = 0; x<5; x++)
      System. out .println(x);
 

for (int x = 0; x<5; x++)
                  
      System. out .println(x);

NOTE: the space between the two lines does not cause an error.

for (int x = 0; x<5; x++)
       // comments here
      System. out .println(x);
 

for (int x = 0; x<5; x++)
       for (int y = 0; y<5; y++)
             for (int z = 0; z<5; z++)
                  System. out .println(x);
 


Unusual loop/conditional constructions that ARE NOT valid.
  

       for (int x = 0; x<5; x++)
            System. out .println(x);
      System. out .println(x); // out of scope error
 

for (int x = 0; x<5; x++)
       for (int y = 0; y<5; y++)
             for (int z = 0; z<5; z++)
            
There must be a line of code that is executed after the last for statment.
 

       for (int x = 0; x<5; x++)
             for (int y = 0; y<5; y++)
                   for (int z = 0; z<5; z++)
                        System. out .println(z);
            System. out .println(y); // out of scope
      System. out .println(x); // out of scope
 

       for (int i = 0; i < 3; i++)
            System. out .println(“i = “ +i);
             for (int j = 0; j < 3; j++)
                  System. out .println(“j = “ + j);
                  System. out .println(“j = “ + j); // out of scope
                   for (int k = 0; k < 3; k++)
                        
                        System. out .println(“k = “ + k);
            System. out .println(k);   // out of scope

In nested loops without braces there must be one line of code and optionally a for statement. If there are two or more lines of code then we have compile time problems.
 

if (true) { break ; }
Cannot have break or continue in an ‘if’ or ‘else’ block.
 

if();

if (true ) else; // Else is not a valid statement
 

            
Infinate loops:
The first two loops continue without stopping because the test condition is true. NOTE: any code after either of these two for loops will not be reachable and therefor will not compile.
  

       for (int x=0;;x++){
            System. out .println(x);
      }
 

       for (int y=0; true ;y++){
            System. out .println(y);
      }
 

    for ( ; ; ) {
         // your code goes here
    }
 

       for ( ; true ; ) break ;
 

Loops that cause Unreachable code errors: 
The last loop does not compile because of “unreachable code”. The line System.out.println(y); can never be executed because the test condition is always false.
      

             for (int y=0; false ;y++){
                  System. out .println(y);
            }
 

            while (false) { x=3; }
 

            for( int i = 0; false; i++) x = 3;
 
      
NOTE THIS EXCEPTION:

if(false){ x=3; } this code does not cause an unreachable code error.

In if(false){ x=3; }, although the body of the condition is unreachable, this is not an error because the JLS explicitly defines this as an exception to the rule. It allows this construct to support optimizations through the conditional compilation. For example,

if(DEBUG){ System.out.println(“beginning task 1”); }

Here, the DEBUG variable can be set to false in the code while generating the production version of the class file, which will allow the compiler to optimize the code by removing the whole if statement entirely from the class file.


      

For loops and method calls/Wrapper objects

Method calls can be used instead of literals comparisons:
  

public class ForLoopsMethodCalls {
       public static void main(String [] arg){         
             for (int x = intValue(); test(x); x = go (x)){
                  System. out .println(x);
            }                 
      }
      
       public static Boolean test( int x){
             return new Boolean(x < 10);         
      }
      
       public static int intValue(){
             return 0;
      }
      
       public static int go( int x){
             return ++x;
      }           
}
 

Wrapper objects can be used where literals are used:
  

public class ForLoopsWrapperClasses {
       public static void main(String [] arg){         
             for (int x = Integer.valueOf (10); test(x); x = go(x)){
                  System. out .println(x);
            }           
      }
      
       public static Boolean test( int x){
             return new Boolean(x < 10);         
      }
      
       public static Integer go( int x){
             return new Integer(3);
      }                 
}
 

Assertions

Assertions were introduced in java 1.4.

Type 1: assert <boolean_expression>;
If <boolean_expression> evaluates to false, a new AssertionError() is thrown.
Equivalent: if( !<boolean_expression>  ) throw new AssertionError();


Type 2: assert <boolean_expression> : <any_expression_but_void>;
If <boolean_expression> evaluates to false, then the <any_expression_but_void> expression is evaluated and passed as a parameter to the constructor of the AssertionError class.
Equivalent: if( !<boolean_expression>  ) throw new AssertionError(<any_expression_but_void>);

<boolean_expression> must evaluate to true or false, can also be a method call that returns a boolean.
<any_expression_but_void> should evaluate to any object or a primitive.
  
  • both types throw an AssertionError.
  • you are asserting that what is in the first part is true, if not then throw an AssertionError();
  • the AssertionError () can a have no argument  or a String or any number.
  • the braces are not obligatory.
  
Valid   

int j = 10;
assert (++j > 7);
assert (++j > 7) : “hi” ;
assert (j > 7)   : j = 12;
assert (++j > 7) : new Object();
assert (++j > 7) : aReturn(); // the method returns something or null.
assert (j > 7)   : null;
assert false;

NOTE: it is only valid to use a method call as the second parameter if the method returns something even if that something is a null.
 
Invalid

assert (++j > 7) : go(); // go() does not return a value.
assert 0;
assert (j);
assert (++j > 7) : noReturn(); // this method does not have a return.
assert (++j > 7) : Object o; // only a refer not an object.

NOTE: it is invalid that the second argument contains a call the a method that does not return a value. i.e. the method return type is null.
 

Catching assertion errors

If the assertion fails it will throw a java.lang.AssertionError. Note that this does not extend from Exception and therefore cannot be caught by Exception.
  
            try

            {
                        assert i == 20;
            }
            catch(Exception e)
            {
                        i = 20;
            }

This code WILL NOT catch the AssertionError because AssertionError extends Error and is not a subclass of Exception, so cannot be caught by a catch block catching Exception.
 


Appropriate:
  • It is appropriate to use assertions to generate alerts when you reach code that should not be reached , even in public methods: use assert false;
  • It is appropriate to use assertions to validate arguments to private methods.

Not appropriate:
  • It is not appropriate to use assertions to validate arguments to public methods.
  • It is not appropriate to catch and handle assertion errors.
  • It is not appropriate to use assertions to validate command-line arguments.
  • It is not appropriate for assertions to change a programs state or cause side-effects.

Compiling:
  • Exam assumes the use of Java 6;
  • Assertions did not exist in version 1.3 or below, so any use of assertions will result in a compilation failure.
  • From version 1.4 the use of “assert” as a keyword will result in a compilation failure.
  • In version 1.3 the compiler will give a warning if assert is used as a keyword.
  
Command line
As an identifier
As a keyword
javac –source 1.3 file.java
Code compiles with warnings
Compilation fails.
javac –source 1.4 file.java
Compilation fails.
Code compiles
javac –source 1.5 file.java
Compilation fails.
Code compiles
javac –source 5 file.java
Compilation fails.
Code compiles
javac –source 1.6 file.java
Compilation fails.
Code compiles
javac –source 6 file.java
Compilation fails.
Code compiles
javac file.java
Compilation fails.
Code compiles


Command line switches

Assertion are disabled by default.
  
java -disablassertions or -da
disable assertions
java -enableassertions or -ea
enable assertions
java -ea:com.scjp
enables assertions in the com.scjp package and all of its subpackages.
java -ea:com.scjp.Test
enables assertions in the com.scjp.Test class.
java -ea –da:com.scjp
enables assertions in general but to disable them in the package com.scjp and all of its subpackages.
java -dsa
disables assertions in the system classes
java -esa
enables assertions in the system classes
java -enablesystemassertions
enables assertions in the system classes

Enable/disable assertions in packages


Assertions can be enabled or disabled for specific packages or classes. To specify a class, use the class name. To specify a package, use the package name followed by “…” (three dots):

java -ea:<class> myPackage.myProgram
java -da:<package>… myPackage.myProgram

Each enable or disable modifies the one before it. This allows you to enable assertions in general, but disable them in a particular package:

java -ea -da:<package>… myPackage.myProgram

To enable assertion for one package and disable for other you can use:

java -ea:<package1>… -da:<package2>… myPackage.myProgram

You can enable or disable assertions in the unnamed root (default)package (the one in the current directory) using the following commands:

java -ea:… myPackage.myProgram
java -da:… myPackage.myProgram