Monkeys at Keyboards: The Javanomicon
© Michael James Heron
Topic: Java Programming
Level: 2
Version: delta

If trees could scream do you think we would be so cavalier as to cutting them down? Maybe if they screamed all the time for no good reason.
Jack Handey

1 - Java Fundamentals

PreviousTable of ContentsNext
Forum


Chapter Objectives

By the end of this chapter, the reader will be able to:

  • Be able to make use of variables.
  • Be able to make use of selection and repetition structures.
  • Be able to make use of methods.
  • Be able to make use of logical operators.
  • Be able to make instances of a class with the new keyword.


1.1

Introduction

This book is not an introductory programming text... it is expected that readers making use of this book have some experience with programming concepts. It is not anticipated that all readers will be familiar with the syntax of the Java programming language in particular, and this chapter is provided as an introduction to Java terminology and how certain fundamental programming constructs are built.

The techniques that are learned in introductory programming books are usually only building blocks - they serve as the foundation for later learning. It is impossible to progress as a Java developer without a sound appreciation for these low level concepts:

  • Variables
  • Scope
  • Operators
  • Conditionals
  • Repetition
  • Objects and Classes
  • Methods
  • Parameters

This chapter will briefly cover these building blocks, but readers who feel as if they could benefit from more detail are directed towards any one of the many introductory Java programming texts that are aimed primarily at these concepts. There will be a list of recommended reading texts at the end of the chapter.

You may already feel comfortable with this material, and if that's the case you can probably safely skim the material contained within... or indeed ignore it entirely. But upon your own heads be it!

It's recommended that you spend at least a few minutes, regardless of how comfortable you feel with Java, making a note of what is assumed knowledge for the rest of the book.

1.2

The Structure of a Java Program

Java is an Object Oriented Programming (OOP) Language. This means that it is written with the idea of objects firmly as a driving force. We will look at the idea of objects later on in the book, but there are certain fundamental things we need to understand before we can even begin to write a Java program.

All Java programs are written as classes. A class is a blueprint of sorts for an object. Objects are instances of a class. As an abstract example, consider a human being as a class, and individual people as instances of that class, and thus objects:

Relationship between objects and classes
Fig 1.1: Relationship between objects and classes

The implications of this development model will be discussed throughout the coming chapters... it's a very complicated system that takes some time to comprehend, so don't worry if you don't quite Get It from the start.

Consider the structure of a trivial piece of Java code:


public class Example {

public static void main (String arg[]) {
System.out.println ("Argh, it burns!");
}

}

This is the simplest of possible Java programs... all it does is print out the text 'Argh, it burns!' to the console window.

The first line of the program indicates to Java that you are creating a class, and that class is going to be called Example. The public keyword has particular meaning, and we'll discuss this in chapter eleven.

Once we've declared the class definition to Java, we have an open brace which is shown on the diagram as being bold. Each opening brace in Java has a matching closing brace - any code between these braces is treated as belonging to the single block of code that is associated with a particular programming structure. The closing brace for this open brace is also shown in bold, and it can be seen at the end of the code extract.

The position of braces in a Java program often confuses, since it seems initially to be completely arbitrary as to where they begin and end. For now, we have to just shrug our shoulders with weary ennui and accept that a class has an opening brace when it is declared and a closing brace when it is completed. The more we look at Java code, the more this should make sense.

The name of a Java class has special significance also... Java has an enforced naming convention that requires that the name of your class is be the same as the name of the file in which it resides. So if your class resides in a file called MyCode.java, then your class must be called MyCode. If it's not, Java will throw a tantrum and refuse to play. If you have a file called ThisIsMyStuff.java, then the class must be called ThisIsMyStuff.

If it doesn't and you attempt to compile your program, you will get an error message similar to the following:

class CLASS_NAME is public, should be declared in a file named CLASS_NAME.java

So to get back to the topic of braces, a class needs an opening brace and a closing brace:


public class Example {
}

The braces are used to indicate possession... that the code that follows an opening brace belongs to a particular coding structure (in this case, it belongs to a class). The closing brace indicates the end of possession. If it is the closing brace for a class, then the code for the class has been completed. If it is the closing brace for a programming structure within a class, then the possession returns to the previous structure.

We'll look at this a bit more in a later section of this chapter.

Within the example class above there is a piece of code that looks like this:


public static void main (String arg[]) {
System.out.println ("Argh, it burns!");
}

This is the main method for the class. This is the first thing that the Java Virtual Machine will execute when you compile and run a Java program. We'll look at the idea of methods a little later in this chapter, but for now all we need to know is that the main method will hold any code that we want to be executed when the program is compiled and executed.

The main method for our example class holds a single line of code:

System.out.println ("Argh, it burns!"); 

This is Java's console output method, and simply prints a line of text (in this case, 'Hello World!') to the console (see the JCreator Tutorial document for details on the console. This may be found in appendix one).

When we compile this file, the Java Development Kit will turn our human readable Java code into Java readable byte-code, and store it in a .class file. We'll talk about this a little more in the next chapter.

When we execute the code, Java will look for the appropriate class file and pass that on to the Java Virtual Machine, which will handle the task of actually making the computer do what it is told. The Java Virtual Machine will look for a main method within the class, and execute each of the lines of code within that method sequentially.

In the case of our example program, the main method sends a request to the operating system for it to display the text 'Argh, it burns!'.

1.3

Variables

The first building block that we have reason to look at is that of the variable. As can be imagined from the name, a variable is a container for some information that can change. It's very difficult (and by difficult I mean 'impossible') to write a piece of software that does anything of any degree of complexity without first understanding the idea of a variable.

Variables in Java have a type. This type indicates what kind of data can be found within. Variables in Java also have a name, which is used to make a reference to their contents in your code. They are somewhat similar to the unknown values in a simple algebra expression:

 x * x = 4

However, rather than you having to work out what the variables contain, you tell Java what information should go into them. They allow you to make a note of various things as your program runs. For example, you may want to keep track of what a user has typed, or how many times you've repeated a piece of code, or any number of other aspects of your program's execution. As you will see throughout the textbook, variables are the most fundamental aspects of learning how to program.

Any time we are going to have some data in our program that we don't in advance know the value of, we use a variable to hold it. Consider for example a program that asks the user their age and then prints it out on the screen. There is no way the developer can know in advance what the user is going to enter for their age, and so the developer must use a variable to contain this information so that the Java program can later do something with it.(in this case, so it can print the value out to the screen).

In all cases, the developer must know what kind of information is going to be placed into the variable. Some of the more standard variable types that Java provides are:

A table of data types
Fig 1.2: A table of data types

These are what are known as primitive data types in Java. There are more, but these are the most commonly used. We'll look at more complex data types as the book progresses, but these are the simplest of all Java variables.

Java also provides a special data type called a String. As you can imagine, this is used for holding whole strings of text. Although this is not a primitive data type (we'll talk about why this is the case when we talk about string representation later in the book), it is incredibly useful and worth mentioning at this point in our discussion about Java.

In order to use a variable, we must first declare it. To do this, we must give the type of the variable, and the name with which we will refer to it within our code. We do this using the following syntactical structure:

type variable_name; 

For example, to declare a variable that will hold an integer value that we reference with the name age, we would use the following line of code:

int age; 

This line of code sets aside some space in the computer's memory for our variable. When primitive data types are declared, they are given a starting value of 0. So our age variable here is a container for the number 0.

If we wish to put a different value into the variable, we use the assignment operator, which is indicated by a single equals sign.(more on the idea of operators later). We use the assignment operator like so:

variable_name = some_value; 

This indicates to Java that we wish to make the left hand side of the operator equal to the right hand side. So to put the value 15 into our age variable, we would use the following line of code:

age = 15; 

This is called an assignment... you assign a particular value to the variable. At the point of assignment, the current contents of the variable are overwritten with the new value.

The sequence of setting up a variable is such that you must declare a variable before you assign a value:

Correct:

int age; 
age = 15;

Incorrect:

age = 15; 
int age;

We can refer to the contents of our variable simply by its name - from this point on, our variable can be used in all the same places we could use a discreet value of the same type. The difference is that we don't need to know in advance what the value of the variable is going to be.

For example, let's create a String variable that holds our name. When assigning a value to a String, we surround the text we wish to assign with quotation marks - this lets Java know that we are putting some text into a variable and not referring to another variable. For example, consider the following statements.

String name; 
String Michael;
Michael = "Hello";
name = Michael;

The first thing that Java does here is create space in memory for two String variables. One of these is called name, and one is called Michael. It then assigns the value "Hello" to the variable Michael. But then, it assigns the contents of the variable Michael to the variable name. The consequence of this is that in the end, both variables contain the text "Hello".

Consider a second scenario:

String name; 
String Michael;
Michael = "Hello";
name = "Michael";

In this example, we create two variables in the same way as we did with the first. The difference is that through using this code, we assign the value "Hello" to the variable Michael, and the value "Michael" to the variable name. At the end, each variable holds a different value.

So, back to our string variable that contains our name:

String name; 
name = "Michael";

Think back to our first very simple program. Now that we have a variable that holds a string of text, we can replace the "Argh, it burns!" part of this line of code with our variable:


public static void main (String args[]) {
String name;
name = "You know, it doesn't burn at all!";
System.out.println (name);
}

Voila! This then prints out our message from a variable instead of it having to be hard-coded into the program.

The implications of this will be discussed throughout the book, particularly in relation to the different ways that Java treats primitive data-types and objects.

1.4

Scope

Now that we've spoken a little bit about variables, it's time to talk a bit about variable scope. This is simply a technical way of referring to when we can access variables and when we can't. Java enforces some strict rules on when a particular piece of code has access to a given variable.

Variables in Java have a lifecycle. They are born, they live for a little, and then they die... it's a sad reflection of our own brief, temporary existence. Variables exist as long as they are within scope. There are two main kinds of scope in Java: local scope and class-wide scope.

When you create a variable within a method (for example, within the main method), that variable exists only as long as the method is executing. When the method has finished executing, then the variable is destroyed. The consequence of this is that the variable can no longer be accessed, and whatever contents it had are lost.

Variables that are declared within the body of methods are called local variables - they are local to a particular method and cannot be accessed outside of it. The following code is an example of an invalid variable access:

Invalid scope
Fig 1.3: Invalid scope

This means that you can have multiple variables with the same name, provided they do not have overlapping scope.

The second kind of scope for a variable in Java is class-wide scope, and this means that every method within a particular class has access. Class variables are declared at the top of a class, outside of any method:

Invalid scope
Fig 1.4: Invalid scope

Obviously, the simplest solution to the problem of variable scope would seem to be to make all variables into class variables - however this is bad programming practice since each variable takes up space in memory, and having variables stored for longer than they are required is a drain on system resources. We'll look at ways of having methods communicating with each other via variables a little later in this chapter.

1.5

Operators

Java has a family of symbols called operators that are used to perform operations on values. We've already looked at the assignment operator, which puts the right hand side of the operator into the variable on the left hand side. There are a number of operators in Java that allow mathematical operations and logical comparisons to be performed on variables and values.

Mathematical Operators

Mathematical operators are used to perform arithimetic operations on sets of data. Obviously they are not suitable for all kinds of data - it's difficult to see how you could multiply two boolean values together for example.

The basic mathematical operators are as follows:

Table of mathematical operators
Fig 1.5: Table of mathematical operators

We use these operators all the way through Java programming. There are more of them, but these are the basic mathematical symbols. There are also a range of logical operators which we will discuss when we talk about selection structures.

It is possible to combine operators into a single line of code... for example:

int x = 2 + 3 / 4; 

In this case the standard rules of mathematical precedence are observed - multiplication followed by division followed by addition followed by subtraction.

You can enforce a different order of evaluation by putting brackets around calculations just like in conventional mathematics:

int x = (2 + 3) / 4; 

This for example will ensure that the addition is performed before the division.

Incremental and Decremental Operators

Java provides a family of incremental and decremental operators... we can use these to increase the value of integer variables. Unlike the mathematical operators, they are performed on a variable and do not require a left and right hand side:

The first of these operators is the ++ operator, which increases the numerical value of an integer variable by one. This can be placed before or after the variable:

int x = 10; 
x++;
++x;

There is also a decremental (--) operator that works exactly the same way except that it reduces the numerical value of an integer variable by one:

int x = 10; 
x--;
--x;

There is a difference in the notation (++x versus x++), and this comes when assigning the value of the variable to other variables, or when using the operator within a more complex syntactical structure. With the x++ notation, the variable is incremented after it is assigned, and with the ++ notation it is incremented before it is assigned:

Differences between post and pre incremental operators.
Fig 1.6: Differences between post and pre incremental operators.

These operators do not work on non-integer values since the concept of increasing non-whole numbers by one is mathematically ambiguous.

Assignment Operators

We've already looked at the basic assignment operator (=), but Java provides a range of operators within this family designed to simplify the expression of common assignments, such as adding numbers to variables.

These are compressions of the x = x + y notation, and take the form of the mathematical operator followed by the assignment operator:

Table of compressed assignment operators
Fig 1.7: Table of compressed assignment operators

There are more operators than this provided by the Java language, but these require a discussion of other Java concepts and so will be covered when it is most suitable to do so.

1.6

Conditionals and Selection Structures

So far we've covered sequential statements, assignments, scope and some basic operators. Now we're going to look at the idea of selection structures and how we can use these to allow us to control the flow of execution through a program.

Normally within Java methods, code is executed sequentially - this means that code is executed one line after the next. However, sometimes we have code that we only wish to be executed if certain preconditions are true. We can make the execution of statements conditional using the inbuilt Java selection structures.

>The if structure

The simplest of these is the if structure, and we use this to separate out a block of code that we wish to be executed only if a certain condition happens to be true. The structure of an if statement is as follows:

if (condition) { 
code_to_be_executed;
}

An if statement can contain any number of lines of code to be executed, and can contain other structures as required.

The condition of an if statement is based on a logical comparison - this is a fancy way of saying 'whether something is true'. Java provides a number of equivalence operators that allow us to specify the exact nature of a condition. The simplest of these is the basic equivalence operator (==). Note that this is different from the assignment operator... the equivalence operator takes the form of two equals signs, the assignment operator has only one.

The equivalence operator returns a boolean value depending on whether or not the comparison evaluates to true or false. If the condition within an if statement evaluates to true, then the code within the braces that belong to the if statement will be executed.

An example of some if conditions:

if (x == 5) { 
// The code will be executed only if the value of the variable x is 5.
}

if (x == y) { 
// The code will be executed only if the value of the variable x is the
// same as the value of the variable y.
}

The braces here allow us to lump together a pile of code as belonging to the if statement. Only the first statement of code after an if statement will be executed, but the braces allow us to say 'Hey, see all those lines of code? They're really just one big statement'. The braces are not actually necessary, but we may get unpredictable results if we omit them:

int x = 5; 
int y = 5;
if (x == y)
System.out.println ("Hey there monkey features!");
System.out.println ("Wow, you really look like a monkey!");

In this case, as the variable x has the same value as the variable y, it will print the following output:

 Hey there monkey features! 
Wow, you really look like a monkey!

But, if x does not have the same value as the variable y, it will print:

 Wow, you really look like a monkey!

We can clump together these statements using braces:

if (x == y) { 
System.out.println ("Hey there weirdo!");
System.out.println ("Like I say, you're a weirdo");
}

This is preferable to leaving the braces off since it is often necessary to add statements into an if structure, and omitting the braces may lead to mistakes when it comes time to expand the functionality.

Rather than being limited to simply checking purely for equivalence, Java also provides a number of relational operators we can use:

Table of relational operators
Fig 1.8: Table of relational operators

We can use these in the same places we can use the equivalence operator.

The If-Else Structure

Related to the if structure is the if-else structure. This takes the form of an instruction to Java that it should choose between one of two paths of execution depending on the value of some conditional expression. Unlike the if statement, one part of an if-else statement will always be executed.

If the conditional expression evaluates to true, then the code belonging to the if statement will be executed. Otherwise, the code belonging to the else statement will be executed:

if (x == y) { 
System.out.println ("X is equal to Y!");
}

else {
System.out.println ("X doesn't equal Y! Tragedy!");
}

Once again, there is no need to include these braces, but for the purposes of consistency and maintainability, we will always be using them throughout this book even if only demonstrating single statement structures.

The If-Else if structure

A third of these structures allows us to choose between a range of potential operations that are dependant on multiple conditions. For example:

if (x == y) { 
System.out.println ("X is equal to Y!");
}

else if (x == z) {
System.out.println ("X is equal to Z!");
}

We can extend this structure for as long as we like:

if (x == y) { 
System.out.println ("X is equal to Y!");
}

else if (x == z) {
System.out.println ("X is equal to Z!");
}

else if (y == z) {
System.out.println ("Y is equal to Z!");
}

Only one of the statements in a particular if-else if structure will be selected - each of the conditions are checked sequentially. As soon as one is encountered that returns true for the conditional expression, then it will execute the code that belongs to that particular condition, and once that has been executed the flow of execution returns to the first line of code after the if-else if structure:

int x = 10; 
int y = 20;
int z = 20;
if (x == y) {
System.out.println ("X is equal to Y!");
}

else if (x == z) {
System.out.println ("X is equal to Z!");
}

else if (y == z) {
System.out.println ("Y is equal to Z!");
}

System.out.println ("And now *I* have control!");

In this structure, the first conditional is evaluated. We check to see if x is equal to y. In this case, ten does not equal twenty and so the code associated with that conditional is not executed. It then moves onto the next conditional - checking to see if x is equal to z. Once again, ten does not equal twenty and so once again the code is not executed.

It then checks to see if y is equal to z - in this case, twenty does indeed equal twenty, and so the code that goes with that conditional is executed. The end output is:

Y is equal to Z! And now *I* have control!

If instead we set up the variables as:

int x = 10; 
int y = 10;
int z = 10;

The output instead will be:

X is equal to Y!And now *I* have control!

We can add a final else statement to the structure to provide a general 'catch all' for the case that none of the conditions evaluate to true:

if (x == y) { 
System.out.println ("X is equal to Y!");
}

else if (x == z) {
System.out.println ("X is equal to Z!");
}

else if (y == z) {
System.out.println ("Y is equal to Z!");
}

else {
System.out.println ("Nothing is equal to anything!");
}

With a variable setup as follows:

int x = 10; 
int y = 20;
int z = 30;

The output is:

Nothing is equal to anything! And now *I* have control!

All of the examples above are using single conditional expressions - we can build complex conditionals using some of Java's provided logical operators - more on this in a moment.

The Switch Statement

The switch statement is a condensed form of the if-else if structure, and is used to execute conditional code when the value of a variable is going to fall within a range of possibilities.

The switch statement needs a variable upon which it switches. It also has a number of case statements which represent possible values the variable can have. Java looks for a case statement that matches the current value of the switch variable, and executes the code that belongs to that particular case statement. It also provides syntax for a default case that will be executed if none of the others match:

int x; 
switch (x) {
case 0:
System.out.println ("X is zero.");
case 1:
System.out.println ("X is one.");
case 2:
System.out.println ("X is two.");
default:
System.out.println ("X is something else.");
}

A switch statement employs a 'fall through' architecture that means that multiple cases can be handled by the same statement of code:

int x; 
switch (x) {
case 0:
System.out.println ("X is zero.");
case 1:
System.out.println ("X is one.");
case 2:
case 3:
System.out.println ("X is two. Or maybe three. I'm not sure. Oh no, the pressure " +
"of failure.");
default:
System.out.println ("X is something else.");
}

However, the consequence of this is that all the statements after a matching case statement will be executed. So, for above, if we make x equal to 1, we will get the following output:

X is one. X is two.  Or maybe three. X is something else.

To get around this, we must explicitly tell Java to finish with the switch structure by using a break statement:

int x; 
switch (x) {
case 0:
System.out.println ("X is zero.");
break;
case 1:
System.out.println ("X is one.");
break;
case 2:
case 3:
System.out.println ("X is two. Or maybe three.");
break;
default:
System.out.println ("X is something else.");
break;
}

This ensures that only those statements that belong to a particular case will be executed.

An important drawback of the switch statement is that it only works on primitive data types - because of the way Strings are compared against each other (see chapter eight - String Theory), it's not possible to build a switch statement around them in Java.

1.7

Logical Operators

We often need to express a conditional on something more complex than a simple check. Often we want to check for ranges of values or conditions that are dependant on other conditions. Java allows us to build compound conditionals using a range of logical operators. The two that we will look at in this chapter are the and operator and the or operator. There are others, but they are too complicated for this section.

The And Operator

The and operator takes the form of two ampersand symbols side by side, like so: &&

It is used to express a relationship when the truth of a compound conditional is based on the truth of all its parts. For example, if we wanted to base a selection loop on the condition that a number falls somewhere between 0 and 100, we could use two if statements, nested within each other:

if (x < 0) { 
if (x < 100) {
System.out.println ("Yep, it's in range!");
}

}

For very complex conditions, this is very unwieldy. Instead we make use of a compound conditional to express these two conditions as one. If we use the and operator, we are specifying that both conditions must be true for the whole conditional to be evaluated as true:

if (x > 0 && x < 100) { 
System.out.println ("Yep, it's in range!");
}

We can express the relationship of these conditions as a truth table:

And operator truth table
Fig 1.9: And operator truth table

In other words, one single false condition will cause the whole compound conditional to evaluate as false.

It is good practise to enclose separate con itional expressions in brackets:

if ((x > 0) && (x < 100)) { 
System.out.println ("Yep, it's in range!");
}

By doing this, you ensure that the logical conditions you have in your head are mapped correctly onto the appropriate structure.

The Or Operator

Sometimes however we just want to check if one or another condition is true - we use an or operator to do this. The or operator is two bars side by side: ||

if ((x == y) || (y == z)) { 
System.out.println ("Yeah, one of those were true!");
}

This works in exactly the same way as the and operator, except that the truth table looks slightly different:

Or operator truth table
Fig 1.10: Or operator truth table

For an or operator, both statements must be false for the overall compound condition to evaluate as false. In any other scenario, the compound conditional evaluates as true.

We can build even more complex compound conditionals from these by linking together other compound conditions:

if (((x > 0) && (x < 100)) || y == 20) { 

Compound conditionals are evaluated from left to right, and in the order specified by the precedence of brackets. So first, this if statements attempts to evaluate the condition: (x > 0) && (x < 100).

Once it has evaluated this compound conditional as true or false, it then evaluates the next using an or operator on the result of the last conditional.

For example, if X is 20, then the first conditional will evaluate to true because X is greater than 0 and X is less than 100. Therefore our conditional is evaluated as:

(true) && (true)

Since this is an and operator, both parts of the operator must be true for the whole to evaluate as true. This is the case, so this is condensed down into simply being true.

After this has been evaluated, the if condition looks like this:

if (true || y == 20) { 
}

It can sometimes be very difficult to think through complex conditional compounds, particularly if the operators change frequently. This is something that will become easier with practise. A good grounding in logical algebra is very helpful here, since there are some standard rules that you can use to simplify your conditionals. See the further reading section for more details.

1.8

Repetition

Often in a program there is code that we want to repeat a number of times. One way is to write each of the lines to be repeated separately, but this is sometimes not possible. Consider a program that asks a user for their age and then prints out a * for each candle they would have on their next birthday cake. If I enter 25, it will print out 26 stars.

This is easy to do, but at design time we have no idea what the user is going to enter for the age - it's simply not possible for us to write a program that will anticipate every possible user input value.

Instead, we can make use of repetition structures to repeat code. Java provides three of these, in two flavours: bounded loops and unbounded loops.

Bounded Loops

The main bounded loop that Java provides is the for loop. Bounded loops are used when we know how many times we must repeat a section of code.

For loops have three parts to them, and they base their repetitions on a counter. The first part of a for loop is the initialisation part - this occurs once, as soon as the loop begins. Usually we set up the counter in here. The second part is an evaluation conditional, and this determines whether or not a loop continues to repeat. We use the same format for this as with a conditional in a selection structure, as above.

The third part of the loop is the upkeep part and this contains the code to be executed after every loop. Usually in this part we update the counter.

The syntax for a simple for loop is as follows:

int i; 
for (i = 0; i < 10; i = i + 1) {
System.out.println ("The current number is " + i);
}

Let's look at that in a little more detail:

The for Loop Exploded
Fig 1.11: The for Loop Exploded

When Java gets to this for loop, the first thing that it does is executes the statement within the initialisation section of the loop - it sets the variable i (which we are using as a counter) to 0.

Then, Java checks the conditional expression - is the value of the variable i less than ten? If it is, then Java executes the code that belongs to the for loop:

The current number is 0.

Java then executes the code in the upkeep section - it adds one to the variable i. After the first execution of the for loop's code, i is equal to 1.

Java then once again checks the conditional to see if it should repeat. Note that Java only calls the initialisation part once - the counter is never reset. If it has to repeat again it executes the code:

The current number is 1.

And then executes the upkeep code. It keeps doing this until the evaluation is false:

The current number is 2.
The current number is 3.
The current number is 4.
The current number is 5.
The current number is 6.
The current number is 7.
The current number is 8.
The current number is 9.

Once the evaluation is false it then returns execution to the code outside of the loop.

We can also use variables for our evaluation conditional - this gives us enormous flexibility:

int max = 20; 
int i;
for (i = 0; i < max; i++) {
}

We use a for loop when we know how many times we want to execute a piece of code. Sometimes however we don't know this in advance, and so we need to make use of another kind of loop - the while loop.

Unbounded Loops

Unbounded Loops are used when we don't know in advance how many times we need to repeat a particular section of code. Instead, we base the repetition not on a counter but purely on a conditional expression:

while (x < y) { 
System.out.println ("Yes, I'm still repeating!");
x = x + 4;
y = y + 1;
}

The condition is evaluated before the code is executed, so if the condition evaluates to false, the code that belongs to the while loop will never be executed:

int x = 20; 
int y = 10;
while (x < y) {
System.out.println ("Yes, I'm still repeating, because x is " + x + " and " +
"y is " + y + "!");
x = x + 3;
y = y + 1;
}

System.out.println ("Hello world!");

Since the very first conditional evaluation is false, the code within the while loop is never executed. The output for this would be:

Hello world!

On the other hand, with the setup:

int x = 10; 
int y = 20;

The loop will continue until the condition evaluates as false. So the this time around the loop:

Yes, I'm still repeating because x is 10 and y is 20!
Yes, I'm still repeating because x is 13 and y is 21!
Yes, I'm still repeating because x is 16 and y is 22!
Yes, I'm still repeating because x is 19 and y is 23!
Yes, I'm still repeating because x is 22 and y is 24!
Yes, I'm still repeating because x is 25 and y is 25!
Hello world!

There is a second loop based on the while structure, and this is the do while loop:

do { 
System.out.println ("Yes, I'm still repeating!");
x = x + 3;
y = y + 1;
}

while (x < y);

It is almost the same except that the code will be executed before the condition is evaluated for the first time, which means that the code will always be executed at least once. From that point on, the code is repeated only if the condition evaluates to true.

Breaking Up Is Hard To Do

Usually, provided we write our evaluation condition correctly, a loop is syntactically complete. We loop the appropriate number of times, which is handled by the structure itself, and then we continue on our merry way. Alas, sometimes the real world throws obstacles in our way, and the looping structure itself is not quite enough.

Sometimes we need to change the way a loop works and terminate out of it before it is actually 'finished'. Imagine a real world scenario in which someone gives us a hundred numbered envelopes and tells us to tell them which envelope number was addressed to us. Our actions would work a bit like a for loop:

int mine; 
for (int i = 0; i < 100; i++) {
if (envelope_number_i == addressed_to_us) {
mine = i;
}

}

However, if the envelope was number ten, then it would be pointless for us to check the other ninety. We could model our behaviour instead with a while loop, but that means writing our own counter system:

int mine; 
while (!envelope_found && i < 100) {
if (envelope_number_i == addressed_to_us) {
envelope_found = true;
mine = i;
}

i = i + 1;
}

This would work, but it requires us to implement a counter system that is already present in a for loop... effectively we need to write the upkeep and evaluation parts of the for loop ourselves. This means we're really just making a while loop act like a bounded loop.

Using a for loop by itself however means potential inefficiency... so we need a way that lets us stop a for loop in its tracks if it no longer has to iterate. Java gives us just that power with the use of the break statement.

If we put a break statement within the body of a loop, as soon as Java reaches that line of code it will stop executing the loop and return control to the next statement after the loop structure:

for (int i = 0; i < 10; i++) { 
if (i == 5) {
break;
}

System.out.println ("The counter is " + i);
}

System.out.println ("Hi-oh!");

This would give us the following output:

The counter is 0
The counter is 1
The counter is 2
The counter is 3
The counter is 4
Hi-oh!

Sometimes though, we don't want to completely stop the loop - we just want to avoid one particular iteration. For this, we can use the continue statement, which works in the same way as the break statement except that it terminates only a single iteration, not the entire loop:

for (int i = 0; i < 10; i++) { 
if (i == 5) {
continue;
}

System.out.println ("The counter is " + i);
}

System.out.println ("Hi-oh!");

This structure would yield the following output:

The counter is 0 
The counter is 1
The counter is 2
The counter is 3
The counter is 4
The counter is 6
The counter is 7
The counter is 8
The counter is 9
Hi-oh!

Notice here that the loop has skipped over the iteration where i is five, but has continued merrily onwards with the next iteration.

It is not often that either break or continue are required within a looping structure - over reliance on either of these is a sign that you perhaps need to rethink your program's control flow structure. However, when used sparingly and appropriately, they are useful and powerful statements that can greatly increase the effectiveness and efficiency of your looping structures.

1.9

Methods and Parameters

Methods are stubs of functionality that exist independently until they are executed. They are used to substantially improve the modularity and maintainability of code. :

Methods are identified by name, as with variables. They also have a return type and a list of parameters. Methods may have a number of method qualifiers which we will discuss later. For now, we will simply give all of our methods a public qualifier. :

The main method in a Java application is an example of a method:

A method exploded
Fig 1.12: A method exploded

Methods communicate with other pieces of Java code by means of the parameters and return types of the method. The parameters are variables that are passed into the method - essentially they become local variables within that method. The return type is the type of information that comes out of a method.

Methods may only return one type of data, but they can take any number of parameters. Consider a method that takes two integer parameters and returns the sum of these:


public int addTwoNumbers (int num1, int num2) {
int answer;
answer = num1 + num2;
return answer;
}

We can call this piece of code by referring to the method name:


public static void main (Strin args[]) {
int temp;
temp = addTwoNumbers (10, 20);
System.out.println ("The answer to 10 plus 20 is " + temp);
}

We assign the return value of the method to a variable of the appropriate type (in this case, an int). We use the return keyword to indicate when we want to send some information out of the method - as soon as we do this, the method stops executing and control returns to the code that just called the method. Any code that exists after the return statement has been executed will be unreachable and never executed - Java will provide a compile-time error when this is the case.

Why should we use methods? We use them mainly because they make it easier to keep our code up to date. Consider a piece of code that requires us to check to see if a number of variables are within a particular range:


public static void main (String args[]) {
int temp1, temp2, temp3, temp4, temp5;
if ((temp1 > 0) && (temp1 < 100)) {
System.out.println ("Variable is within range");
}

if ((temp2 > 0) && (temp2 < 100)) {
System.out.println ("Variable is within range");
}

if ((temp3 > 0) && (temp3 < 100)) {
System.out.println ("Variable is within range");
}

if ((temp4 > 0) && (temp4 < 100)) {
System.out.println ("Variable is within range");
}

if ((temp5 > 0) && (temp5 < 100)) {
System.out.println ("Variable is within range");
}

}

Later the requirements change and the valid range of each variable becomes 5-95 - with the code above, we must change every if statement to reflect the new requirements. This can be very cumbersome if we have ten, twenty or even a thousand such statements to change, and that kind of alteration is just begging for some kind of transcription error to slip in.

Instead, we can use a method to return a boolean value indicating if a variable is within range:


public boolean isVariableWithinRange (int var) {
if ((var > 0) && (var < 100)) {
return true;
}

else {
return false;
}

}

And then we base all our checks on that method:

if (isVariableWithinRange (temp1) == true) { 
System.out.println ("Variable is within range");
}

Now, when we need to change the range, we only change the method that does the checking and all of our code is up to date.

Methods do not need to have a return type or any parameters. For a method that does not return a value, we use void as a return type (as with the main method). If we have no parameters, we leave the method brackets empty:


public void printMessage() {
System.out.println ("I'm a message!");
}

Then when we need to execute the method, we call it purely by its name:

printMessage(); 

For those methods that do have parameters, the order in which we pass them into the method determines the value of the parameters in the method:

Order of parameter passing
Fig 1.13: Order of parameter passing

1.10

Method Overloading

Java works out what method to call from what is known as a method signature. The method signature is the name of the method, plus the type and order of parameters. This means that it's possible to have two methods with the same name, but with a different set of parameters. In such a case, Java is perfectly happy to treat them as two different methods. They may have entirely different method bodies and contain entirely different code - Java doesn't mind.

For example, consider the following two methods:


public int addTwoNumbers (int num1, int num2) {
return num1 + num2;
}


public double addTwoNumbers (double num1, double num2) {
return num1 + num2;
}

Java sees these are two entirely different methods, because the method signature for the first is addTwoNumbers (int, int), whereas the method signature for the second is addTwoNumbers(double, double).

Java works out which method should be called by checking the name of the method being called, and the type and order of any parameters passed into it. If it finds a method signature that matches the information it has, it executes the code that belongs to that method (and only that method). Otherwise, it gives an error.

Say we have the following lines of code:

double num1 = 10.2; 
double num2 = 22.7;
double answer = addTwoNumbers (num1, num2);

When Java gets to the addTwoNumbers call, it checks the information passed between the brackets - in this case, two doubles. It checks the first definition for the addTwoNumbers method (which takes two integers), and says 'no... the information this one needs doesn't match the information I have'. It then checks the next definition and says 'Yes, this needs two doubles - I have two doubles... this is the code that needs to be executed'. It then executes the code that belongs to the matching method signature.

You can see from the example above one situation in where this is useful - we provide the same method name for adding integers and adding floating point numbers, which means when using our code we don't need to remember what we called the integer adding method and what we called the double adding method because they both have the same name.

Providing multiple method signatures for the same method name is called method overloading. We'll see more examples of this throughout the book.

1.11

Objects and Classes

The idea of objects and classes is fundamental to an understanding of the Java language - however, this chapter is not the place for us to discuss this in any depth. Objects are so fundamental to Java that we must understand at least how to use them even if we don't spend a lot of time actually thinking about why.

The simple definition of a class is that it is a blueprint of sorts that describes what attributes an object has. An object is a specific instance of a class. For example, a chair may be a class - it describes the attributes that all chairs have. However, specific chairs (your chair, my chair, his chair, her chair) are all objects - they are instances of a class that determines what a chair is.

This is a difficult concept to grasp and so we will spend some time in later chapters of this book looking at the idea a little further.

For now, we're just going to concentrate on how we use them. On a basic level, classes are complex data types. They are containers for some information, and they also usually provide a number of methods for acting on that information. We create objects from them in almost the same way as we create variables of primitive data types. We give the name of a class and the name by which we wish to refer to the object we are going to create from it.

For example, there is a class called Polygon in the Java library and this class holds the information needed to draw a polygon onto an applet (we'll see this process in the next chapter). We would create a variable through which we can refer to the object like so:

Polygon triangle; 

As you can see, this is identical to how we create a variable of a primitive data type. There is a difference however in how we assign them with a starting value. To do this, we must use the special new keyword, and pass the name of the class again.

triangle = new Polygon(); 

The part that follows the new keyword looks like a method call, and that's exactly what it is - it is executing a piece of code called a constructor method that contains the code needed to setup the object. We don't need to worry about that too much just now - where we need to, we will discuss what information needs to be passed into this constructor method to set up our objects correctly.

Once we have our object, we can access its methods and variables by using the dot notation. There is a method in our polygon called addPoint that is used to tell Java about a new co-ordinate to be used in the drawing of the polygon. We can access this method as follows:

triangle.addPoint (100, 100); 

This is exactly the same as the syntax for executing a method as shown above, except that we have to tell Java where to find the add oint method. The dot notation lets us say 'Call the method addPoint... you'll find it in the triangle object'.

This is quite a complex subject, and we will have cause to return to it in later chapters. For now, you should only recognise the code when you see it in the next few code examples. The specifics will be discussed in due course.

Another difference between objects and primitives is how Java deals with their contents. The variable we use to refer to an object does not hold that object - instead it holds a memory address that indicates where that object may be located. This has implications that will be revealed when we come to discuss comparing objects against other objects.

1.12

Conclusion

This is a very quick guide to some of the fundamental concepts in Java. Remember, this is not an introductory programming textbook. As such, we don't have time to cover these ideas in any further depth. Students who are still unfamiliar with these concepts should spend some time reading any of the introductory programming texts that are available on the subjects.

It is important that readers feel comfortable with all of these topics - it will be taken as read that this is the case throughout the later chapters of this book. Without a sound understanding of these basic concepts, students will struggle throughout the rest of the book. Understand that this is the case and make efforts to compensate if you feel this may be applicable to you - see the further reading section for examples of books that may be useful in helping you get up to speed.

1.13

Reader Exercises

These exercises should test your understanding of the concepts outlined in this chapter. You may find these exercises somewhat complicated to understand - if this is the case, you should have a look at the APE Antics book on the website to familiarise yourself with these concepts. From this point on, the book moves quite fast and you are expected to keep up!

Note: You need to have access to the Graphics object in order to draw to an Applet. However, the only place that has access to the Graphics object is the paint method... all of your methods should allow this object to be passed. For example, in question three, your method would have the following signature:

public void drawDoor (Graphics g, int x, int y, int length, int height) 
{
}

And it would be called from within paint like so:


public void paint (Graphics g) {
drawDoor (g, 10, 10, 100, 100);
}

Exercise One

Open up a new JApplet. Use the JCreator template for this.

Amend the paint method in the provided code to create a String variable and set a message to be displayed. The message itself does not matter.

Amend the call to the drawString method so that it uses the contents of your String variable for the message.

Using a loop, have the applet print the message stored in your string variable to the screen a total of five times. Each time it should print it lower on the applet than the last.

Write a method called buildMessage that takes two parameters... a String containing a name and an int containing an age. This method should return a string that places the two in an appropriate sentence (Such as: ' is years old.");

Amend your program so that the message displayed in the applet is generated from the method you wrote in part 5.

Amend your buildMessage method so that if the age is greater than 40 it returns the string " is years young".

Exercise Two

Open up a new JApplet. Use the JCreator template for this.

Draw a circle in the middle of the applet screen.

From the bounds you have specified from the circle, work out the radius of the circle and store it in an integer variable.

Write a method, calculateArea that takes the radius of the circle and returns a double that represents the area - you can determine this by using the formula 3.141 * radius * radius.

Display the radius of the drawn circle in the middle of the circle itself.

Exercise Three

Open up a new JApplet. Use the JCreator template for this.

Write a method, drawDoor, that takes an x, y, length and height parameter and draws the appropriate door at the specified location with the specified dimensions.

Write a companion method, drawWindow, that takes id ntical parameters and draws a window at the specified location.

Make use of these methods within your applet to draw a block of flats:

Doors; Windows; and Flats
Fig 1.14: Doors; Windows; and Flats

Exercise Four

Write a method, drawHouse, that will take an x, y, length and height combination and draw a house to scale. You will need to do some calculations within your method to get everything drawn in relation to each aspect of the house.

Provide another method, 'drawRowOfHouses' that will draw a number of houses in a row. It should take an integer parameter that indicates how many houses to draw, an x and y pair that indicate where to start drawing, and a length and height pair that indicate the scale to which each house should be drawn.

Exercise Five

Provide an overloaded method for the drawDoor method in question four. This method should provide a default value for x, y, length and height if none are provided. Note: Your overloaded method should not duplicate any code - it should simply call the written method with default parameters.

Exercise Six

A tree can be drawn as a series of green circles with a brown rectangle for a trunk. Write a method drawTree that does exactly this. It should take the standard x, y, length and height parameters to calculate where to draw all the aspects:

A tree
Fig 1.15: A tree

Exercise Seven

As with the drawRowOfHouses method in question 4a, write a method - drawLineOfTrees that will draw a line of trees according to the passed parameters.

Further Reading

The following table details further reading on the topic in this chapter, and also any external resources that you may find useful.

ResourceDescription
Lecture Slides for this chapterThis zip file contains the Powerpoint lecture slides that accompany this chapter.
On The Difficulty of Learning To ProgramTony Jenkins is an entertaining speaker on the subject of teaching programming - this is one of his papers. It's worth reading.
APE AnticsDid you find this chapter a little hard going? Perhaps you'd be better starting off with the book APE Antics which covers all of this material in tender, loving depth. It is definitely worth taking a look at if you don't feel 100% confident with the topics outlined in this chapter.

PreviousTable of ContentsNext

© 2004-2006 Michael James Heron