O'Reilly logo

Head First Java, 2nd Edition by Bert Bates, Kathy Sierra

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Writing a Program: Extra-Strength Methods

image with no caption

Let’s put some muscle in our methods. We dabbled with variables, played with a few objects, and wrote a little code. But we were weak. We need more tools. Like operators. We need more operators so we can do something a little more interesting than, say, bark. And loops. We need loops, but what’s with the wimpy while loops? We need for loops if we’re really serious. Might be useful to generate random numbers. And turn a String into an int, yeah, that would be cool. Better learn that too. And why don’t we learn it all by building something real, to see what it’s like to write (and test) a program from scratch. Maybe a game, like Battleships. That’s a heavy-lifting task, so it’ll take two chapters to finish. We’ll build a simple version in this chapter, and then build a more powerful deluxe version in Chapter 6.

Let’s build a Battleship-style game: “Sink a Dot Com”

It’s you against the computer, but unlike the real Battleship game, in this one you don’t place any ships of your own. Instead, your job is to sink the computer’s ships in the fewest number of guesses.

Oh, and we aren’t sinking ships. We’re killing Dot Coms. (Thus establishing business relevancy so you can expense the cost of this book).

Goal: Sink all of the computer’s Dot Coms in the fewest number of guesses. You’re given a rating or level, based on how well you perform.

Setup: When the game program is launched, the computer places three Dot Coms on a virtual 7 x 7 grid. When that’s complete, the game asks for your first guess.

How you play: We haven’t learned to build a GUI yet, so this version works at the command-line. The computer will prompt you to enter a guess (a cell), that you’ll type at the command-line as “A3”, “C5”, etc.). In response to your guess, you’ll see a result at the command-line, either “Hit”, “Miss”, or “You sunk Pets. com” (or whatever the lucky Dot Com of the day is). When you’ve sent all three Dot Coms to that big 404 in the sky, the game ends by printing out your rating.

image with no caption

You’re going to build the Sink a Dot Com game, with a 7 x 7 grid and three Dot Coms. Each Dot Com takes up three cells.

part of a game interaction

image with no caption

First, a high-level design

We know we’ll need classes and methods, but what should they be? To answer that, we need more information about what the game should do.

First, we need to figure out the general flow of the game. Here’s the basic idea:

  1. User starts the game

    1. Game creates three Dot Coms

    2. Game places the three Dot Coms onto a virtual grid

  2. Game play begins

    Repeat the following until there are no more Dot Coms:

    image with no caption
  3. Game finishes

    Give the user a rating based on the number of guesses.

image with no caption

Now we have an idea of the kinds of things the program needs to do. The next step is figuring out what kind of objects we’ll need to do the work. Remember, think like Brad rather than Larry; focus first on the things in the program rather than the procedures.

The “Simple Dot Com Game” a gentler introduction

It looks like we’re gonna need at least two classes, a Game class and a DotCom class. But before we build the full monty Sink a Dot Com game, we’ll start with a stripped-down, simplified version, Simple Dot Com Game. We’ll build the simple version in this chapter, followed by the deluxe version that we build in the next chapter.

Everything is simpler in this game. Instead of a 2-D grid, we hide the Dot Com in just a single row. And instead of three Dot Coms, we use one.

The goal is the same, though, so the game still needs to make a DotCom instance, assign it a location somewhere in the row, get user input, and when all of the DotCom’s cells have been hit, the game is over. This simplified version of the game gives us a big head start on building the full game. If we can get this small one working, we can scale it up to the more complex one later.

image with no caption

In this simple version, the game class has no instance variables, and all the game code is in the main() method. In other words, when the program is launched and main() begins to run, it will make the one and only DotCom instance, pick a location for it (three consecutive cells on the single virtual seven-cell row), ask the user for a guess, check the guess, and repeat until all three cells have been hit.

Keep in mind that the virtual row is... virtual. In other words, it doesn’t exist anywhere in the program. As long as both the game and the user know that the DotCom is hidden in three consecutive cells out of a possible seven (starting at zero), the row itself doesn’t have to be represented in code. You might be tempted to build an array of seven ints and then assign the DotCom to three of the seven elements in the array, but you don’t need to. All we need is an array that holds just the three cells the DotCom occupies.

  1. Game starts, and creates ONE DotCom and gives it a location on three cells in the single row of seven cells.

    Instead of “A2”, “C4”, and so on, the locations are just integers (for example: 1,2,3 are the cell locations in this picture:

    image with no caption
  2. Game play begins. Prompt user for a guess, then check to see if it hit any of the DotCom’s three cells. If a hit, increment the numOfHits variable.

  3. Game finishes when all three cells have been hit (the numOfHits variable value is 3), and tells the user how many guesses it took to sink the DotCom.

A complete game interaction

image with no caption

Developing a Class

As a programmer, you probably have a methodology/process/approach to writing code. Well, so do we. Our sequence is designed to help you see (and learn) what we’re thinking as we work through coding a class. It isn’t necessarily the way we (or you) write code in the Real World. In the Real World, of course, you’ll follow the approach your personal preferences, project, or employer dictate. We, however, can do pretty much whatever we want. And when we create a Java class as a “learning experience”, we usually do it like this:

  • Figure out what the class is supposed to do.

  • List the instance variables and methods.

  • Write prepcode for the methods. (You’ll see this in just a moment.)

  • Write test code for the methods.

  • Implement the class.

  • Test the methods.

  • Debug and reimplement as needed.

  • Express gratitude that we don’t have to test our so-called learning experience app on actual live users.

Brain Power

Flex those dendrites.

How would you decide which class or classes to build first, when you’re writing a program? Assuming that all but the tiniest programs need more than one class (if you’re following good OO principles and not having one class do many different jobs), where do you start?

The three things we’ll write for each class:

image with no caption

This bar is displayed on the next set of pages to tell you which part you’re working on. For example, if you see this picture at the top of a page, it means you’re working on prepcode for the SimpleDotCom class.

image with no caption

prep code

A form of pseudocode, to help you focus on the logic without stressing about syntax.

test code

A class or methods that will test the real code and validate that it’s doing the right thing.

real code

The actual implementation of the class. This is where we write real Java code.

Note

To Do:

SimpleDotCom class

  • write prep code

  • write test code

  • write final Java code

SimpleDotComGame class

  • write prep code

  • write test code [no]

  • write final Java code

image with no caption

You’ll get the idea of how prepcode (our version of pseudocode) works as you read through this example. It’s sort of half-way between real Java code and a plain English description of the class. Most prepcode includes three parts: instance variable declarations, method declarations, method logic. The most important part of prepcode is the method logic, because it defines what has to happen, which we later translate into how, when we actually write the method code.

DECLARE an int array to hold the location cells. Call it locationCells.

DECLARE an int to hold the number of hits. Call it numOfHits and SET it to 0.

DECLARE a checkYourself() method that takes a String for the user’s guess (“1”, “3”, etc.), checks it, and returns a result representing a “hit”, “miss”, or “kill”.

DECLARE a setLocationCells() setter method that takes an int array (which has the three cell locations as ints (2,3,4, etc.).

image with no caption

Writing the method implementations

let’s write the real method code now, and get this puppy working

Before we start coding the methods, though, let’s back up and write some code to test the methods. That’s right, we’re writing the test code before there’s anything to test!

The concept of writing the test code first is one of the practices of Extreme Programming (XP), and it can make it easier (and faster) for you to write your code. We’re not necessarily saying you should use XP, but we do like the part about writing tests first. And XP just sounds cool.

image with no caption

Writing test code for the SimpleDotCom class

We need to write test code that can make a SimpleDotCom object and run its methods. For the SimpleDotCom class, we really care about only the checkYourself() method, although we will have to implement the setLocationCells() method in order to get the checkYourself() method to run correctly.

Take a good look at the prepcode below for the checkYourself() method (the setLocationCells() method is a no-brainer setter method, so we’re not worried about it, but in a ‘real’ application we might want a more robust ‘setter’ method, which we would want to test).

Then ask yourself, “If the checkYourself() method were implemented, what test code could I write that would prove to me the method is working correctly?”

Based on this prepcode:

METHOD String checkYourself(String userGuess)
 GET the user guess as a String parameter
 CONVERT  the user guess to an int
 REPEAT  with each of the location cells in the int  array
   // COMPARE the user guess to the location cell
   IF the user guess matches
        INCREMENT the number of hits
        // FIND OUT  if it was the last location cell:
        IF  number of hits is 3, RETURN  “Kill” as the result
        ELSE  it was not a kill, so RETURN“Hit”
        END IF
   ELSE the user guess did not match, so RETURN  “Miss”
   END IF
 END REPEAT
END METHOD

Here’s what we should test:

  1. Instantiate a SimpleDotCom object.

  2. Assign it a location (an array of 3 ints, like {2,3,4}).

  3. Create a String to represent a user guess (“2”, “0”, etc.).

  4. Invoke the checkYourself() method passing it the fake user guess.

  5. Print out the result to see if it’s correct (“passed” or “failed”).

Test code for the SimpleDotCom class

image with no caption

The checkYourself() method

There isn’t a perfect mapping from prepcode to javacode; you’ll see a few adjustments. The prepcode gave us a much better idea of what the code needs to do, and now we have to find the Java code that can do the how.

In the back of your mind, be thinking about parts of this code you might want (or need) to improve. The numbers are for things (syntax and language features) you haven’t seen yet. They’re explained on the opposite page.

image with no caption

Just the new stuff

The things we haven’t seen before are on this page. Stop worrying! The rest of the details are at the end of the chapter. This is just enough to let you keep going.

image with no caption

Final code for SimpleDotCom and SimpleDotComTester

public class SimpleDotComTestDrive {

   public static void main (String[] args) {
      SimpleDotCom dot = new SimpleDotCom();
      int[] locations = {2,3,4};
      dot.setLocationCells(locations);
      String userGuess = "2";
      String result = dot.checkYourself(userGuess);
   }
}
public class SimpleDotCom {

   int[] locationCells;
   int numOfHits = 0;

   public void setLocationCells(int[] locs) {
      locationCells = locs;
   }

   public String checkYourself(String stringGuess) {
      int guess = Integer.parseInt(stringGuess);
      String result = "miss";
      for (int cell : locationCells) {
         if (guess == cell) {
           result = "hit";
           numOfHits++;
           break;
         }
      } // out of the loop

      if (numOfHits ==
          locationCells.length) {
          result = "kill";
      }
      System.out.println(result);
         return result;
   } // close method
} // close class

There’s a little bug lurking here. It compiles and runs, but sometimes... don’t worry about it for now, but we will have to face it a little later.

Note

What should we see when we run this code?

The test code makes a SimpleDotCom object and gives it a location at 2,3,4. Then it sends a fake user guess of “2” into the checkYouself() method. If the code is working correctly, we should see the result print out:

java SimpleDotComTestDrive
hit
passed

Prepcode for the SimpleDotComGame class

Everything happens in main()

There are some things you’ll have to take on faith. For example, we have one line of prepcode that says, “GET user input from command-line”. Let me tell you, that’s a little more than we want to implement from scratch right now. But happily, we’re using OO. And that means you get to ask some other class/object to do something for you, without worrying about how it does it. When you write prepcode, you should assume that somehow you’ll be able to do whatever you need to do, so you can put all your brainpower into working out the logic.

public static void main (String [] args)
        DECLARE an int variable to hold the number of user guesses, named numOfGuesses, set it to 0.
        MAKE a new SimpleDotCom instance
        COMPUTE a random number between 0 and 4 that will be the starting location cell position
        MAKE an int array with 3 ints using the randomly-generated number, that number incremented by 1, and that number incremented by 2 (example: 3,4,5)
        INVOKE the setLocationCells() method on the SimpleDotCom instance
        DECLARE a boolean variable representing the state of the game, named isAlive. SET it to true

        WHILE the dot com is still alive (isAlive == true) :
          GET user input from the command line
          // CHECK the user guess
          INVOKE the checkYourself() method on the SimpleDotCom instance
          INCREMENT numOfGuesses variable
          // CHECK for dot com death
          IF result is “kill”
               SET isAlive  to false (which means we won’t enter the loop again)
               PRINT the number of user guesses
          END IF
      END WHILE
END METHOD

Metacognitive Tip

image with no caption

Don’t work one part of the brain for too long a stretch at one time. Working just the left side of the brain for more than 30 minutes is like working just your left arm for 30 minutes. Give each side of your brain a break by switching sides at regular intervals. When you shift to one side, the other side gets to rest and recover.

Left-brain activities include things like step-by-step sequences, logical problem-solving, and analysis, while the right-brain kicks in for metaphors, creative problem-solving, pattern-matching, and visualizing.

image with no caption

The game’s main() method

Just as you did with the SimpleDotCom class, be thinking about parts of this code you might want (or need) to improve. The numbered things are for stuff we want to point out. They’re explained on the opposite page. Oh, if you’re wondering why we skipped the test code phase for this class, we don’t need a test class for the game. It has only one method, so what would you do in your test code? Make a separate class that would call main() on this class? We didn’t bother.

image with no caption

random() and getUserInput()

Two things that need a bit more explaining, are on this page. This is just a quick look to keep you going; more details on the GameHelper class are at the end of this chapter.

  1. Make a random number

    image with no caption
  2. Getting user input using the GameHelper class

    image with no caption

One last class: GameHelper

We made the dot com class.

We made the game class.

All that’s left is the helper class—the one with the getUserInput() method. The code to get command-line input is more than we want to explain right now. It opens up way too many topics best left for later. (Later, as in Chapter 14.)

image with no caption

Just copy[4] the code below and compile it into a class named GameHelper. Drop all three classes (SimpleDotCom, SimpleDotComGame, GameHelper) into the same directory, and make it your working directory.

Whenever you see the logo, you’re seeing code that you have to type as-is and take on faith. Trust it. You’ll learn how that code works later.

Let’s play

Here’s what happens when we run it and enter the numbers 1,2,3,4,5,6. Lookin’ good.

A complete game interaction

(your mileage may vary)

image with no caption

What’s this? A bug?

Gasp!

Here’s what happens when we enter 1,1,1.

A different game interaction

(yikes)

image with no caption

More about for loops

We’ve covered all the game code for this chapter (but we’ll pick it up again to finish the deluxe version of the game in the next chapter). We didn’t want to interrupt your work with some of the details and background info, so we put it back here. We’ll start with the details of for loops, and if you’re a C++ programmer, you can just skim these last few pages...

Regular (non-enhanced) for loops

image with no caption

What it means in plain English: “Repeat 100 times.”

How the compiler sees it:

* create a variable i and set it to 0.

* repeat while i is less than 100.

* at the end of each loop iteration, add 1 to i

Part One: initialization

Use this part to declare and initialize a variable to use within the loop body. You’ll most often use this variable as a counter. You can actually initialize more than one variable here, but we’ll get to that later in the book.

Part Two: boolean test

This is where the conditional test goes. Whatever’s in there, it must resolve to a boolean value (you know, true or false). You can have a test, like (x >= 4), or you can even invoke a method that returns a boolean.

Part Three: iteration expression

In this part, put one or more things you want to happen with each trip through the loop. Keep in mind that this stuff happens at the end of each loop.

repeat for 100 reps:

image with no caption

Trips through a loop

for (int i = 0; i < 8; i++) {
   System.out.println(i);
}
System.out.println("done");
image with no caption

Difference between for and while

A while loop has only the boolean test; it doesn’t have a built-in initialization or iteration expression. A while loop is good when you don’t know how many times to loop and just want to keep going while some condition is true. But if you know how many times to loop (e.g. the length of an array, 7 times, etc.), a for loop is cleaner. Here’s the loop above rewritten using while:

image with no caption

output:

image with no caption

++ --

Pre and Post Increment/Decrement Operator

The shortcut for adding or subtracting 1 from a variable.

x++;

is the same as:

x = x + 1;

They both mean the same thing in this context: “add 1 to the current value of x” or “increment x by 1” And:

x--;

is the same as:

x = x - 1;

Of course that’s never the whole story. The placement of the operator (either before or after the variable) can affect the result. Putting the operator before the variable (for example, ++x), means, “first, increment x by 1, and then use this new value of x.” This only matters when the ++x is part of some larger expression rather than just in a single statement.

int x = 0;     int z = ++x;

produces: x is 1, z is 1

But putting the ++ after the x give you a different result:

int x = 0;     int z = x++;

produces: x is 1, but z is 0! z gets the value of x and then x is incremented.

The enhanced for loop

Beginning with Java 5.0 (Tiger), the Java language has a second kind of for loop called the enhanced for, that makes it easier to iterate over all the elements in an array or other kinds of collections (you’ll learn about other collections in the next chapter). That’s really all that the enhanced for gives you—a simpler way to walk through all the elements in the collection, but since it’s the most common use of a for loop, it was worth adding it to the language. We’ll revisit the enhanced for loop in the next chapter, when we talk about collections that aren’t arrays.

image with no caption

What it means in plain English: “For each element in nameArray, assign the element to the ‘name’ variable, and run the body of the loop.”

How the compiler sees it:

* Create a String variable called name and set it to null.

* Assign the first value in nameArray to name.

* Run the body of the loop (the code block bounded by curly braces).

* Assign the next value in nameArray to name.

* Repeat while there are still elements in the array.

Note

Note: depending on the programming language they’ve used in the past, some people refer to the enhanced for as the “for each” or the “for in” loop, because that’s how it reads: “for EACH thing IN the collection...”

Part One: iteration variable declaration

Use this part to declare and initialize a variable to use within the loop body. With each iteration of the loop, this variable will hold a different element from the collection. The type of this variable must be compatible with the elements in the array! For example, you can’t declare an int iteration variable to use with a String[] array.

Part Two: the actual collection

This must be a reference to an array or other collection. Again, don’t worry about the other non-array kinds of collections yet—you’ll see them in the next chapter.

image with no caption

Casting primitives

image with no caption

In Chapter 3 we talked about the sizes of the various primitives, and how you can’t shove a big thing directly into a small thing:

long y = 42;
int x = y;     // won't compile

A long is bigger than an int and the compiler can’t be sure where that long has been. It might have been out drinking with the other longs, and taking on really big values. To force the compiler to jam the value of a bigger primitive variable into a smaller one, you can use the cast operator. It looks like this:

long y = 42;          // so far so good
int x = (int) y;      // x = 42 cool!

Putting in the cast tells the compiler to take the value of y, chop it down to int size, and set x equal to whatever is left. If the value of y was bigger than the maximum value of x, then what’s left will be a weird (but calculable[5]) number:

long y = 40002;
// 40002 exceeds the 16-bit limit of a short

short x = (short) y;    // x now equals -25534!

Still, the point is that the compiler lets you do it. And let’s say you have a floating point number, and you just want to get at the whole number (int) part of it:

float f = 3.14f;
int x = (int) f;     // x will equal 3

And don’t even think about casting anything to a boolean or vice versa—just walk away.



[4] We know how much you enjoy typing, but for those rare moments when you’d rather do something else, we’ve made the Ready-bake Code available on wickedlysmart.com.

[5] It involves sign bits, binary, ‘two’s complement’ and other geekery, all of which are discussed at the beginning of Appendix B.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required