Statements and Functions

Selection, Iteration and Static Methods

Non-trivial programs require a way to make decisions, and to repeat a set of instructions — control flow. To fa­ci­li­tate these requirements, Java provides a number of selection and it­e­ra­tion state­ments. Pro­grams also need a way to group repeatable code, which are functions, but commonly called methods because of Java’s object-oriented nature.

Types, Values and Variables

Arrays and Collections

PREREQUISITES — You should already…

Selection Statements

java-logo

The logical and comparison operators provide a means for us to calculate boolean results. They are generally only useful, if we use these results to execute different statements, i.e. select which statements to execute. By the same token, boolean results can be used to determine whether we must or must not, repeat a series of statements. But, first, the selection statements…

NOTATIONBoolean Expression & Statements

Since boolean type expressions will be common, we shall use the notation:

  • bool-expr means any “expression, regardless of complexity, resulting in a boolean”.

Furthermore, we remind you of the following:

  • statement means any statement (normally terminated with a semicolon), including a
  • compound statement curly-brace delimited block, with zero or more ‹statement›s.

It is a recursive definition — statements can contain statements can contain statements…

If Statement

The if statement (tutorial), can be used to conditionally execute statements, in other words, it may jump over the statements, depending on a boolean condition.

SyntaxIf Statement

  • if (bool-expr)
    statement
  • bool-expr any expression resulting in a boolean value.

Since the if statement can contain one ‹statement›, we often “cheat” and use a compound statement at that position, because a compound statement is one statement, which satisfies the syntax, but it can contain multiple statements. Some programmers consistently use a compound statement, whether it is required or not. This is not a bad convention for several reasons, so you might consider it.

PatternIf Statement with Compound Statement

  • if (bool-expr) {
    statement

    }

The ‹statement› part of an if statement, is only executed when the ‹bool-expr› results in true.

We fully-qualified all methods, so you can be reminded of where they reside, but it is the if statement that is of importance here.

If-Else Statement

The if statement by itself is useful, but sometimes we want to execute A or B, i.e. “either this A, or that B”. For that scenario, we have the if-else statement (tutorial), where the else clause belongs to the closest if part.

SyntaxIf-Else Statement

  • if (bool-expr)
    statementA
    else
    statementB

As before, either ‹statementA›, or ‹statementB›, or both, can be compound statements. We sug­gest that if one is a compound statement, make the other also a compound statement regardless. If you follow the convention that you always use compound statements, you are covered.

One problem with if-else, is when we want to have multiple instances of it, a multi-way select in other words. This means we want to execute only one of: either statement A, or statement B, or statement C,… This often lead to programmers writing the construct with a staircase effect:

This is completely unnecessary and serves not purpose. We suggest that logically, you must think of situations when an if follows and else as one concept, an elseif clause, if you will, except that is not a keyword, and you must write it: else if:

This much neater, more readable, more maintainable, more consistent and less wasteful of space. If you used compound statements, it would look as follows (using our style):

Obviously, in the above case, you could have had multiple statements inside of each compound statement.

Switch Statement

Sometimes, a multi-way select can be represented more succinctly, with the switch statement (tutorial). Understand that whatever logic you use a switch statement for, can be implemented with if-else statements, which means using a switch statement is sometimes just somebody’s preference. The reverse is not true — you cannot rewrite every series of if-else statements in terms of a switch statement.

SyntaxSwitch Statement

  • switch (expr) {
    caselabel1:
    statementA›…
    [break;]
    caselabel2:
    statmentB›…
    [break;]

    [default:]
    [‹statementX>…]
    }
  • expr can only be an integer, enumerated or string type.
  • labelN must be unique constant expressions of same type as ‹expr›.

The ‹expr› is matched agains the ‹label?› expressions, and when a match is found, execution transfers (jumps) to the first statement following the matching label. Any break statement encountered afterwards, will cause execution to transfer to the statement(s) after the closing curly-brace.

Notice that the break statements are optional. If they are omitted, execution will fall-through to the next ‹statement›, even if past another case label. If you compile with -Xlint and/or the -Xdiags:verbose switches to javac, you will get warnings if you omit the break statements, since they are often forgotten, and more commonly an error, than by design:

warning: [fallthrough] possible fall-through into case

Apart from the warning, the code will still compile and execute as desired.

too many

The default label is optional, and can appear anywhere although surprisingly few programmers know that, so rather always put it last, if present. When omitted, you must of course not have any ‹statementX› either.

too many     zero       one        two       three

The ellipses after ‹statement?›… implies that you can have any number of statements, of any kind before the break statement.

three      too many

Of course, with break statements, the code snippet would look like this:

three

Iteration Statements

Now that we can control the flow of our program with selection statements, we want to consider iteration (“loops” for us plebs). An iteration statement will continuously execute a set of state­ments while some condition remains true, i.e., some ‹bool-expr›ession. It is possible for an iteration to continue indefinitely, and is generally a defect, and is called an infinite loop.

While Loop

This simplest of the iteration statements, has a similar syntax pattern to the if statement:

SyntaxWhile Iteration Statement

  • while (bool-expr)
    statement

Exactly like the if statement, the ‹statement› part can also be a compound statement (block), and some programmers always use a compound statement as a convention.

loop  9 times (1..9) :   1  2  3  4  5  6  7  8  9
loop 10 times (1..10):   1  2  3  4  5  6  7  8  9 10
loop 10 times (0..9) :   0  1  2  3  4  5  6  7  8  9
loop 10 times (0..9) :   0  1  2  3  4  5  6  7  8  9

Do-While Loop

In some algorithms, we want the ‹statement› part of a loop to execute at least once, guaranteed. With the normal while loop, it is not guaranteed to execute the ‹statement› even once. In such rare occasions, you may consider the do-while loop:

SyntaxDo-While Loop

  • do
    statement
    while (bool-expr );

Even if ‹bool-expr› is false, the ‹statement› will execute once. Style-wise, it does represent some consistency problems when using a compound statement; we provide some ideas:

Personally, we suggest you choose between the first two.

MultLoop.javaIf, While and Do-While Statements Example

Although in all the examples above, we knew beforehand how many iterations were required, it is not the most common use of a while loop. We generally use it when we do not know how many times to loop beforehand, like reading lines from a file.

Exercise: Program that outputs a complete multiplication table grid for 112, no input required.

For Loop

Although with our while loop examples, we knew beforehand how may times to iterate, the for loop is generally the iteration statement to use when we know the count.

SyntaxFor Loop Statement

  • for ( [‹init›] ; [‹bool-expr›] ; [‹iter-expr›] )
    statement
  • init expression and/or variable definition executed once.
  • bool-expr condition that controls when iteration will terminate.
  • iter-expr expression to evaluate at end of each iteration.

Note that each of ‹init›, ‹bool-expr› and ‹iter-expr› are optional; however, if ‹bool-expr› is not present, Java will substitute true, which makes it an infinite loop. If both ‹init› and ‹iter-expr› are omitted, you effectively have a weird-looking while loop.

Consider the elements of the while loop in the previous example:

We can now rewrite it as a for loop, which is much more succinct, and all elements that control the loop: 1) initialising the controlling variable(s), 2) checking the condition, and 3) modifying the controlling variable(s), are all in one place.

It is not a requirement to define variables in the ‹init› part of the for loop, but is certainly common. The scope of any definition there, is limited to the ‹statement› part of the for loop.

One can define more than one variable in the ‹init› part of the for loop, and also evaluate more than one ‹iter-expr›ession, by utilising the comma operator (which is the only place you can use it in Java):

For-Each Loop

For completeness, we include the “for-each” loop here, which Java calls the enhanced for statement, but we shall find use for it in the next section, when we deal with multiple values (arrays an collections). But for now, here is the syntax:

SyntaxFor-Each / Enhanced For Loop

  • for ( [‹type›] ‹ident:iter-expr)
    statement
  • type when defining ‹ident›; must be type of item from ‹iter-expr›.
  • ident variable which will contain sucessive items produced by ‹iter-expr›.
  • iter-expr collection expression that is “iterable”.
\u2502 \u2500 \u253C \u252C \u2534 \u2524 \u251C \u250C \u2518 \u2514 \u2510

Abstractly, the construct pattern: ‘for(item:collection)’ means: “for each ‹item› in this ‹collection…”, which is why we call it the “for-each” loop.

Break and Continue

The break statement can also be used inside iteration statements. It will effectively terminate the iteration summarily — transfer execution to the first statement following the body of the loop. This means, it is practically only useful after a selection statement.

A statement that has the opposite effect: immediately start the next iteration; is the continue statement.

Labelled Statements

Any iteration statement can be labelled with ‹label:, where ‹label› is just an ‹ident›ifier, really. Java has not goto, but the label can be used by the continue and break statements, in other words, you write: ‘breaklabel;’, which means that the break will apply to the labelled iteration statement, not necessarily the potentially nested loop that contains the break. The same syntax applies to continue.

We use a label (INPUT) to break out of the outer for loop. We could simply have used a return statement, but this way we could still perform some tasks just before the return statement. It is all a bit contrived, but you can at least see it in action. Since we also wanted the function to be practical, we did use a try-catch block, which will deal with later. Now, even if the user enters garbage that cannot be parsed to a Double, the program will not terminate.

Other Statements

Here follows a number of other statement types, or topics involving statements. They are all specialised and simpler than the major statements we already described.

Null or Empty Statement

If the syntax requires a statement, and for some reason you have not useful statement to employ at that point, you can simply write a semicolon (;). In that context, it is called a null, or empty, statement.

Statement Nesting

Anywhere we used ‹statement› you can use any construct we called a statement. Practically, this means that inside while loop, you can have another while loop, which contains for example, an if statement, which contains a try-catch statement, etc. In other words, statements can nest to arbitrary depth.

Expression Statements

Although not as forgiving as C or C++, any expression that affects state, or that calls a method, can be made a statement, simply by appending a semicolon.

Assert Statements

The assert statement can be use to facilitate the abstractions of preconditions and postconditions. In other words, we do not use assert statements for input or runtime validation. It is intended to guard against programmer errors.

SyntaxAssert Statement

  • assertbool-expr;
  • assertbool-expr1:bool-expr2;

Since many assertions (generally a good sign), can be expensive (bad thing), we can enable or disable assertions with arguments to the javac command line compiler. You can en/disable assertions globally, or for a package.

Functions / Methods

A major component in a programmer’s toolset, is the ability to name a group of statements. We may want to do that because it could make a program more readable (as long as the name suggests properly what is going to happen), or to reuse a group of statements in several places. In Java the technical mechanism for this, is a function (a construct that takes arguments and returns one value), although because of the OOP influence, Java acolytes prefer the term method.

Other languages call their implementation of the concept: subprogram, subroutine or procedure. We will use the terms function when we discuss syntax and technicalities, and call it method, when we focus on its object-oriented features and behaviour.

Function Definition

A function definition is a syntax that conforms to a pattern in certain locations in your program. There is no keyword to define functions, just like there is not keyword to define variables.

You cannot define functions inside other functions; definitions can therefore only appear a class level. Unless they have the static specifier attached, they are instance functions, but they cannot be called until you have an object (instance of the class). Syntax-wise, the only difference is the static specifier, which is why we show it as optional in the syntax:

SyntaxFunction Definition

  • [static] ‹ret-type›‖voidident( [‹param›] ) function header
    [‹thow-spec›]        unchecked exceptions “thrown”.
    { function body block.
    [‹statement›…]
    [return;returnexpr;]
    }
  • ret-type the type of the value the function will return.
  • ident name of the function.
  • void the function will not return any value, but may use return;.
  • return; only legal on functions with void return type.
  • returnexpr; required when using a ‹ret-type› that is not void.
  • param optionalparameters..
  • throw-spec list of unchecked exceptions that can “escape” the function.

IMPORTANTFunction Signatures ≡ Overloading

A function ‹ident›ifier, types and numbers of ‹param›eters together, constitutes its signature. The function signature is what identifies a function uniquely; you can think of it as the ID of the function. A function ‹ident›ifier by itself, is thus ambiguous, and does not identify a function. It also means that functions may have the sameident›ifier, as long as the signatures are different.

This is overloading — functions with the same names, taking different arguments.

Notice that ‹statement›s are optional, which means it is legal to have a function with an empty body — as long as it returns void, otherwise you must have at least a ‘returnexpr;’ statement.

Returns

A function can return only one value. This may be a composite value, but nevertheless one value. The ‹type› of the ‹expr›ession returned, must match the function’s ‹ret-type› (return type in the definition of the function).

Although it goes against the grain of structured programming, you may have multiple return statements in a function. Since it is an execution transfer statement, no statement after a return statement, will execute. The following function has multiple return statements, which is not in line with structured programming, but is certainly easy to understand:

Note that the compiler is intelligent enough to realise that all execution paths will have a return statement, which is why it will not complain that there is not return statement at the end of the function body block. You could take out the default: label, and move its return statement to the end of the function, and you will still have the same logic.

Returning Multiple Values

A function, by definition, can only return a single value. This value can be of any ‹type›, even a type containing many values, so this is never a problem, but does require syntax and concepts we have not yet discussed. In many languages, including C++ and C#, the standard li­bra­ries pro­vide some sort of tuple for ad hoc grouping of arbitrary type and number of values. Java does not, but a search for tuples will bring up many implementations, articles and libraries.

The simplest (and least flexible) solution below should not be too difficult to follow, even if we have not yet discussed classes and encapsulation. We want a function to return two values, one of type String, and another of type double, so we create a simple class TupleSD con­tain­ing in­stan­ce members representing two value with these types.

TuplePair.javaSimple Pair Tuple Example
Pair: "Some String", 12.3400
Pair: "Another String", 56.7800

For each combination of types and number of values, you will have to make a new class, but the pattern is simple. More realistic implementations will use generics, but we leave that for later.

Parameters

To make functions more generic, so that its functionality can be applied to different values, we need the ability to pass arguments. The syntax that enables this ability, is called parameters, or “formal parameters”. Parameters are in every respect like local variables:

The only difference, is that parameters are initialised by the caller of the function at run time.

NOTEParameters vs Arguments

These two term are unfortunately used interchangeably by too many authors. They are not synonyms. Arguments are ‹expressions›, while a parameter involves a concept, and a syntax in the definition of functions (methods). That is how we use these two terms religiously.

Since parameters are variables, they have the same syntax as variable definitions, except that no initialisation clause is possible. And unlike variables, you must repeat the ‹type› for each parameter. Here is the basic syntax for ‹param›eters:

SyntaxFunction Parameters

  • type› ‹ident single parameter.
  • type› ‹ident1,type› ‹ident2, multiple parameters, with the same ‹type›.
  • type1› ‹ident1,type2› ‹ident2, multiple parameters with different ‹type›s.
  • type...ident variable number of ‹type› arguments can be passed.
  • type1› ‹ident1,type2...ident›    one fixed argument, followed by zero
    or more arguments can be passed
    .

In the last case, you can have any number of parameters before the last variable-length pa­ra­me­ter. The three dots together are called ellipsis, but they are three period characters (...), not the Unicode ellipsis character: (…).

VarLenParam.javaVariable Length Parameters Example
zero :''  │  one  :A  │  two  :BC  │  three:DEF  │  many :GHIJ

Arguments are passed by position to the respective parameters. Java possesses no syntax for named arguments, nor default arguments. You have to make do with function over­load­ing (dif­fe­rent sig­na­tur­es), and variable argument list parameters.

The function F above, can take any number of String arguments after the first argument (which must be int). If you wanted to pass arbitrary ‹type›s of arguments after the first, you have to make it an Object.

ObjVarArgs.javaObject Variable Length Parameter
zero ""
one     : <A (String)>
two     : <123 (int)> <B (String)>
three   : <D (String)> <45.67 (double)> <F (char)>
too many: <99 (int)> <true (boolean)> <12.0 (double)> <J (String)>

This example also illustrates use of the instanceof operator, which is an example of simple re­flec­tion. You should not depend on reflection too much, if at all, and hence try to not design with the instanceof operator in mind.

As a matter of interest, for this particular example, we could have asked Java to get use the ‹type› name of each argument, using either the getName method, or the getSimpleName method from the java.lang.Class<T> type returned by the getClass method of java.lang.Object:

These two methods are really only useful for debugging or learning; they do occur much, if at all, in production code or non-trivial programs.

Only Pass-by-Value

It is a common cause of confusion for newcomers to Java, but arguments are always passed by value, even if that value is a reference value. Pass-by-value as a concept, means “pass a copy” of the argument expression. Java offers no syntax or concept for pass-by-reference; just something to be aware of. If you want a function to modify some argument you pass, a few patterns are available to achieve the effect.

Consider a simple example: You want a function that takes a double as parameter, which it must modify, e.g. it must increase its value by 50%. A common solution, is to put the single double in an array variable and pass the array. Since a reference will be passed, the function can modify the first (and only) element. This is a bit of a hack, but the alternative is to wrap the double (only) in a class.

NoPassByRef.javaAlternative Pass-by-Reference Solutions

Clearly, the preferable option is to have a function return a modified value, and assign that back to the variable which was also passed as argument. This is only an option though, if the function is to “modify” one argument. For multiple argument modifications with this method, you have to wrap the arguments in a class, so that you can still pass one argument, and return one result.

The option to put it in an array, is fine, except that the function looks a bit odd (we pass an array, but for the purposes of modifying the only element).

Abstractly, the best solution is to create a wrapper class. It does add more code, but the meaning of your program is clear. This is jumping the gun a bit, since we have not really discussed en­cap­su­la­tion, instance methods, and constructors yet, but it is a simple pattern nevertheless.

Recursion

Java functions can call themselves, and this is recursion. Any recursive algorithm can be rewritten iteratively, so you should not feel compelled to use recursion. The common refrain is that re­cur­sive algorithms can be more elegant. Recursion is basically just another way to iterate. It is also an easy way to get results in reverse order.

Recurse.javaSimple Recursion Example
R1: 0 1 2 3 4
R2: 5 4 3 2 1
R3: 5 4 3 2 1 0
R4: 0 0 1 2 3 4
R5: 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0

As you can see, you get different effects and order, depending on where you do the actual work with the parameter; out.format("%d ", i) in our case. The examples are not particularly useful, but does illustrate that recursion is a simple concept in principle. It simply uses the stack to cre­ate new copies of variables, which an iterative solution has to manage itself. The fol­low­ing it­e­ra­tion snippet, will produce exactly same result, for example, as R5(5):

And as final thoughts: in general, recursive algorithms are slower their iterative counterparts, potentially use more memory, and has the likelihood of exhausting the stack. So, use it only if you really think that your recursive solution is safe, and more comprehensible (or elegant).

Exception Handling

Ahem. It has come to this. To understand exceptions, you have to understand several pre­re­qui­site concepts. Exceptions concern “exceptional and unfortunate circumstances we hope will never come to pass”. It is not a mechanism for controlling the flow of a program. But events out­side a program’s control may cause errors, so can bugs in code. Both are “unfortunate cir­cum­stan­ces”, but we cannot just “hope”, we must be prepared for these events, even if they may seem unlikely.

Java and other languages encapsulates this concept under the umbrella term “exceptions”, and build a whole vocabulary of terms around it. For example, code may “throw” or “raise” an ex­cep­tion. Other parts of the code may “catch” or “handle” the exception. We shall use throw and catch exclusively, because Java has throw and catch keywords related to exceptions.

Thread of Execution

We can visualise the step-wise execution of a program as a thread that is fixed at the start of a pro­gram’s startup code: it unwinds with a call to main(); then unwinds ever more as state­ments are exe­cu­ted. Calls to functions also unwind this proverbial thread, and calls to other func­tions within them, unwind it even further — to an arbitrary depth. Normally, only return statements from functions can rewind the thread back up again. This trail that the thread leaves, is re­cord­ed on the stack. This is why this rewinding of the thread is often referred to as “un­wind­ing the stack”, be­cause the stack size decreases (it really should have been called “rewinding the thread”).

Exception handling can use this trail and follow it right back to the start, if necessary. In the pro­cess of retracing the thread, the exception handling mechanism will look for a handler in the cur­rent func­tion. If not found, it will perform normal local variable clean-up, before it re­winds the thread to the caller, at which time it repeats the process, until it potentially reach­es main(). If still not caught in main(), the program will terminate with an “unhandled ex­cep­tion” message.

Inheritance and Up­casting

Consider a class Deriv, that inherits from (or extends) class Base. In Java and other OOP lan­guag­es, the one significant feature that prevails: is that a variable of type Base, can store a re­fe­ren­ce to a Deriv object, without an explicit cast (type conversion). This is sometimes referred to as an “up-cast”, simply because the convention in UML (Unified Modelling Language), is to draw the Base class higher than Derived classes. Go figure.

If a class, let us call it Downward, in turns inherits from Deriv, a Base variable can reference a Downward object as well, without an explicit cast, because the conversion is still “upwards”.

Exception Objects

In order to throw and exception, code cannot just throw anything: the type of the object must be “throwable” (java.lang.Throwable class), which in practical terms mean that code can throw any type of object, as long as it inherits directly, or indirectly, from Throwable. In the Java li­bra­ry clas­ses, the java.lang.Exception class is the major class that inherits from Throwable, and almost all other classes that represent exceptions, in turn inherits from Exception.

Practically, this means if you have a variable or parameter of type Exception, you can pass any object that has the Exception class in its ancestry (upwards). All methods that throw exception objects, document this fact, which is why the Java SE 8 Documentation is indispensable. And all will throw exceptions derived from Exception (well, about 99%).

Catching Exceptions

To alert Java that your code is prepared to catch an exception object, your code that has the po­ten­ti­al to cause an exception to be thrown, must be enclosed in a try block. Following, the try block, will be one or more catch blocks, and optionally, a finally block:

SyntaxTry-Catch-Finally Statement

  • try {
    statement›…
    }
    catch (type1› ‹ident) {
    statement›…
    }
    catch (type2› ‹ident) {
    statement›…
    }

    finally {
    statement›…
    }

To avoid clutter, we did not show in the syntax that finally is optional, and that only one catch block is required. Multiple catch blocks are optional, and the ‹type› must be different from other catch block ‹type›s. The curly-brace blocks are mandatory, and forms a scope. The ‹ident›ifiers act logically like parameter to each catch block, so you can use the same name in all catch block parameters. Many use e or ex consistently.

In fact, unless the ‹type› is your own custom exception type, you must make sure that the deepest derived ‹type1› comes before the least-derived ‹type2›. That is because Java only looks for a viable catch block for a thrown object, not the best match. And if your custom ‹type› inherits from Exception, directly or indirectly, you must still adhere to this rule. The main problem is that the Java compiler does not alert you to this potential problem (it could, it just doesn’t).

The finally block is very special. If it is present, the statements inside this block, is guaranteed to execute… regardless if an exception was thrown or not; regardless if the function has a return statement in the try block, or not. A try block may have only a finally block (no catch blocks); this is often used to close files, or dispose of resources that cannot be retained indefinitely.

Of course, statements inside a catch or finally block can also throw exceptions, or cause ex­cep­tions to be thrown. If code in a catch block throwsident› (the catch block parameter), it is called a “re-throw”, and will restart the process of looking for a “catcher”, just not in the current func­tion. Sometimes we catch exceptions for purposes other than “handling” the exception (or “deal­ing with the prob­lem”), so we can do your thing, and just “re-throw” the exception, as if nothing happened. And yes, finally code will still execute.

Exception Summary

This section exists to introduce you to the concepts of exception handling. It does not show any examples because that will obscure from the concepts we are trying to impart, but it does mean we shall be using exception handling more and more in example code. Because our code will have to become more sophisticated very soon, our examples will have to deal with, and even throw, exceptions.

Types, Values and Variables

Arrays and Collections

2017-12-29: Edited. [jjc]
2017-12-28: Created. [brx]