Return to index

Java Basics 5
Expressions, Statements and Blocks

 

Topics covered include :

  • Expressions, Statements and Blocks
  • Control Flow Statements

 

Expressions, Statements and Blocks

This section discusses how to combine operators and variables into sequences known as expressions. Expressions are the building blocks of your code. You will also learn how to construct statements and statement blocks.

Variables and operators, which you met in the previous two sections, are the basic building blocks of programs. You combine literals, variables and operators to form expressions - segments of code that perform computations and return values. Certain expressions can be made into statements - complete units of execution. By grouping statements together with curly braces { and }, you create blocks of code.

 

Expressions

Expressions perform the work of a program. Among other things, expressions are used to compute and to assign values to variables and to help control the execution flow of a program.

The job of an expression is twofold:

  • to perform the computation indicated by the elements of the expression
  • to return a value that is the result of the computation.

Definition:  An 'expression' is a series of variables, operators and method calls (constructed according to the syntax of the language) that evaluates to a single value.

As discussed in the previous section, operators return a value, so the use of an operator forms an expression. This program snippet has its expressions shown in purple:

private void method1 {
      char aChar = 'S';
      boolean aBoolean = true;
      byte largestByte = Byte.MAX_VALUE;
      System.out.println("The largest byte value is " + largestByte + ".");
      ...
      if (Character.isUpperCase(aChar)) {
             ...
      }
      ...
} 

Each of these expressions performs at least one operation and returns a value.

Expression Action Value Returned
aChar = 'S' Assign the character 'S' to the character variable aChar The value of aChar after the assignment ('S')
"The largest byte value is " + largestByte + "." Concatenate the string "The largest byte value is " and the value of largestByte converted to a string The resulting string: The largest byte value is 127
Character.isUpperCase(aChar) Call the method isUpperCase The return value of the method: true

 The data type of the value returned by an expression depends on the elements used in the expression. The expression aChar = 'S' returns a character because the assignment operator returns a value of the same data type as its operands and aChar and 'S' are characters. As you can see from the other expressions, an expression can return a boolean value, a String, and so on.

The Java programming language allows you to construct compound expressions and statements from various smaller expressions as long as the data types required by one part of the expression match the data types of the other. Here's an example of a compound expression:

x * y * z 

In this particular example, the order in which the expression is evaluated is unimportant because the results of multiplication is independent of order - the outcome is always the same no matter what order you apply the multiplications. However, this is not true of all expressions. For example, the following expression gives different results depending on whether you perform the addition or the division operation first:

x + y / 100     // ambiguous 

You can specify exactly how you want an expression to be evaluated by using balanced parentheses '(' and ')'. For example to make the previous expression unambiguous, you could write:

(x + y)/ 100      // unambiguous, recommended 

If you don't explicitly indicate the order in which you want the operations in a compound expression to be performed, the order is determined by the precedence assigned to the operators in use within the expression. Operators with a higher precedence get evaluated first. For example, the division operator has a higher precedence than does the addition operator. Thus, the two following statements are equivalent:

x + y / 100
x + (y / 100)     // unambiguous, recommended 

When writing compound expressions, you should be explicit and indicate with parentheses which operators should be evaluated first. This will make your code easier to read - and to maintain.

The following table shows the precedence assigned to the operators. The operators in this table are listed in precedence order: the higher in the table an operator appears, the greater its precedence. Operators with higher precedence are evaluated before operators with a relatively lower precedence. Operators on the same line have equal precedence.

postfix operators [] . (params) expr++ expr--
unary operators ++expr --expr +expr -expr ~ !
creation or cast new (type)expr
multiplicative * / %
additive + -
shift << >> >>>
relational < > <= >= instanceof
equality == !=
bitwise AND &
bitwise exclusive OR ^
bitwise inclusive OR |
logical AND &&
logical OR ||
conditional ? :
assignment = += -= *= /= %= &= ^= |= <<= >>= >>>=


When operators of equal precedence appear in the same expression, a rule must govern which is evaluated first. All binary operators except for the assignment operators are evaluated in left-to-right order. Assignment operators are evaluated right to left because the result of the right hand expression is stored in the left hand variable.

 

Statements

Statements are roughly equivalent to sentences in natural languages. A 'statement' forms a complete unit of execution. The following types of expressions can be made into a statement by terminating the expression with a semicolon (;):

  • Assignment expressions
  • Any use of ++ or --
  • Method calls
  • Object creation expressions

These kinds of statements are called 'expression statements'. Here are some examples of expression statements:

aValue = 8933.234;      // assignment statement
aValue++;        // increment statement
System.out.println(aValue);         // method call statement
Integer integerObject = new Integer(4);      // object creation statement 

In addition to these kinds of expression statements, there are two other kinds of statements. A 'declaration statement' declares a variable. You've seen many examples of declaration statements. Here is an example:

double aValue = 8933.234;       // declaration statement 

A 'control flow statement' regulates the order in which statements are executed. The for loop and the if statement are both examples of control flow statements.

 

Blocks

A 'block' is a group of zero or more statements between balanced braces and can be used anywhere that a single statement is allowed. The following listing shows two blocks from a longer program, each containing a single statement:

...
if (Character.isUpperCase(aChar)) {
    System.out.println("The character " + aChar + " is upper case.");
} else {
    System.out.println("The character " + aChar + " is lower case.");
}
...

 

Summary of Expressions, Statements and Blocks

An expression is a series of variables, operators and method calls (constructed according to the syntax of the language) that evaluates to a single value. You can write compound expressions by combining expressions so long as the types required by all of the operators involved in the compound expression are correct. When writing compound expressions, you should be explicit and indicate with parentheses which operators should be evaluated first.

If you choose not to use parentheses, then the Java platform evaluates the compound expression in the order dictated by operator precedence.

A statement forms a complete unit of execution and is terminated with a semicolon (;). There are three kinds of statements:

  • expression statements
  • declaration statements
  • control flow statements.

You can group zero or more statements together into a block with curly brackets ( { and } ). Even though not required, we recommend using blocks with control flow statements even if there's only one statement in the block.

Be careful when writing complex compound expressions because they can be much harder to read and might hide bugs. Write in a series of simpler steps instead.

 

Control Flow Statements

Programs use control flow statements to conditionally execute statements, to loop over statements, or to jump to another area in the program. This section shows you how to control your program's flow with such statements as if-else and while.

When you write a program, you type statements into a file. Without control flow statements, the interpreter executes these statements in the order they appear in the file from left to right, top to bottom.

You can use 'control flow statements' in your programs to conditionally execute statements, to repeatedly execute a block of statements, and to otherwise change the normal, sequential flow of control. For example, in the following code snippet, the if statement conditionally executes the System.out.println statement within the braces, based on the return value of Character.isUpperCase(aChar):

char c;
...
if (Character.isUpperCase(aChar)) {
    System.out.println("The character " + aChar + " is upper case.");
} 

The Java programming language provides a number of control flow statements, which are listed in the following table.

Statement Type Keyword
looping while, do-while, for
decision making if-else, switch-case
exception handling try-catch-finally, throw
branching break, continue, label:, return

 

In the sections that follow, you will see the following notation to describe the general form of a control flow statement:

control flow statement details {
       statement(s)
} 

Technically, the braces, { and }, are not required if the block contains only one statement.

if (x<0) System.out.println("x is < 0");

is equivalent to :

if (x<0) {
    System.out.println("x is < 0");
}

However, we recommend that you always use { and }, because the code is easier to read and maintain. It also helps to prevent errors.

 

The 'while' and 'do-while' Statements

You use a while statement to continually execute a block of statements while a condition remains true. The general syntax of the while statement is:

while (expression) {
    statements
} 

First, the while statement evaluates 'expression', which must return a boolean value. If the expression returns true, then the while statement executes the statement(s) associated with it inside the {} block. The while statement continues testing the expression and executing its block until the expression returns false. Hence code within the block should be capable of changing the result of the condition or the program will be caught in an endless loop.

The example program shown below, called WhileDemo, uses a while statement to step through the characters of a string, appending each character from the string to the end of a string buffer until it encounters the letter 'g'.

public class WhileDemo {
      public static void main(String[] args) {
            String copyFromMe = "Copy this string until you " + "encounter the letter 'g'.";
            StringBuffer copyToMe = new StringBuffer();
            int i = 0;
            char c = copyFromMe.charAt(i);
            while (c != 'g') {
                  copyToMe.append(c);
                  c = copyFromMe.charAt(++i);
            }
            System.out.println(copyToMe);
      }
} 

The value printed by the last line is: Copy this strin.

The Java programming language provides another statement that is similar to the while statement - the do-while statement. The general syntax of the do-while is:

do {
      statement(s)
} while (expression); 

Instead of evaluating the expression at the top of the loop, do-while evaluates the expression at the bottom. Thus the statements associated with a do-while are executed at least once.

Here's the previous program rewritten to use do-while and renamed to DoWhileDemo:

public class DoWhileDemo {
      public static void main(String[] args) {
            String copyFromMe = "Copy this string until you encounter the letter 'g'.";
            StringBuffer copyToMe = new StringBuffer();
            int i = 0;
            char c = copyFromMe.charAt(i);
            do {
                  copyToMe.append(c);
                  c = copyFromMe.charAt(++i);
            } while (c != 'g');
            System.out.println(copyToMe);
      }
} 

The value printed by the last line is: Copy this strin.

 

The 'for' Statement

The for statement provides a compact way to iterate (loop) over a range of values. The general form of the for statement can be expressed like this:

for (initialization; termination condition; increment/decrement) {
      statements
} 

The 'initialization' is an expression that initializes the loop - it is executed once at the beginning of the loop. The 'termination' expression determines when to terminate the loop. This expression is evaluated at the top of each iteration of the loop. When the expression evaluates to false, the loop terminates. Finally, 'increment/decrement' is an expression that gets invoked after each iteration of the loop. All these components are optional.

Often for loops are used to iterate over the elements in an array, or the characters in a string. The following example, ForDemo, uses a for statement to iterate over the elements of an array and print them:

public class ForDemo {
      public static void main(String[] args) {
            int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076 };
            for (int i = 0; i < arrayOfInts.length; i++) {
                  System.out.print(arrayOfInts[i] + " ");
            }
            System.out.println();
      }
} 

The output of the program is: 32 87 3 589 12 1076.

Note that you can declare a local variable within the initialization expression of a for loop. The scope of this variable extends from its declaration to the end of the block governed by the for statement so it can be used in the termination and increment expressions as well. If the variable that controls a for loop is not needed outside of the loop, it's best to declare the variable in the initialization expression. The names i, j, and k are often used to control for loops; declaring them within the for loop initialization expression limits their life-span and reduces errors.

 

The 'if' and 'if / else' Statements

The if statement enables your program to selectively execute other statements, based on some criteria. For example, suppose that your program prints debugging information, based on the value of a boolean variable named debug. If debug is true, your program prints debugging information, such as the value of a variable, such as x. Otherwise, your program proceeds normally. A segment of code to implement this might look like this:

if (debug) {
      System.out.println("DEBUG: x = " + x);
} 

This is the simplest version of the if statement - the block governed by the if statement is executed if the condition is true. Generally, the simple form can be written like this:

if (expression) {
      statement(s)
} 

What if you want to perform a different set of statements if the expression is false? You use the else statement for that. Consider another example. Suppose that your program needs to perform different actions depending on whether the user clicks the 'OK' button or another button in a dialog. Your program could do this by using an if statement along with an else statement:

. . .
// response is either OK or CANCEL depending on the button that the user pressed
. . .
if (response.equals("OK")) {
      // code to perform OK action
} else {
      // code to perform Cancel action
} 

The else block is executed if the if part is false. Another form of the else statement, else if, executes a statement based on another expression. An if statement can have any number of companion else if statements but only one else statement.

The following example is a program, IfElseDemo, that assigns a grade based on the value of a test score: an A for a score of 90% or above, a B for a score of 80% or above, and so on:

public class IfElseDemo {
      public static void main(String[] args) {
            int testscore = 76;
            char grade;
            if (testscore >= 90) {
                  grade = 'A';
            } else if (testscore >= 80) {
                  grade = 'B';
            } else if (testscore >= 70) {
                  grade = 'C';
            } else if (testscore >= 60) {
                  grade = 'D';
            } else {
                  grade = 'F';
            }
            System.out.println("Grade = " + grade);
      }
} 

The output from this program is:

Grade = C 

You may have noticed that the value of testscore can satisfy more than one of the expressions in the compound if statement: 76 >= 70 and 76 >= 60. However, as the runtime system processes a compound if statement such as this one, once a condition is satisfied, the appropriate statements are executed (grade = 'C';), and the flow of execution passes out of the if statement without evaluating the remaining conditions.

The Java programming language supports an operator, ?:, that is a compact version of an if statement. Recall this statement from an earlier program:

if (Character.isUpperCase(aChar)) {
      System.out.println("The character " + aChar + " is upper case.");
} else {
      System.out.println("The character " + aChar + " is lower case.");
} 

Here's how you could rewrite that statement using the ?: operator:

System.out.println("The character " + aChar + " is " +
                   (Character.isUpperCase(aChar) ? "upper" : "lower") +
                   "case."); 

The ?: operator returns the string "upper" if the isUpperCase() method returns true. Otherwise, it returns the string "lower". The result is concatenated with the other parts of the message to be displayed. Using ?: makes sense here because the if statement is secondary to the call to the println method. Once you get used to this construct, it can make the code more concise in some circumstances.

 

The 'switch' Statement

The switch statement works in a similar way to a compound if statement (one that uses else if) - but it depends on discreet values rather than ranges of values or conditions as is possible with multiple if statements. So we could not easily rewrite the grading example from above using the switch statement.

The following example program, SwitchDemo, declares an integer named month whose value represents the month in a date. The program displays the name of the month as a String, based on the value of month:

public class SwitchDemo {
      public static void main(String[] args) {        
            int month = 8;
            switch (month) {
                  case 1:  System.out.println("January"); break;
                  case 2:  System.out.println("February"); break;
                  case 3:  System.out.println("March"); break;
                  case 4:  System.out.println("April"); break;
                  case 5:  System.out.println("May"); break;
                  case 6:  System.out.println("June"); break;
                  case 7:  System.out.println("July"); break;
                  case 8:  System.out.println("August"); break;
                  case 9:  System.out.println("September"); break;
                  case 10: System.out.println("October"); break;
                  case 11: System.out.println("November"); break;
                  case 12: System.out.println("December"); break;
            }
      }
} 

The switch statement evaluates its expression, in this case simply the value of variable month, and executes the appropriate case statement. Thus, the output of the program is: August.

Of course, you could implement this by using a compound if statement:

int month = 8;
if (month == 1) {
      System.out.println("January");
} else if (month == 2) {
      System.out.println("February");
} else if (month == 3) {
      System.out.println("March");
}  
. . .   // and so on 

Deciding whether to use a compound if statement or a switch statement is a judgement call. You can decide which to use, based on readability and other factors. An if statement can be used to make decisions based on ranges of values or conditions, whereas a switch statement can make decisions based only on discreet values (char, int). Also, the value provided to each case statement must be unique.

Another point of interest is the break statement after each case. Each break statement terminates the enclosing switch statement so that the flow of control continues with the first statement following the switch block. The break statements are necessary because without them, the case statements fall through. That is, without an explicit break, control will flow sequentially through subsequent case statements.

The following example, SwitchDemo2, illustrates why it might be useful to have case statements 'fall through':

public class SwitchDemo2 {
      public static void main(String[] args) {
            int month = 2;
            int year = 2000;
            int numDays = 0;
            switch (month) {
                  case 1:
                  case 3:
                  case 5:
                  case 7:
                  case 8:
                  case 10:
                  case 12:
                        numDays = 31;
                        break;
                  case 4:
                  case 6:
                  case 9:
                  case 11:
                        numDays = 30;
                        break;
                  case 2:
                        if ( ((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0) ) {
                              numDays = 29;
                        } else {
                              numDays = 28;
                        }
                        break;
                 }
                 System.out.println("Number of Days = " + numDays);
        }
} 

The output from this program is:

Number of Days = 29 

Technically, the final break is not required because flow would fall out of the switch statement anyway. However, we recommend using a break for the last case statement just in case you need to add more case statements at a later date and forget to add it. This makes modifying the code easier and less error-prone.

Finally, you can use a default statement at the end of the switch to handle all values that aren't explicitly handled by one of the case statements.

int month = 8;
switch (month) {
      case 1:  System.out.println("January"); break;
      case 2:  System.out.println("February"); break;
      case 3:  System.out.println("March"); break;
      case 4:  System.out.println("April"); break;
      case 5:  System.out.println("May"); break;
      case 6:  System.out.println("June"); break;
      case 7:  System.out.println("July"); break;
      case 8:  System.out.println("August"); break;
      case 9:  System.out.println("September"); break;
      case 10: System.out.println("October"); break;
      case 11: System.out.println("November"); break;
      case 12: System.out.println("December"); break;
      default: System.out.println("Hey, that's not a valid month!"); break;
}

The 'break' Statement

The break statement has two forms: unlabeled and labeled.

You saw the unlabeled form of the break statement used with switch earlier. As noted there, an unlabeled break terminates the enclosing switch statement, and flow of control transfers to the statement immediately following the switch block. You can also use the unlabeled form of the break statement to terminate a for, while, or do-while loop. The following example program, BreakDemo, contains a for loop that searches for a particular value within an array:

public class BreakDemo {
      public static void main(String[] args) {
            int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 };
            int searchfor = 12;
            int i = 0;
            boolean foundIt = false;
            for ( ; i < arrayOfInts.length; i++) {
                  if (arrayOfInts[i] == searchfor) {
                        foundIt = true;
                        break;
                 }
          }
          if (foundIt) {
                System.out.println("Found " + searchfor + " at index " + i);
          } else {
                System.out.println(searchfor + "not in the array");
          }
    }
} 

The break statement terminates the for loop when the value is found. The flow of control transfers to the statement following the enclosing for block, which is the print statement at the end of the program.

The output of this program is:

Found 12 at index 4

 

Exception Handling Statements

The Java programming language provides a mechanism known as exceptions to help programs report and handle errors. When an error occurs, the program throws an exception.

What does this mean? It means that the normal flow of the program is interrupted and that the runtime environment attempts to find an exception handler - a block of code that can handle a particular type of error. The exception handler can attempt to recover from the error or, if it determines that the error is unrecoverable, provide a meaningful explanation and gentle exit from the program.

Three statements play a part in handling exceptions:

  • The try statement identifies a block of statements within which an exception might be thrown.
  • The catch statement must be associated with a try statement and identifies a block of statements that can handle a particular type of exception. The statements are executed if an exception of a particular type occurs within the try block.
  • The finally statement (optional) must be associated with a try statement and identifies a block of statements that are executed regardless of whether or not an error occurs within the try block.

Here's the general form of these statements:

try {
      statement(s)
} catch (exceptiontype name) {
      statement(s)
}

and with a finally block:

try {
      statement(s)
} catch (exceptiontype name) {
      statement(s)
} finally {
      statement(s)
}


This has been a brief overview of the statements provided by the Java programming language used in reporting and handling errors. However, note that other factors and considerations, such as the difference between runtime and checked exceptions and the hierarchy of exceptions classes, which represent various types of exceptions, play a role in using the exception mechanism. See the section on Exception Handling for more information on this topic.

Note : Although 'goto' is a reserved word, currently the Java programming language does not support the goto statement and is unlikely to do so because unstructured jumping leads to 'spagetti code'.

 
Download and run ...

You can download the source code for the example programs as a TJI project from the 'Resources' page of our website.

 

NOTE : This document was based on parts of the excellent book 'The Java Tutorial' by Mary Campione, Kathy Walrath and Alison Huml; also on-line at Sun's Java site.


Return to index