Learning any programming language can be a daunting task. Java is no exception. It was designed to be on the cutting edge and can sometimes suffer from problems not found in more established languages. Luckily, Java also has been designed to be as
simple as possible while remaining, for the most part, as powerful as any other modern programming language.
Java is, at its core, an object-oriented language. Often touted as the holy grail of programming, object-oriented programming is essentially a very useful way to break up large programs into smaller, more manageable pieces known as objects. Being
object-oriented also means that programming isn't as straightforward as is might have been in a language like BASIC or even C.
The discussion of Java's object-oriented nature is not until the next chapter to keep things in this chapter as simple as possible so that you can better understand what can be put into objects. This chapter discusses some of the core functions in Java.
If this information seems a little bit dry, it is. However, when you learn any new language(computer or human), there is a period of learning the very basics before being able to articulate interesting things. Have no fear, though; Java's syntax is not as
strange as most other languages' is.
Comments are the most underused syntax element in programming. A comment enables you to add notes to your code to make sure that when someone else(or you in a few years) reads your code and can't figure out what is going on, there is some guide to clear
things up.
There are three ways to comment Java code:
/* This is a block comment */ /** This is a 'doc' comment **/ // This is a line comment
The block and 'doc' comments are both surrounded by beginning and end markers. They should be used when a paragraph or two needs to be said about a block of code in general. The 'doc' comments are one of Java's nicer features. This type of comment
enables you to comment your code as you normally would, and they also can be read by the javadoc program to create on-the-fly HTML documentation for your applets. The line comment does not have an end marker; it marks everything to the end of the line as a
comment. It is most useful to comment the program on a line by line basis.
The compiler ignores comments; they are there purely to help the programming. Feel free to write as much as you think is necessary, going overboard in explaining if necessary. That said, make sure that the comments you leave are pertinent. Many
beginning programmers make the mistake of trying to comment every line, which is almost worse that no commenting at all. Why? First, the programmer tends to tire of all the commenting quickly and gives up on commenting entirely in the long run. Second, the
important comments tend to get lost in the mass of verbiage. A good general rule on commenting is to look at a piece of code and ask yourself, "Is what this code does obvious?" If not, comment it.
Much like real life, there is a need in programming to remember things and to associate a name with those things. For instance, you refer to how old someone is by his or her age. Programming languages do the same thing. Statements in the language say
things like the following line, which sets the age to be 22:
age = 22;
In this example, age is a variable because its value can be changed. You could set age to 30 at a later time. This is known as variable assignment: '=' assigns whatever is to the right of it to the variable to the left of it. The semicolon (;)is Java's
way of indicating the end of the current statement.
In some languages, such as BASIC, variables can be created on the fly, and a statement like the preceding one could appear in the middle of a program. In Java, much like C or C++, all variables must be declared at the beginning of a program. When you
declare a variable, you must specify both its name and its type. For instance, someone's age would be represented as an integer, which in Java is signified by int:
int age; age = 22;
The eight basic (or primitive) types available in Java fall into four categories: integer, floating-point number, character, and boolean.
Representing numbers is one of the most basic aspects of programming, and numbers can be represented as integers in most cases. An integer is a positive or negative whole number (but no fractional numbers). For example, 34 is an integer, but 34.5 is
not. The following table lists the four types of integers available in Java:
Keyword |
Type |
Range |
byte |
8-bit integer |
-256 to 255 |
short |
16-bit integer |
-32768 to 32767 |
int |
32-bit integer |
-2147483648 to 2147483647 |
long |
64-bit integer |
-9223372036854775808 to 9223372036854775807 |
The different integer types enable you to specify a larger or smaller range for the number that is stored in a variable. The int type should be sufficient for most purposes unless the value of the number that needs to be stored is huge (on the order of
several billion) or if many smaller numbers need to be stored (in which case byte might make sense).
Although most of the time integers are sufficient, sometimes it's necessary to store numbers with a decimal point, like 3.14132. These numbers are known as floating-point numbers. The following table lists the two types of floating-point numbers in
Java.
Keyword |
Type |
Range |
float |
32-bit float |
-2^24E-149 to 2^24E104 |
double |
64-bit float |
-2^53E-1045 to 2^53E1000 |
The following example shows how a floating-point number might be used:
float temperature; temperature = 82.3;
The difference between the two is that the double type has more precision and can thus hold more decimal places. Most of the time it makes sense to stick with the float type, which is what most programmers do. The range for this type is quite large and
needs to be indicated using scientific notation with a mantissa. A mantissa is the number following the E. It is the power of 10 to multiply the first part of the number by. For example, 100 would be 1.0E2, 200 would be 2.0E2, and 1,000 would be
1.0E3.
When deciding whether to use an integer or a floating-point number in an application, keep these things in mind:
A character is basically anything that can be typed on a keyboard: a letter(like a, b, or c), a single-digit number( 1, 2 ,3), or non-alphanumeric character(#, $, %).
Keyword |
Type |
Range |
char |
16-bit integer |
Any Unicode character |
The following is an example of how the character type could be used:
char letter_grade; letter_grade = 'B';
Java differs slightly from other languages by including support for Unicode. Unicode is a standard that allows characters in languages other than English to be supported. Although support for this standard is not important to most people at the current
time, it means that your applets can be used internationally without a complete rewrite. Think of Unicode as the new ASCII, but with the ability to handle foreign characters.
In programming, comparisons between two things happen constantly. Decisions for what the program should do next are based upon on whether the result of a question was true or false. A variable containing a true or false value is known as a boolean. A
boolean could be represented with an integer by using a 0 for false and a 1 for true(C programs usually use this method), but that method makes programs much harder to read. Java includes native support for booleans.
Keyword |
Type |
Range |
boolean |
boolean |
true or false |
The following is an example of the boolean type in use:
boolean ready; ready = false;
Booleans can only hold two values: true or false. They are not only useful for remembering what the value of a comparison was, but also to keep track of the current state of your program. For instance, you may have a Slideshow applet that cycles through
images automatically if the Cycle button is pressed. You could then have a boolean called cycle that is changed to true or false when the button is pressed.
An expression is the most fundamental operation in Java. Expressions are how work on and comparisons with basic data types are done. They are operations that result in a value. The following are some examples of expressions:
6 + (10 / 5) // Returns the value of dividing 10 by five then adding six to the result. (37 / 10) * (82 - 3) // Returns the value of dividing 37 by 10 and then multiplying it by the result of 82 minus 3. (value == 10) // Returns true if value is equal to 10. (2 < 4) && (value != 4) // Returns true if 2 is less than four and the variable value does not equal 4.
Note that expressions are not listed with semicolons after them because by themselves they are meaningless; their result must be used for something (like a variable assignment).
Expressions are built out of operators and operands. The three main classes of operators are arithmetic, relational, and logical. An operand is the data that the operator does its work upon. For instance, in the expression 2 + 4, the plus sign
(+) is the operator, and the numbers 2 and 4 are the operands.
Java uses infix notation with arithmetic operators, which means that the operators appear between the numbers (or variables). This notation should be quite familiar to youit's the way math is usually written down, as shown in the following
examples:
int result = 2 + 2 * 10; // result = 22 int x = 10 / 4; // x = 2 int y = 10 * 10; // y = 100
If you want to make sure certain operations are done first, use parentheses. For example, if you wanted to multiply 10 by the result of adding 2 plus 2 but were unsure of the rules of precedence (which operations occur before others), you could write
(2 + 2) * 10;
instead of
2 + 2 * 10
The parentheses would guarantee you that 2 would be added to 2 before it was multiplied by 10. If you are unsure of what operation takes precedence in an expression, go ahead and group parentheses around the operation you want to happen first.
Table 8.1 lists the common arithmetic operators in Java. The four major operations are obvious, but remainder, decrement, and increment need a bit more explanation.
Operator |
Action |
+ |
Addition |
- |
Subtraction |
* |
Multiplication |
/ |
Division |
% |
Remainder |
-- |
Decrement |
++ |
Increment |
When two numbers are divided by one another, there is often a remainder. When you use floating-point numbers, this remainder is included in the numbers that follow the decimal point. However, when you do integer division, this remainder is lost. For
example in,
int result = 7 / 3;
result is equal to 2, but the information that 1 was left over is lost. The Remainder operator (%) allows the remainder to be computed. Thus in,
int result = 7 % 3;
is equal to 1 because that is what is left over when 7 is divided by 3.
Addition and subtraction are operations that are done constantly in programming. In fact, 1 is added to or subtracted from a variable so often that this expression has its own operators: increment and decrement. The operator ++ adds (increments) 1 to
its operand and -- subtracts (decrements) 1 from its operand. Therefore, the code
age++;
is equivalent to
age = age + 1;
Increment and decrement are special operators. Normally an operator couldn't appear by itself because it needs to be part of an expression. This rule is purposely broken with incrementing and decrementing, mainly in order to save typing.
A relational operator is basically a way to compare two things to find out how they relate to one another. For example, you can check to see whether two things are equal to one other or whether one is greater than the another. Table 8.2 lists the
available relational operators.
For example, to check to see whether age is equal to 16, you would use the == operator:
boolean is_sixteen = (age > 21);
If this expression is true, then the boolean value true is assigned to is_sixteen, otherwise false. Note that this is very different than the assignment operator, which is a single equal sign. The assignment operator = sets the value of the variable to
the left to the value of the expression on the right, whereas the equal relational operator == checks to see whether the value on the left is equivalent to the value on the right, and if it is, returns true.
Operator |
Action |
> |
Greater than |
< |
Less than |
>= |
Greater than or equal |
<= |
Less than or equal |
== |
Equal |
!= |
Not equal |
Quite often it is convenient to be able to do multiple relational tests at the same time. Logical operators (listed in Table 8.3) make this process possible.
Operator |
Action |
&& |
And |
|| |
Or |
! |
Negation |
The And (&&) operator returns true only if both of its operands are true. Thus,
(2 == 2) && (3 < 4)
evaluates to true, because 2 is equal to 2 and 3 is in fact less than 4. On the other hand,
(2 == 2) && (3 == 4)
evaluates to false because 3 is not equal to four. In this case, one of the operands is false so the whole expression is false.
The Or operator (||) is similar except that it evaluates to true if either of its operands are true. Therefore,
(2 == 2) && (3 == 4)
evaluates to true because (2 == 2) is true.
The Negation (!) operator is a bit strange. It takes its operand, which must be a boolean, and gives the opposite boolean value. Therefore, what was true is now false, and what was false is now true. For example,
!(2 == 2)
is false because (2 == 2) evaluated to true, and the opposite of true is false.
The Negation operator is powerful, but it should also be used with care because it can be very confusing to figure out what expressions that contain it mean. You should use this operator only when the meaning of the expression is clear.
When declaring variables, it makes sense to have distinct names for them, up to a point. However, suppose you are writing a gradebook program, and you need to keep scores for 50 people in the class. You could have a variable for each: student1,
student2, student3, and so on. This amount of variables would get quite unwieldy.
Arrays are the solution. They allow you to group what would be a large number of different variables with the same type under one name. Arrays enable you to keep things simple when you have a large number of variables that can be grouped together. An
array is declared in the following manner:
int students[]; students = new int[50];
First, you specify the type of variable that will be contained in the array, which in this case is an integer.
Then you name the array (in this case students) and follow it with [], which tells the compiler that this code is an array.
At this point, you have declared that students will be an array, but you haven't declared how many items will be in it. The next line does that operation:
students = new int[50];
This statement creates an array of 50 integers. Then this array of integers is assigned to the variable students, which is functioning as an array reference in the preceding line of code. This notion of declaring a variable that is a reference and then
needing to use new to create instances of this type is a new and important concept, which will be discussed in Chapter 9.
When you first declare the array (students in the preceding example), all you are doing is saying, "This variable will at some point contain an array." That is why the number is not listed in the first declaration of students, but later when
the actual array is created.
The number in the square brackets ([])that come after new are an index, which is the fundamental thing that separates arrays from other data types. The index of an array is an integer in the range from 0 to the size of the array minus one. For instance,
the Students array can be referenced by any of the following:
students[0] students[1] students[2] ... students[49]
Each indexed reference to students[] is called an array element and can be treated in exactly the same way as any other variable of a basic data type. The index does not necessarily have to be a constant number; it can also be a variable, as in the
following:
students[current value]
When using arrays, keep in mind that you start counting with them at 0 and end at one less than the number of elements in the array. In the Students array, for example, if you forgot that for a 50 element array the last valid index was 50 you might try
the following,
......students[50]
which would not be a valid reference. Forgetting this counting scheme isn't quite as big a problem in Java as it is in other languages. In C, trying to reference an element of the array that does not exist can cause the program (and all too often the
computer) to crash. Java is much more forgiving; it simply generates a message that an array has been referenced out of bounds.
The handling of array reference problems is a good example of how Java, although not necessarily easy to program in, is much more friendly than most other programming languages. Sun realized that programming languages tended to be far too unforgiving
about handling errors and made sure Java wasn't. Errors in programming are a fact of life, but, more often than not, when your program careens out of control, Java gives you a concise and helpful message about why.
In Java, each conceptual step of the program is known as a statement. For example, both a variable declaration and a variable assignment like the following are statements:
int age; age = 100;
A statement is followed by a semicolon to let the compiler know that the statement has ended.
A block is an arbitrary number of statements that are grouped together. The beginning and ending of the block are marked by opening and closing braces, { and } respectively. The following code shows the preceding statements contained within a
block:
{ int age; age = 100; }
Blocks are used a great deal throughout the rest of the book. You have already seen them in the HelloWorld applet example from Chapter 7, and they are also an integral part of defining object classes in Chapter 9. Most importantly for now, they are also
used a great deal in controlling the flow of a program, which is discussed in the next section.
You now know how to represent data in Java. That's half the battle. The second half is keeping control of the program. Java statements are executed in a linear order, one after another. Flow control statements, as explained in the following sections,
let you modify that order.
One of the most basic things a program needs to do is to make decisions. Test statements check the result of a boolean relational expression (discussed earlier in this chapter) and decide in which manner the program will continue based upon the result
of this expression.
By far, the most important test statement is if. An if statement has the following form:
if (Expression) ThingsToDoIfTrue else ThingsToDoIfFalse
If the expression is true, the block (or statements) contained in ThingsToDoIfTrue is executed. If the expression is false, the block (or statements) contained in ThingsToDoIfFalse contained after the else is executed. If you just
need to do something if the expression is true, the else can be left off.
Suppose you wanted to add 1 to a variable named counter only if the boolean variable add_one is set to true; otherwise, you wanted to subtract 1 from the variable. The following example does this:
boolean add_one; int counter; add_one = true; counter = 1; if (add_one == true) counter = counter + 1; else counter = counter - 1;
In this example, counter ends up being equal to 2. Why? The expression in the if statement is evaluated first. The program checks to see whether add_one is equal to the boolean value true. In this case, the add_one variable is true, so the program
evaluates the second part of the if statement, which adds 1 to counter. If the add_one variable were not true, the statement(s) following the else would have been executed.
Java enables you to repeat something over and over again through a construct known as iteration statements. An iteration statement executes a block of code based on whether an expression is true.
This process is known as looping. A loop occurs in a program when a single block of code is executed more than once. A loop can be set to repeat a definite number of times(a for loop) or a variable number of times(a while or do. . .while loop).
A for loop repeats a program block a finite number of times based upon a counter. The following sample for loop repeats 10 times:
for (int i=0; i<10; i = i + 1) { // Things you want to do }
The for loop has three main components:
A semi-colon is required at the end of components 1 and 2, to tell the Java compiler that this is where the component ends.
For loops make the most sense when you know ahead of time how many times the loop will need to be executed. For example, if you had a variable result that you wanted to multiply by 3 for 20 times, you could use the following:
for (int i=0; i<20; i = i + 1) { result = result * 3; }
A while loop is a much more general loop than a for loop. A while loop decides whether to evaluate the loop again based upon whether its expression is true or false. The while loop evaluates the expression again if the result is true and doesn't
evaluate the expression again if its result is false. The following example only executes once because value is changed to false once the loop is entered:
boolean value; value = true; while (value == true) { // Do some work value = false; }
Note that a while loop isn't necessarily executed even once, as the following example demonstrates:
boolean value; value = false; while (value == true) { // Do some work value = false; }
In this case, the while expression is evaluated and is found to be false right from the beginning, so the code inside the loop is never executed.
A do. . .while loop is much like a while loop except that the expression to be tested is contained at the end of the loop rather than at the beginning:
boolean value; value = true; do { // Do some work value = false; } while (value == true)
Note that in this case the program block is always executed at least once. There is no effect if you make the same sort of change that was made to the while loop:
boolean value; value = false; do { // Do some work value = false; } while (value == true)
The net effect of changing value so it starts out as false is zero. It is set again to false at the end of the block and then the loop does not repeat. Thus the assignment inside the loop is superfluous. In general, you should decide between a while and
a do. . .while loop based upon whether the test to see whether the loop needs to continue fits more naturally at the beginning or the end of the loop.
If you come from a C or C++ background, you may be wondering why pointers haven't been mentioned. That's because there are no pointers in Java. The designers of Java came to the conclusion that not only do pointers cause severe security problems in
applets, but they also are generally felt to be by far the most difficult thing about programming in C and C++.
The closest thing that Java has to a pointer is a reference to an array (or, as you will see in the next chapter, an object). Like a pointer, an array reference has no value when first created, but it is then set to a value that is created later.
However, there is only one way to reference variables when they are created this way, and cryptic operations like pointer arithmetic aren't supported.
If you don't know what a pointer is, count yourself lucky! Hopefully, you never will.
You are now familiar with the core syntax of Java. You can make variables, arrays, and expressions and control the flow of a program through if statements and for and while loops. A great deal of material in this chapter isn't very exciting, but it
gives you the background to lead into the next chapter on the exciting topic of object-oriented programming.