Classes are the major constructs in Java, but you need to know smaller elements that help you program the behavior and flow of the program. You need to know how commented your program so other people can understand your intentions (programmers often work in teams and help each other). You need to know how to write code that will invoke one method or the other depending on certain conditions. In this chapter I’ll show you some Java elements that you have to know and apply in pretty much any project.
You can add any text comments to your program to explain what a particular line, method or class is for. First of all, someone else may read your program so comments would help in understanding your intentions. Second, even the author of the code can’t remember every program he or she wrote. Besides, if a professional programmer decides to change the employer, if would be nice to leave well-commented code behind.
There are three different types of comments - single-line comments, block comments, and a javadoc comments. Here’s what they are for:
If your comment fits in one line, start it with two slashes:
// This method calculates the distance between A and B.
If you want to write multi-line comments, instead of starting each line with two slashes, just surround the entire text with these symbols: /*
and */
, for example:
/* Now we'll handle the current
position of the Fish.
*/
Java comes with a special program javadoc
that can extract all comments from your programs into a separate help file that can be displayed by any Web browser. This file can be used as a technical documentation for your programs. Such comments are enclosed in symbols /**
and */
. Note the two asterisks after the first slash. Only the most important comments like the description of a class or a method should be placed between these symbols.
/** This method calculates the discount that depends
on the price paid. If the price is more than $100,
give the user 20% off, otherwise only 10%.
*/
The javadoc tool can process your code, extract all comments that start with /**
and create program documentation that can be published online or kept locally on the company server. We are not going to use javadoc in this book, but if you’re interested in learning more about this tool, read Oracle’s tutorial How to Write Doc Comments for the Javadoc Tool.
From now on, I’ll be adding comments to code samples to give you a better idea how and where to use them.
We always make decisions in our life: If she is going to tell me this – I’m going to answer that, otherwise I’ll do something else. You can write a Java program that will "make decisions" with the help of if
and switch
statements. You can also build more complex either-or conditions using logical operators.
Java has an if
statement that checks if a particular expression is true
or false
.
Based on the result of evaluating this expression, your program execution forks, and only the relevant portion of the code will be invoked.
For example, if the expression Do I want to go to grandma’s? is true
, turn to the left, otherwise turn to the right.
Take a look at the following code sample. If an expression inside the parentheses is true
, JVM will execute the code between the first pair of curly braces, otherwise it goes to the code after the else
statement. In other words, if the value of the variable totalSpent
is more than a hundred, give a 20% discount, otherwise take only 10% off.
// Assume that the method getTotalAmount()
// adds up the prices from your shopping cart
int totalSpent = getTotalAmount();
float discountedPrice;
if (totalSpent > 100){
discountedPrice=totalSpent*0.8;
System.out.println("You’ll get a 20% discount");
}
else{
discountedPrice=totalSpent*0.9;
System.out.println("You’ll get a 10% discount");
}
System.out.println("Your discounted price is " + discountedPrice);
Let’s modify the method dive()
in the class Fish
from Chapter 3 to make sure that our fish is not allowed to dive below 100 feet:
public class Fish extends Pet {
int currentDepth=0;
public int dive(int howDeep){
currentDepth=currentDepth + howDeep;
if (currentDepth > 100){
System.out.println("I am a little fish and "
+ " can't dive below 100 feet");
currentDepth=currentDepth - howDeep;
}else{
System.out.println("Diving for " + howDeep +
" feet");
System.out.println("I'm at " + currentDepth +
" feet below the sea level");
}
return currentDepth;
}
public String talk(String something){
return "Don't you know that fish do not talk?";
}
}
Now just make a small change in the class FishMaster
– let it try to make our fish go deep under the sea:
public class FishMaster {
public static void main(String[] args) {
Fish myFish = new Fish();
// Try to have the fish go below 100 feet
myFish.dive(2); // go 2 feet down
myFish.dive(97); // go another 97 feet down
myFish.dive(3); // go 3 more feet down
myFish.sleep();
}
}
Run this program and it’ll print the following on the system console:
Diving for 2 feet.
I'm at 2 feet below the sea level.
Diving for 97 feet.
I'm at 99 feet below the sea level.
I am a little fish and can't dive below 100 feet.
Good night, see you tomorrow.
Sometimes, to make a decision you may need to check more than just one conditional expression, for example if the name of the state is Texas or California, add the state sales tax to the price of every item in the store. This is an example of the logical or – either Texas or California.
In Java the sign for a logical or
is one or two vertical bars. It works like this – if any of the two conditions is true
, the result of the entire expression is also true
.
In the following examples I use a variable of type String
, which has a method equals()
that compares the values of two strings. I use it to see whether the value of the variable state
is "Texas" or "California":
if (state.equals("Texas") | state.equals("California"))
{
// do something
}
You can also rewrite this if
statement using two vertical bars:
if (state.equals("Texas") || state.equals("California"))
{
// do something
}
The difference between these two examples is that if you use two bars, and the first expression is true
, the second expression won’t even be checked. If you place just a single bar, JVM will evaluate both expressions.
The logical and is represented by one or two ampersands (&&
) and each expression in the parentheses must be true
to make the entire expression true
. For example, charge the sales tax only if the state is New York and the price is more than $110. Both conditions must be true
at the same time:
if (state.equals("New York") && price >110)
{
// do something
}
or
if (state.equals("New York") & price >110)
{
// do something
}
If you use double ampersand and the first expression is false
, the second one won’t even be checked, because the entire expression will be false
anyway. With the single ampersand both expressions will be evaluated.
The logical not is also known as negation
and is represented by the exclamation point. The logical not changes expression to the opposite meaning. For example, if you want to perform some actions only if the state is not New York, use this syntax:
if (!state.equals("New York")) {
// do something
}
The following two expressions will produce the same result, because more than 50 and not less than or equal to 50 have the same meaning:
if (price > 50) {
// do something
}
if (!(price <= 50)) {
// do something
}
In the second example the logical not is applied to the expression in parentheses.
There is another type of an if-statement called conditional operator, which allows you to assign a value to a variable based on the expression that ends with a question mark. It’s like you’re asking, "Is this true?". If such an expression is true
, the value after the question mark is used, otherwise the value after the colon is assigned to the variable on the left:
discount = price > 50? 10:5;
If the price is greater than fifty, the variable discount
will get a value of 10, otherwise discount
will have a value of 5. It’s just a shorter replacement of the following if statement:
if (price > 50){
discount = 10;
} else {
discount = 5;
}
You are also allowed to build more complex if
statements with several else if
blocks. To illustrate this technique let’s create a new class called ReportCard
. This class will have two methods: main()
and convertGrades()
with one argument - the school test result. Depending on the number, it should print your grade like A, B, C, or D.
public class ReportCard {
String studentName;
/**
The method convertGrades has one integer argument - the result of the school test. The method returns one letter A, B, C or D depending on the argument's value.
*/
public char convertGrades( int testResult){
char grade;
if (testResult >= 90){
grade = 'A';
} else if (testResult >= 80 && testResult < 90){
grade = 'B';
}else if (testResult >= 70 && testResult < 80){
grade = 'C';
}else {
grade = 'D';
}
return grade;
}
public static void main(String[] args){
ReportCard rc = new ReportCard();
char yourGrade = rc.convertGrades(88);
System.out.println("Your first grade is " +
yourGrade);
yourGrade = rc.convertGrades(79);
System.out.println("Your second grade is " +
yourGrade);
}
}
Beside using the else if
condition, this example also shows you how to use variables of type char
. You can also see that with the &&
operator you can check if a number falls into specific range. You can not just write if testResult between 80 and 89, but with logical and you can check the condition when testResult
is greater than or equal to 80 and less then 89 at the same time:
testResult >= 80 && testResult < 89
Take a guess as to why we could not use the logical or operator here? Say the testResult
is 100. It’s greater than 80, and the above expression would evaluate to true, because for the || operator having one true
is enough to make the entire expression true. But this is not what we want - we need the above expression to be true only if the value of testResult
is between 80 and 89. The logical and operator does the job by ensuring that both conditions are true.
The switch
statement sometimes can be used as an alternative to if
. The variable after the keyword switch
is evaluated, and program goes only to one of the case
statements:
public static void main(String[] args){
ReportCard rc = new ReportCard();
rc.studentName = "Jerry Lee";
char yourGrade = rc.convertGrades(88);
switch (yourGrade){
case 'A':
System.out.println("Excellent Job!");
break;
case 'B':
System.out.println("Good Job!");
break;
case 'C':
System.out.println("Need to work more!");
break;
case 'D':
System.out.println("Change your attitude!");
break;
}
// Some other program code goes here
}
Say, the value of yourGrade
is B
. Then the above code will print "Good Job!" and will break out of the switch
statement to continue executing the rest of the program code if any.
Do not forget to put the keyword break
at the end of each case
statement to make the code jump out of the switch
. For example, if you forget to put the break
in the case 'B'
block, the above code would print "Good Job!" followed by "You need to work more!".
Class ReportCard
declares a variable grade
inside the method convertGrades()
. If you declare a variable inside any method, such variable is called local. This means that this variable is available only for the code within this method. When the method is complete, this variable automatically gets removed from memory.
Programmers use the word scope to say how long a variable will live, for example you can say that variables declared inside a method have a local scope. If a variable is declared within the code block surrounded with curly braces (e.g. in the if statement), it has a block scope and won’t be visible outside of this block.
If a variable has to be reused by several method calls, or it has to be visible from more than one method in a class, you should declare such a variable outside of any method. In the class Fish
from Chapter 3, the currentDepth
is a member variable. The member variable currentDepth
is alive until the instance of the object Fish
exists in the computer’s memory. You can call currentDepth
a instance variable, because its declaration doesn’t include the keyword static
, which we’ll discuss shortly.
Member variables can be shared and reused by all methods of the class, and we can make them visible from external classes too, if need be. For example the method main
of the class ReportCard
includes the statement System.out.println()
. It uses the class variable out
that was declared in the Java class System
.
Wait a minute! Can we use a member variable out
from the class System
if we haven’t even created an instance of this class? Yes we can, if the class System
declares the variable out
with a keyword static
.
When you start any Java program it loads the definition of the required classes in memory. The definition of a class can be used for creation of one or more instances of this class. For example:
ReportCard rc = new ReportCard();
rc1.studentName = "Jerry Lee";
ReportCard rc2 = new ReportCard();
rc2.studentName = "Sarah Smith";
In this example we have two instances of the class ReportCard
, and each of them has its own value in the variable studentName
, which is an instance variable. Now, let’s change the declaration of this variable by adding the keyword static
:
static String studentName;
In this case both instances of the ReportCard
would share the same variable studentName
, and the above code would first assign "Jerry Lee" to this variable, and then it would be replaced with "Sarah Smith". This doesn’t seem like a good idea does it?
Moreover, if the declaration of a member variable or a method starts with static
, you do not have to create an instance of this class to use such a variable or a method. Static members of a class are used to store the values that are the same for all instances of the class.
For example, the method convertGrades
should be declared as static
in the class ReportCard
, because its code does not use member variables to store values specific to a particular instance of the class.
public static char convertGrades( int testResult){
// the code of this method goes here
}
There is no need to create instances to call static methods or access static variables. Just write the name of the class followed by the dot and the name of the static member:
char yourGrade = ReportCard.convertGrades(88);
Here’s another example: Java has a class Math
that contains several dozen mathematical methods like sqrt
, sin
, abs
and others. All these methods are static
and you do not need to create an instance of the class Math
to invoke them, for example:
double squareRoot = Math.sqrt(4.0);
You’ve already learned that Java uses the operator new
to create instances of objects in memory, for example:
Fish myFish = new Fish();
Parentheses after the word Fish
tell us that this class has some method called Fish
. Yes, there are special methods that are called constructors, and these methods have the following features:
-
Constructors are special methods that are called only once during construction of the object in memory.
-
They must have the same name as the class itself.
-
They do not return a value, and you do not even have to use the keyword
void
in the constructor’s declaration.
Any class can have more than one constructor. If you do not create a constructor for the class, Java automatically creates one during the compilation time - it’s so-called default no-argument constructor. That’s why Java compiler has never complained about the statements new Fish()
or new ReportCard()
, even though neither class Fish
nor class ReportCard
has any explicitly declared constructor.
In general, constructors are used to assign initial values to member variables of the class, for example the next version of the class Fish
has a one-argument constructor that just assigns the argument’s value to the instance variable currentDepth
for future use.
public class Fish extends Pet {
int currentDepth;
// This is constructor
Fish(int startingPosition){
currentDepth=startingPosition;
}
}
Now the class FishMaster
can create an instance of the Fish
and assign the initial position of the fish. The next example creates an instance of the Fish
that is “submerged” 20 feet under the sea:
Fish myFish = new Fish(20);
If a constructor with arguments has been defined in a class, you can no longer use the default no-argument constructor. If you’d like to have a constructor without arguments - write one.
The keyword this
is useful when your code needs to refer to the instance of the object, where this code is running. Look at the next code example, which is a slight modification of the previous one:
class Fish {
int currentDepth ;
Fish(int currentDepth){
this.currentDepth = currentDepth;
}
}
Have you noticed that the member variable and the constructor’s argument have the same name? The keyword this
helps to avoid name conflicts. In this code sample this.currentDepth
refers to the object’s member variable currentDepth
, while the currentDepth
refers to the argument’s value. In other words, the code points at the current instance of the Fish
object.
You’ll see another important example of using the keyword this
in Chapter 6 in the section How to Pass Data Between Classes.
An array is an object that holds several values of the same type - primitives or objects. Let’s say your program has to store the names of four game players. Instead of declaring four different String
variables, you can declare one String
array that has four elements. Arrays are marked by placing square brackets either after the variable name, or after the data type:
String [] players;
or
String players[];
These declarations just tell the Java compiler that you are planning to store several text strings in the array players
. Each element has its own index (position number) starting from zero. The next sample actually creates an instance of an array that can store four String
elements and assigns the values to the elements of this array:
players = new String [4];
players[0] = "David";
players[1] = "Daniel";
players[2] = "Anna";
players[3] = "Gregory";
You must declare the size of the array before assigning values to its elements. If you do not know in advance how many elements you are going to have, you cannot use arrays, but you should look into other classes - Java collections. For example the ArrayList
object does not require you to announce the exact number of elements in advance. I’ll show you some examples of using the ArrayList
collection in Chapter 10 about data collections.
Any array has an attribute called length
that stores the number of elements in this array, and you can always find out how many elements are there:
int totalPlayers = players.length;
If you know all the values that will be stored in the array at the time when you declare it, Java allows you to declare and initialize such array in one shot:
String [] players = {"David", "Daniel", "Anna", "Gregory"};
Imagine that the second player is a winner and you’d like to write the code to congratulate this kid. If the players’ names are stored in an array get its second element:
String theWinner = players[1];
System.out.println("Congratulations, " + theWinner + "!");
The output from these two lines of code will look like this:
Congratulations, Daniel!
Do you know why the second element has the index [1]? Of course you do, because the index of the first element is always [0].
The array of players in our example is called one-dimensional array. Imagine the players sitting like ducks in a row. The single dimension is the seat number here. If the players (or game spectators) will occupy several rows, then we’ll have two dimensions - the row number and a set number within the row. This is the case where we’d need to declare a two-dimensional array. Java allows creation of multi-dimensional arrays, and I’ll show you how to do this in Chapter 10.
A loop is a language construct that allows to repeat the same action multiple times. For example, if we need to print congratulation to several winners, the printing code should be invokes several times in a loop. When you know in advance how many times this action has to be repeated, you can use a loop with a keyword for
:
int totalPlayers = players.length;
int counter;
for (counter=0; counter < totalPlayers; counter++){
String thePlayer = players[counter];
System.out.println("Congratulations,"+
thePlayer+"!");
}
The above code means the following:
Print the value of the element from the players
array whose number is the same as the current value of the counter
. Start from the element number 0: _ counter=0)
, _and increment the value of the counter
by one: (counter++)
. Keep doing this while the counter
is less than totalPlayers`: `counter<totalPlayers
.
JVM executes every line between the curly braces and then returns back to the first line of the loop to increment the counter and check the conditional expression.
There is another flavor of the for
loop known as for each loop. It allows the program to repeat the same action to every element of the collection without even knowing how many are there. You are basically saying, do this for each element.The for-each loop allows to congratulate players in a more concise manner:
for (String pl: players){
System.out.println("Congratulations," + pl +"!");
}
You can read the above code as follows:
The variable pl
has the type String
- the same as as the array’s elements. Use this variable as a cursor, point it to each element in the array players
one by one and repeatedly execute the code inside the curly brackets for the current element.
There is another keyword for writing loops - while
. In these loops you do not have to declare exactly how many times to repeat the action, but you still need to know when to end the loop. Let’s see how we can congratulate players using the while
loop that will end when the value of the variable counter
becomes equal to the value of totalPlayers
:
int totalPlayers = players.length;
int counter=0;
while (counter< totalPlayers){
String thePlayer = players[counter];
System.out.println("Congratulations, "
+ thePlayer + "!");
counter++;
}
In Chapter 9 you’ll learn how to save the data on the disk and how to read the saved data back into computer’s memory. If you read game scores from the disk file, you do not know in advance how many scores were saved there. Most likely you’ll be reading the scores using the while
or for-each loop, which don’t require you to state the number of iterations upfront.
You can also use two important keywords with loops: break
and continue
.
As with switch
statements, the keyword break
is used to jump out of the loop when some particular condition is true
. Let’s say we do not want to print more than 3 congratulations, regardless of how many players we’ve got. In the next example, after printing the array elements 0, 1 and 2, the break
will make the code go out of the loop and the program will continue from the line after the closing curly brace.
The next code sample has the double equal sign ==
in the if
statement. This means that you are comparing the value of the variable counter
with number 3. A single equal sign in the here would mean assigning the value of 3 to the variable counter
. Placing =
in an if
statement instead of ==
is a very tricky mistake, and it can lead to unpredictable program errors that may be dificcult to find.
int counter =0;
while (counter< totalPlayers){
if (counter == 3){
break; // Jump out of the loop
}
String thePlayer = players[counter];
System.out.println("Congratulations, "+thePlayer+ "!");
counter++;
}
The keyword continue
allows the code to skip some code lines and return back to the beginning of the loop. Imagine that you want to congratulate everyone but David – the keyword continue
will return the program back to the beginning of the loop:
while (counter< totalPlayers){
counter++;
String thePlayer = players[counter];
if (thePlayer.equals("David"){
continue;
}
System.out.println("Congratulations, "+ thePlayer+ !");
}
There is yet another type of the while
loop that starts with the word do
, for example:
do {
System.out.println("Congratulations, "+
players[counter] + !");
counter++;
} while (counter< totalPlayers);
Such loops check an expression after executing the code between curly braces, which means that code in the loop will be executed at least once. Loops that start with the keyword while
might not be executed at all if the loop expression is false
to begin with.
-
Create a new IntelliJ Idea Java project as described in Chapter 2. Name it
Chapter4
. -
In the src directory of the project create a new class (the menu File | New) named TemperatureConverter.
-
Add the method
convertTemp()
so the code of the class looks like this:public class TemperatureConverter { public static float convertTemp (float temperature, char convertTo) { } }
-
Write the if statement inside the method
convertTemp
to check the value of the argumentconvertTo
. If it’sF
, the temperature has to be converted to Fahrenheit, and if it’sC
, convert it to Celsius. Return the result. The methodconvertTemp
should look like this:public static String convertTemp (float temperature, char convertTo) { if (convertTo=='F'){ return "The temperature in Fahrenheit is " + (9*temperature/5 + 32); } else if(convertTo=='C') { return "The temperature in Celsius is " + (temperature - 32) * 5/9; } else{ return "You can enter either F or C as convertTo argument"; } }
-
Add the method
main
using the shortcut psvm + Tab as explained in Chapter 2. It should look like this:public static void main(String[] args) { System.out.println("Converting 21C to Fahrenheit. " + convertTemp(21,'F')); System.out.println("Converting 70F to Celsius. " + convertTemp(70,'C')); }
-
Run the program
TemperatureConverter
using the IDEA menu Run | Run TemperatureConverter. If you did everything right, you should see the following output on the IDEA console:Converting 21C to Fahrenheit. The temperature in Fahrenheit is 69.8 Converting 70F to Celsius. The temperature in Celsius is 21.11111
-
Do a little research to change this program so it always prints the temperature with two digits after the decimal point. Study Oracle’s tutorial about formatting numeric output: http://goo.gl/3riLIZ.