This HTML version of Think Java is provided for convenience, but it is not the best format of the book. In particular, some of the symbols are not rendered correctly.
Chapter 2 Variables and operators
This chapter describes how to write statements using variables, which store values like numbers and words, and operators, which are symbols that perform a computation. We also explain three kinds of programming errors and offer additional debugging advice.
2.1 Declaring variables
One of the most powerful features of a programming language is the ability to define and manipulate variables. A variable is a named location that stores a value. Values may be numbers, text, images, sounds, and other types of data. To store a value, you first have to declare a variable.
This statement is a declaration, because it declares that the variable named
Some types begin with a capital letter and some with lowercase.
We will learn the significance of this distinction later, but for now you should take care to get it right.
There is no such type as
To declare an integer variable named
This example declares two variables with type
This example also demonstrates the syntax for declaring multiple variables with the same type on one line:
You can use any name you want for a variable.
But there are about 50 reserved words, called keywords, that you are not allowed to use as variable names.
These words include
You can find the complete list of keywords at http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html, but you don’t have to memorize them. Most programming editors provide “syntax highlighting”, which makes different parts of the program appear in different colors.
Now that we have declared variables, we want to use them to store values. We do that with an assignment statement.
This example shows three assignments, and the comments illustrate different ways people sometimes talk about assignment statements. The vocabulary can be confusing here, but the idea is straightforward:
As a general rule, a variable has to have the same type as the value you assign to it.
For example, you cannot store a string in
A common source of confusion is that some strings look like integers, but they are not.
Variables must be initialized (assigned for the first time) before they can be used. You can declare a variable and then assign a value later, as in the previous example. You can also declare and initialize on the same line:
2.3 State diagrams
Because Java uses the
Equality is commutative, and assignment is not.
For example, in mathematics if a = 7 then 7 = a.
Also, in mathematics, a statement of equality is true for all time. If a = b now, a is always equal to b. In Java, an assignment statement can make two variables equal, but they don’t have to stay that way.
The third line changes the value of
Taken together, the variables in a program and their current values make up the program’s state. Figure 2.1 shows the state of the program after these assignment statements run.
Diagrams like this one that show the state of the program are called state diagrams. Each variable is represented with a box showing the name of the variable on the outside and the value inside. As the program runs, the state changes, so you should think of a state diagram as a snapshot of a particular point in time.
2.4 Printing variables
You can display the value of a variable using
When we talk about displaying a variable, we generally mean the value of the variable. To display the name of a variable, you have to put it in quotes.
For this example, the output is:
Conveniently, the syntax for displaying a variable is the same regardless of its type. For example:
The output of this program is:
To output multiple values on the same line, it’s common to use several
2.5 Arithmetic operators
Operators are symbols that represent simple computations.
For example, the addition operator is
The following program converts a time of day to minutes:
In this program,
The result of the previous example is:
Expressions are generally a combination of numbers, variables, and operators. When complied and executed, they become a single value.
For example, the expression
Addition, subtraction, and multiplication all do what you expect, but you might be surprised by division. For example, the following fragment tries to compute the fraction of an hour that has elapsed:
The output is:
This result often confuses people.
The value of
As an alternative, we can calculate a percentage rather than a fraction:
The new output is:
Again the result is rounded down, but at least now it’s approximately correct.
2.6 Floating-point numbers
A more general solution is to use floating-point numbers, which can represent fractions as well as integers.
In Java, the default floating-point type is called
Java performs “floating-point division” when one or more operands are
The output is:
Although floating-point numbers are useful, they can be a source of confusion.
For example, Java distinguishes the integer value
The following is illegal because the variable on the left is an
It is easy to forget this rule because in many cases Java automatically converts from one type to another:
The preceding example should be illegal, but Java allows it by converting the
You might expect the variable
One way to solve this problem (once you figure out the bug) is to make the right-hand side a floating-point expression.
The following sets
As a matter of style, you should always assign floating-point values to floating-point variables. The compiler won’t make you do it, but you never know when a simple mistake will come back and haunt you.
2.7 Rounding errors
Most floating-point numbers are only approximately correct. Some numbers, like reasonably-sized integers, can be represented exactly. But repeating fractions, like 1/3, and irrational numbers, like π, cannot. To represent these numbers, computers have to round off to the nearest floating-point number.
The difference between the number we want and the floating-point number we get is called rounding error. For example, the following two statements should be equivalent:
But on many machines, the output is:
The problem is that
For many applications, like computer graphics, encryption, statistical analysis, and multimedia rendering, floating-point arithmetic has benefits that outweigh the costs. But if you need absolute precision, use integers instead. For example, consider a bank account with a balance of $123.45:
In this example, balances will become inaccurate over time as the variable is used in arithmetic operations like deposits and withdrawals. The result would be angry customers and potential lawsuits. You can avoid the problem by representing the balance as an integer:
This solution works as long as the number of cents doesn’t exceed the largest integer, which is about 2 billion.
2.8 Operators for strings
In general, you cannot perform mathematical operations on strings, even if the strings look like numbers. The following expressions are illegal:
Or if you have a variable called
Since addition is defined for both numbers and strings, Java performs automatic conversions you may not expect:
Java executes these operations from left to right.
In the first line,
When more than one operator appears in an expression, they are evaluated according to order of operations. Generally speaking, Java evaluates operators from left to right (as we saw in the previous section). But for numeric operators, Java follows mathematical conventions:
Don’t work too hard to remember the order of operations, especially for other operators. If it’s not obvious by looking at the expression, use parentheses to make it clear.
So far we have looked at the elements of a programming language – variables, expressions, and statements – in isolation, without talking about how to put them together.
One of the most useful features of programming languages is their ability to take small building blocks and compose them. For example, we know how to multiply numbers and we know how to display values. We can combine these operations into a single statement:
Any arithmetic expression can be used inside a print statement. We’ve already seen one example:
You can also put arbitrary expressions on the right side of an assignment:
The left side of an assignment must be a variable name, not an expression. That’s because the left side indicates where the result will be stored, and expressions do not represent storage locations.
The ability to compose operations may not seem impressive now, but we will see examples later on that allow us to write complex computations neatly and concisely. But don’t get too carried away. Large, complex expressions can be hard to read and debug.
2.10 Types of errors
Three kinds of errors can occur in a program: compile-time errors, run-time errors, and logic errors. It is useful to distinguish among them in order to track them down more quickly.
Compile-time errors occur when you violate the syntax rules of the Java language.
For example, parentheses and braces have to come in matching pairs.
Error messages from the compiler usually indicate where in the program the error occurred, and sometimes they can tell you exactly what the error is. As an example, let’s get back to the hello world program from Section 1.4.
If you forget the semicolon at the end of the print statement, you might get an error message like this:
That’s pretty good: the location of the error is correct, and the error message tells you what’s wrong.
But error messages are not always easy to understand. Sometimes the compiler reports the place in the program where the error was detected, not where it actually occurred. And sometimes the description of the problem is more confusing than helpful.
For example, if you leave out the closing brace at the end of
There are two problems here. First, the error message is written from the compiler’s point of view, not yours. Parsing is the process of reading a program before translating; if the compiler gets to the end of the file while still parsing, that means something was omitted. But the compiler doesn’t know what. It also doesn’t know where. The compiler discovers the error at the end of the program (line 7), but the missing brace should be on the previous line.
Error messages contain useful information, so you should make an effort to read and understand them. But don’t take them too literally.
During the first few weeks of your programming career, you will probably spend a lot of time tracking down compile-time errors. But as you gain experience, you will make fewer mistakes and find them more quickly.
The second type of error is a run-time error, so-called because it does not appear until after the program has started running. In Java, these errors occur while the interpreter is executing byte code and something goes wrong. These errors are also called “exceptions” because they usually indicate that something exceptional (and bad) has happened.
Run-time errors are rare in the simple programs you will see in the first few chapters, so it might be a while before you encounter one. When a run-time error occurs, the interpreter displays an error message that explains what happened and where.
For example, if you accidentally divide by zero you will get a message like this:
Some parts of this output are useful for debugging.
The first line includes the name of the exception,
Error messages sometimes contain additional information that won’t make sense yet. So one of the challenges is to figure out where to find the useful parts without being overwhelmed by extraneous information. Also, keep in mind that the line where the program crashed may not be the line that needs to be corrected.
The third type of error is the logic error. If your program has a logic error, it will compile and run without generating error messages, but it will not do the right thing. Instead, it will do exactly what you told it to do. For example, here is a version of the hello world program with a logic error:
This program compiles and runs just fine, but the output is:
Assuming that we wanted the output on one line, this is not correct.
The problem is that the first line uses
Identifying logic errors can be hard because you have to work backwards, looking at the output of the program, trying to figure out why it is doing the wrong thing, and how to make it do the right thing. Usually the compiler and the interpreter can’t help you, since they don’t know what the right thing is.
Now that you know about the three kinds of errors, you might want to read Appendix C, where we’ve collected some of our favorite debugging advice. It refers to language features we haven’t talked about yet, so you might want to re-read it from time to time.
The code for this chapter is in the ch02 directory of ThinkJavaCode. See page ?? for instructions on how to download the repository. Before you start the exercises, we recommend that you compile and run the examples.
If you have not already read Appendix A.2, now might be a good time. It describes the DrJava Interactions Pane, which is a useful way to develop and test short fragments of code without writing a complete class definition.
If you are using this book in a class, you might enjoy this exercise. Find a partner and play “Stump the Chump”:
Start with a program that compiles and runs correctly. One player looks away while the other player adds an error to the program. Then the first player tries to find and fix the error. You get two points if you find the error without compiling the program, one point if you find it using the compiler, and your opponent gets a point if you don’t find it.
The point of this exercise is (1) to use string concatenation to display values with different types (
The point of this exercise is to (1) use some of the arithmetic operators, and (2) start thinking about compound entities (like time of day) that are represented with multiple values.
Hint: You might want to use additional variables to hold values during the computation. Variables that are used in a computation but never displayed are sometimes called “intermediate” or “temporary” variables.
Are you using one of our books in a class?We'd like to know about it. Please consider filling out this short survey.