Skip to content

Latest commit

 

History

History
636 lines (454 loc) · 28.7 KB

Chapter_4.adoc

File metadata and controls

636 lines (454 loc) · 28.7 KB

Java Building Blocks

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.

Program Comments

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.

Making Decisions

We always make decisions in our life: If she is going to tell me thisI’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.

The if Statement

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.

fig 4 01
Figure 1. The fork

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.

Logical Operators

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.

Conditional operator

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;
}

Using else if

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

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!".

fig 4 02
Figure 2. The switch statement

How Long Will A Variables Live?

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.

The Keyword static

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);

Special Methods: Constructors

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

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.

fig 4 03
Figure 3. I’m this object

You’ll see another important example of using the keyword this in Chapter 6 in the section How to Pass Data Between Classes.

Arrays

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"};

fig 4 04
Figure 4. The array of players

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.

Repeating Actions with Loops

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.

Challenge Yourself

  1. Create a new IntelliJ Idea Java project as described in Chapter 2. Name it Chapter4.

  2. In the src directory of the project create a new class (the menu File | New) named TemperatureConverter.

  3. Add the method convertTemp() so the code of the class looks like this:

    public class TemperatureConverter {
        public static float convertTemp (float temperature,
                                   char convertTo) {
        }
    }
  4. Write the if statement inside the method convertTemp to check the value of the argument convertTo. If it’s F, the temperature has to be converted to Fahrenheit, and if it’s C, convert it to Celsius. Return the result. The method convertTemp 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";
            }
        }
  5. 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'));
    
        }
  6. 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
  7. 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.