Chapter 2
IN THIS CHAPTER
Creating proper variable declarations
Discovering the difference between primitive and reference types
Looking at Java’s built-in data types
Introducing strings
Getting input from the console
Getting input if you’re using an older version of Java
In this chapter, you find out the basics of working with variables in Java. Variables are the key to making Java programs general purpose. The Hello, World!
programs in the previous chapter, for example, are pretty specific: The only thing they say is “Hello, World!” But with a variable, you can make this type of program more general. You could vary the greeting so that sometimes it would say “Hello, World!” and at other times it would say “Greetings, Foolish Mortals.” Or you could personalize the greeting, so that it said “Hello, Bob!” or “Hello, Amanda!”
Variables are also the key to creating programs that can perform calculations. Suppose that you want to create a program that calculates the area of a circle, given the circle's radius. Such a program uses two variables: one to represent the radius of the circle and the other to represent the circle’s area. The program asks the user to enter a value for the first variable. Then it calculates the value of the second variable.
In Java, you must explicitly declare all variables before using them. This rule is in contrast to some languages — most notably Python, which lets you use variables that haven’t been explicitely declared.
The basic form of a variable declaration is this:
type name;
Here are some examples:
int x;
String lastName;
double radius;
In these examples, variables named x
, lastName
, and radius
are declared. The x
variable holds integer values, the lastName
variable holds String
values, and the radius
variable holds double values. For more information about what these types mean, see the section “Working with Primitive Data Types” later in this chapter. Until then, just realize that int
variables can hold whole numbers (such as 5
, 1,340
, or -34
), double
variables can hold numbers with fractional parts (such as 0.5
, 99.97
, or 3.1415
), and String
variables can hold text values (such as "Hello, World!"
or "Jason P. Finch"
).
You can declare two or more variables of the same type in a single statement by separating the variable names with commas. For example:
int x, y, z;
Here three variables of type int
are declared, using the names x
, y
, and z
.
A class variable is a variable that any method in a class can access, including static methods such as main
. When declaring a class variable, you have two basic rules to follow:
static
in the declaration. The word static
comes before the variable type.The following program shows the proper way to declare a class variable named helloMessage
:
public class HelloApp
{
static String helloMessage;
public static void main(String[] args)
{
helloMessage = "Hello, World!";
System.out.println(helloMessage);
}
}
As you can see, the declaration includes the word static
and is placed within the HelloApp
class body but not within the body of the main
method.
public class HelloApp
{
public static void main(String[] args)
{
helloMessage = "Hello, World!";
System.out.println(helloMessage);
}
static String helloMessage;
}
Here the helloMessage
variable is declared after the main
method.
An instance variable is similar to a class variable but doesn’t specify the word static
in its declaration. As the name suggests, instance variables are associated with instances of classes. As a result, you can use them only when you create an instance of a class. Because static methods aren’t associated with an instance of the class, you can’t use an instance variable in a static method — and that includes the main
method.
The following example program won't compile:
public class HelloApp
{
String helloMessage; // error -- should use static keyword
public static void main(String[] args)
{
helloMessage = "Hello, World!";
System.out.println(helloMessage); // will not compile
}
}
If you try to compile this program, you get the following error messages:
C:\Java\HelloApp.java:7: error: non-static variable helloMessage cannot be referenced from a static context
helloMessage = "Hello, World!";
^
C:\Java\HelloApp.java:8: non-static variable helloMessage cannot be referenced from a static context
System.out.println(helloMessage);
^
Both of these errors occur because the main
method is static, so it can’t access instance variables.
Instance variables are useful whenever you create your own classes, but because I don’t cover that topic until Book 3, you won’t see many examples of instance methods in the remainder of the chapters in Book 2.
A local variable is a variable that’s declared within the body of a method. Then you can use the variable only within that method. Other methods in the class aren’t even aware that the variable exists.
Here’s a version of the HelloApp
class in which the helloMessage
variable is declared as a local variable:
public class HelloApp
{
public static void main(String[] args)
{
String helloMessage;
helloMessage = "Hello, World!";
System.out.println(helloMessage);
}
}
Note that you don't specify static
on a declaration for a local variable. If you do, the compiler generates an error message and refuses to compile your program. Local variables always exist within the scope of a method, and they exist only while that method is executing. As a result, whether an instance of the class has been created is irrelevant. (For more information, see the section “Understanding Scope,” later in this chapter.)
public class HelloApp
{
public static void main(String[] args)
{
helloMessage = "Hello, World!"; // error -- helloMessage
System.out.println(helloMessage); // is not yet declared
String helloMessage;
}
}
When it gets to the first line of the main
method, the compiler generates two error messages complaining that it can't find the symbol "helloMessage"
. That’s because the symbol hasn’t been declared.
Although most local variables are declared near the beginning of a method’s body, you can also declare local variables within smaller blocks of code marked by braces. This will make more sense to you when you read about statements that use blocks, such as if
and for
statements. But here's an example:
if (taxRate > 0)
{
double taxAmount;
taxAmount = subTotal * taxRate;
total = subTotal + total;
}
Here the variable taxAmount
exists only within the set of braces that belongs to the if
statement. (You can assume that the variables taxRate
, subtotal
, and total
are defined outside of the code block defined by the braces.)
In Java, local variables are not given initial default values. The compiler checks to make sure that you have assigned a value before you use a local variable. The following example program won't compile:
public class testApp
{
public static void main(String[] args)
{
int i;
System.out.println("The value of i is " + i);
}
}
If you try to compile this program, you get the following error message:
C:\Java\testApp.java:6: error: variable i might not have been initialized
System.out.println("The value of i is " + i);
^
To avoid this error message, you must initialize local variables before you use them. You can do that by using an assignment statement or an initializer, as I describe in the following sections.
One way to initialize a variable is to code an assignment statement following the variable declaration. Assignment statements have this general form:
variable = expression;
Here, the expression
can be any Java expression that yields a value of the same type as the variable. Here's a version of the main
method from the previous example that correctly initializes the i
variable before using it:
public static void main(String[] args)
{
int i;
i = 0;
System.out.println("i is " + i);
}
In this example, the variable is initialized to a value of zero before the println
method is called to print the variable's value.
You find out a lot more about expressions in Book 2, Chapter 3. For now, you can just use simple literal values, such as 0
in this example.
Java also allows you to initialize a variable on the same statement that declares the variable. To do that, you use an initializer, which has the following general form:
type name = expression;
In effect, the initializer lets you combine a declaration and an assignment statement into one concise statement. Here are some examples:
int x = 0;
String lastName = "Lowe";
double radius = 15.4;
In each case, the variable is both declared and initialized in a single statement.
When you declare more than one variable in a single statement, each variable can have its own initializer. The following code declares variables named x
and y
, and initializes x
to 5
and y
to 10
:
int x = 5, y = 10;
static int x, y = 5;
Here you might think that both x
and y
would initialize to 5
. But the initializer applies only to y
, so x
is initialized to its default value, 0
. (If you make this mistake with a local variable, the compiler displays an error message for the first statement that uses the x
variable because it isn't properly initialized.)
A final variable is a variable whose value you can’t change after it’s been initialized. To declare a final variable, you add the final
keyword to the variable declaration, like this:
final int WEEKDAYS = 5;
A variable that is both final and static is called a constant. Constants are often used for values that are universally the same, such as the number of days in June or the atomic weight of iridium. To create a constant, add static final
(not final static
) to the declaration, as follows:
static final WEEKDAYS = 5;
In addition to values that are universally the same, constants are useful for values that are used in several places throughout a program and that don’t change during the course of the program. Suppose that you’re writing a game that features bouncing balls, and you want the balls always to have a radius of 6 pixels. This program probably needs to use the ball diameter in several places — to draw the ball onscreen, to determine whether the ball has hit a wall, to determine whether the ball has hit another ball, and so on. Rather than just specify 6
whenever you need the ball's radius, you can set up a class constant named BALL_RADIUS
, like this:
static final BALL_RADIUS = 6;
Using a constant has two advantages:
7
, you make the change in just one place: the initializer for the BALL_RADIUS
constant.BALL_RADIUS
rather than 6
, for example.The term data type refers to the type of data that can be stored in a variable. Java is sometimes called a strongly typed language because when you declare a variable, you must specify the variable's type. Then the compiler ensures that you don’t try to assign data of the wrong type to the variable. The following example code generates a compiler error:
int x;
x = 3.1415;
Because x
is declared as a variable of type int
(which holds whole numbers), you can't assign the value 3.1415
to it.
A key difference between a primitive type and a reference type is that the memory location associated with a primitive-type variable contains the actual value of the variable. As a result, primitive types are sometimes called value types. By contrast, the memory location associated with a reference-type variable contains an address (called a pointer) that indicates the memory location of the actual object. I explain reference types more fully in the section “Using reference types,” later in this chapter, so don’t worry if this explanation doesn’t make sense just yet.
Java defines a total of eight primitive types, listed in Table 2-1. Of the eight primitive types, six are for numbers, one is for characters, and one is for true/false values.
An integer is a whole number — that is, a number with no fractional or decimal portion. Java has four integer types, which you can use to store numbers of varying sizes. The most commonly used integer type is int
. This type uses 4 bytes to store an integer value that can range from about negative 2 billion to positive 2 billion.
TABLE 2-1 Java's Primitive Types
Type |
Explanation |
|
A 32-bit (4-byte) integer value |
|
An 8-bit (1-byte) integer value |
|
A 16-bit (2-byte) integer value |
|
A 64-bit (8-byte) integer value |
|
A 32-bit (4-byte) floating-point value |
|
A 64-bit (8-byte) floating-point value |
|
A 16-bit character using the Unicode encoding scheme |
|
A |
If you're writing the application that counts how many hamburgers McDonald’s has sold, an int
variable may not be big enough. In that case, you can use a long
integer instead. long
is a 64-bit integer that can hold numbers ranging from about negative 9,000 trillion to positive 9,000 trillion. (That's a big number, even by federal deficit standards.)
In some cases, you may not need integers as large as the standard int
type provides. For those cases, Java provides two smaller integer types. The short
type represents a two-byte integer, which can hold numbers from –32,768 to +32,767, and the byte
type defines a single-byte integer that can range from –128 to +127.
Although the short
and byte
types require less memory than the int
and long
types, there's usually little reason to use them for desktop applications, where memory is usually plentiful. A few bytes here or there won’t make any difference in the performance of most programs — so you should stick to int
and long
most of the time. Also, use long
only when you know that you're dealing with numbers too large for int
.
int xInt;
long yLong;
xInt = 32;
yLong = xInt;
Here you can assign the value of the xInt
variable to the yLong
variable because yLong
is larger than xInt
. Java does not allow the converse, however:
int xInt;
long yLong;
yLong = 32;
xInt = yLong;
The value of the yLong
variable cannot be assigned to the xInt
because xInt
is smaller than yLong
. Because this assignment may result in a loss of data, Java doesn't allow it. (If you need to assign a long
to an int
variable, you must use explicit casting, as described in the “Type casting” section, later in this chapter.)
You can include underscores to make longer numbers easier to read. Thus, the following statements both assign the same value to the variables xLong1
and xLong2
:
long xLong1 = 58473882;
long xLong2 = 58_473_882;
Floating-point numbers are numbers that have fractional parts (usually expressed with a decimal point), such as 19.95 or 3.1415.
Java has two primitive types for floating-point numbers: float
, which uses 4 bytes, and double
, which uses 8 bytes. In almost all cases, you should use the double
type whenever you need numbers with fractional values.
The precision of a floating-point value indicates how many significant digits the value can have following its decimal point. The precision of a float
type is only about six or seven decimal digits, which isn't sufficient for many types of calculations.
By contrast, double variables have a precision of about 15 digits, which is enough for most purposes.
You can find more information about some of the nuances of working with floating-point values in Book 2, Chapter 3.
When you use a floating-point literal, I suggest you include a decimal point, like this:
double period = 99.0;
That avoids the confusion of assigning what looks like an integer to a floating-point variable.
To save that time, you can add an F
or D
suffix to a floating-point literal to indicate whether the literal itself is of type float
or double
. For example:
float value1 = 199.33F;
double value2 = 200495.995D;
If you omit the suffix, D
is assumed. As a result, you can usually omit the D
suffix for double
literals.
The char
type represents a single character from the Unicode character set. It’s important to keep in mind that a character is not the same as a String; you find out about strings later in this chapter, in the section “Working with Strings.” For now, just realize that a char
variable can store just one character, not a sequence of characters, as a String can.
To assign a value to a char
variable, you use a character literal, which is always enclosed in apostrophes rather than quotes. Here's an example:
char code = 'X';
Here the character X
is assigned to the variable named code
.
The following statement won't compile:
char code = "X"; // error -- should use apostrophes, not quotes
That’s because quotation marks are used to mark Strings, not character constants.
You can also assign an integer value from 0 to 255 to a char
variable, like this:
char cr = 013;
Here, the decimal value 13, which represents a carriage return, is assigned to the variable named cr
.
Unicode is a 2-byte character code that can represent the characters used in most languages throughout the world. Currently, about 35,000 codes in the Unicode character set are defined, which leaves another 29,000 codes unused. The first 256 characters in the Unicode character set are the same as the characters of the ASCII character set, which is the most commonly used character set for computers with Western languages.
Character literals can also use special escape sequences to represent special characters. Table 2-2 lists the allowable escape sequences. These escape sequences let you create literals for characters that can't otherwise be typed within a character constant.
TABLE 2-2 Escape Sequences for Character Constants
Escape Sequence |
Explanation |
|
Backspace |
|
Horizontal tab |
|
Line feed |
|
Form feed |
|
Carriage return |
|
Double quote |
|
Single quote |
|
Backslash |
A Boolean
type can have one of two values: true
or false
. Booleans are used to perform logical operations, most commonly to determine whether some condition is true. For example:
boolean enrolled = true;
boolean credited = false;
Here a variable named enrolled
of type boolean
is declared and initialized to a value of true
, and another boolean
named credited
is declared and initialized to false
.
Every primitive type has a corresponding class defined in the Java API class library. This class is sometimes called a wrapper class because it wraps a primitive value with the object-oriented equivalent of pretty wrapping paper and a bow to make the primitive type look and behave like an object. Table 2-3 lists the wrapper classes for each of the eight primitive types.
TABLE 2-3 Wrapper Classes for the Primitive Types
Primitive Type |
Wrapper Class |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
As you find out later in this chapter, you can use these wrapper classes to convert primitive values to strings, and vice versa.
In Book 3, Chapter 1, you're introduced to some of the basic concepts of object-oriented programming. In particular, you see how all Java programs are made up of one or more classes, and how to use classes to create objects. In this section, I show how you can create variables that work with objects created from classes.
To start, a reference type is a type that’s based on a class rather than on one of the primitive types that are built into the Java language. A reference type can be based on a class that’s provided as part of the Java API class library or on a class that you write yourself. Either way, when you create an object from a class, Java allocates however much memory the object requires to store the object. Then, if you assign the object to a variable, the variable is actually assigned a reference to the object, not the object itself. This reference is the address of the memory location where the object is stored.
Suppose that you’re writing a game program that involves balls, and you create a class named Ball
that defines the behavior of a ball. To declare a variable that can refer to a Ball
object, you use a statement like this:
Ball b;
Here, the variable b
is a variable of type Ball
.
To create a new instance of an object from a class, use the new
keyword along with the class name. This second reference to the class name is actually a call to a special routine of the class called a constructor. The constructor is responsible for initializing the new object. Here's a statement that declares a variable of type Ball
, calls the Ball
class constructor to create a new Ball
object, and assigns a reference to the Ball
object to the variable:
Ball b = new Ball();
Consider these statements:
Ball b1 = new Ball();
Ball b2 = b1;
Here I’ve declared two Ball
variables, named b1
and b2
, but I've created only one Ball
object. In the first statement, the Ball
object is created, and b1
is assigned a reference to it. Then, in the second statement, the variable b2
is assigned a reference to the same object that's referenced by b1
. As a result, both b1
and b2
refer to the same Ball
object.
If you use one of these variables to change some aspect of the ball, the change is visible to the ball no matter which variable you use. Suppose that the Ball
class has a method called setSpeed
that lets you set the speed of the ball to any int
value and a getSpeed
method that returns an integer value that reflects the ball's current speed. Now consider these statements:
b1.setSpeed(50);
b2.setSpeed(100);
int speed = b1.getSpeed();
When these statements complete, is the value of the speed
variable 50
or 100
? The correct answer is 100
. Because b1
and b2
refer to the same Ball
object, changing the speed by using b2
affects b1
as well.
This is one of the most confusing aspects of programming with an object-oriented language such as Java, so don't feel bad if you get tripped up from time to time.
Java 10 introduced a new featured called local variable type inference, which lets you substitute the generic word var
for the variable type whenever you delclare and initialize a local variable in the same sentence.
Whew! That’s a moutful. A simple example should make this more clear. Traditionally, you declare and initialize a integer variable like this:
int x = 5;
Note in this example that when I declare the variable x
, I explicitly state the type of the variable as int
. I then assign the integer value 5
to the variable.
Beginning with Java 10, you don't have to explicitly identify the type of a variable if the Java compiler can infer the variable type from the value you assign to it. Instead of stating the variable’s type as int
, you can use the generic word var
, like this:
var x = 5;
Here, the Java compiler can infer that the variable type should be int
because you assign an integer value (5
) to the variable.
Here's another example, this time creating a variable of type Ball
:
var b1 = new Ball();
In this example, the variable b1
is given the type Ball
because the variable is assigned an instance of the Ball
class.
Here are a few important details to note about local variable type inference:
var
type, you must declare the variable and assign a value in the same statement. So, the following code will not compile:
var b1; // Does not compile
b1 = new Ball();
var
type can be used only for local variables. You must still explicitly state the type for class variables.var
variable, you can’t change its type. For example, the following will not compile:
var x = 5;
x = "Hello!"; // Can't change the type
var
only for local variables. You can't use it for method parameters, method return types, or class fields.Many programmers like to use the var
keyword because it slightly reduces the verbosity of their programs. Personally, I avoid the var
keyword because I want to be certain that I'm aware of the type of every variable I declare. So you won’t see very many examples that use the var
keyword in this book.
A String is a sequence of text characters, such as the message "Hello, World!"
displayed by the HelloApp
program illustrated in this chapter and the preceding chapter. In Java, strings are an interesting breed. Java doesn't define strings as a primitive type. Instead, strings are a reference type defined by the Java API String
class. The Java language does have some built-in features for working with strings. In some cases, these features make strings appear to be primitive types rather than reference types.
Java’s string-handling features are advanced enough to merit an entire chapter, so for the full scoop on strings, I refer you to Book 4, Chapter 1. The following sections present just the bare essentials of working with strings so that you can incorporate simple strings into your programs.
Strings are declared and initialized much like primitive types. In fact, the only difference you may notice at first is that the word String
is capitalized, unlike the keywords for the primitive types, such as int
and double
. That's because String
isn’t a keyword. Instead, it’s the name of the Java API class that provides for string objects.
The following statements define and initialize a string variable:
String s;
s = "Hello, World!";
Here a variable named s
of type String
is declared and initialized with the string literal "Hello, World!"
. Notice that string literals are enclosed in quotation marks, not apostrophes. Apostrophes are used for character literals, which are different from string literals.
Like any variable declaration, a string declaration can include an initializer. Thus you can declare and initialize a string variable in one statement, like this:
String s = "Hello, World!";
String s = "";
Combine two strings by using the plus sign (+
) as a concatenation operator. (In Java-speak, combining strings is called concatenation.) The following statement combines the value of two string variables to create a third string:
String hello = "Hello, ";
String world = "World!";
String greeting = hello + world;
The final value of the greeting
variable is "Hello, World!"
.
Alternatively, you can concatenate a string literal along with the string variables. For example:
String hello = "Hello";
String world = "World!";
String greeting = hello + ", " + world;
Here the comma and the space that appear between the words Hello
and World
are inserted as a string literal.
Concatenation is one of the most commonly used string-handling techniques, so you see plenty of examples in this book. In fact, I've already used concatenation once in this chapter. Earlier, I showed you a program that included the following line:
System.out.println("The value of i is " + i);
Here the println
method of the System.out
object prints the string that's created when the literal "The value of i is "
is concatenated with the value of the i
variable.
Because string concatenation lets you combine two or more string values, and because primitive types such as int
and double
are not string types, you may be wondering how the last example in the preceding section can work. In other words, how can Java concatenate the string literal "The value of i is "
with the integer value of i
in this statement?:
System.out.println("The value of i is " + i);
The answer is that Java automatically converts primitive values to string values whenever you use a primitive value in a concatenation.
int i = 2;
System.out.println(i + i + " equals four.");
This prints the following on the console:
4 equals four.
Here, the first plus sign indicates the addition of two int
variables rather than concatenation. For the second plus sign, the resulting int
answer is converted to a string and concatenated with " equals four."
String s = Integer.toString(x);
In the next chapter, you discover how to use a special class called the NumberFormat
class to convert primitive types to strings while applying various types of formatting to the value, such as adding commas, dollar signs, or percentage marks.
Converting a primitive value to a string value is pretty easy. Going the other way — converting a string value to a primitive — is a little more complex, because it doesn't always work. If a string contains the value 10
, for example, you can easily convert it to an integer. But if the string contains thirty-two
, you can't.
To convert a string to a primitive type, you use a parse
method of the appropriate wrapper class, as listed in Table 2-4. To convert a string value to an integer, you use statements like this:
String s = "10";
int x = Integer.parseInt(s);
Note that there is no parse
method to convert a String
to a Character
. If you need to do that, you can find out how in Book 4, Chapter 1.
TABLE 2-4 Methods That Convert Strings to Numeric Primitive Types
Wrapper |
parse Method |
Example |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
From time to time, you need to convert numeric data of one type to another. You may need to convert a double value to an integer, or vice versa. Some conversions can be done automatically; others are done using a technique called casting. I describe automatic type conversions and casting in the following sections.
Java can automatically convert some primitive types to others and do so whenever necessary. Figure 2-1 shows which conversions Java allows. Note that the conversions shown with dotted arrows in the figure may cause some of the value's precision to be lost. An int
can be converted to a float
, for example, but large int
values won't be converted exactly because int
values can have more digits than can be represented by the float
type.
Whenever you perform a mathematical operation on two values that aren't of the same type, Java automatically converts one of them to the type of the other. Here are the rules Java follows when doing this conversion:
double
, the other value is converted to a double
.double
but one is a float
, the other is converted to a float
.
double
nor a float
but one is a long
, the other is converted to a long
.int
.Casting is similar to conversion but isn't done automatically. You use casting to perform a conversion that is not shown in Figure 2-1. If you want to convert a double
to an int
, for example, you must use casting.
To cast a primitive value from one type to another, you use a cast operator, which is simply the name of a primitive type in parentheses placed before the value you want to cast. For example:
double pi = 3.1314;
int iPi;
iPi = (int) pi;
Note that the fractional part of a double is simply discarded when cast to an integer; it isn't rounded. For example:
double price = 9.99;
int iPrice = (int) price;
Here iPrice
is assigned the value 9
. If you want to round the double value when you convert it, use the round
method of the Math
class, as I show you in the next chapter.
As I mention earlier in this chapter, in the section “Using wrapper classes,” Java provides wrapper classes for each of its primitive data types. You may think that you would have to explicitly cast values from a primitive type to the corresponding wrapper type, like this:
int x = 1000;
Integer y = (Integer) x;
Because of a feature called boxing, you don't have to do that. Boxing occurs when Java automatically converts a primitive value to its corresponding wrapped object, and unboxing occurs when Java goes the other way (converts from a wrapped object to the corresponding primitive value). You don’t have to explicitly cast the primitive value to its wrapper class, or vice versa.
Here’s an example:
Integer wrap = 10;
System.out.println(wrap);
int prim = wrap;
System.out.println(prim);
The output of this code is 10
followed by another 10
. In the first line, you assign a primitive value 10
to the wrapper object named wrap
. In the third line of code, Java turns the big wrapped wrap
object back into a primitive 10
(because the variable prim
is of type int
).
Think of boxing and unboxing as nicknames for wrapping and unwrapping. The bottom line is, Java can wrap and unwrap values automatically. That's very handy.
The scope of a variable refers to which parts of a class the variable exists in. In the simplest terms, every variable exists only within the block in which the variable is declared, as well as any blocks that are contained within that block. That’s why class variables, which are declared in the class body, can be accessed by any methods defined by the class, but local variables defined within a method can be accessed only by the method in which they are defined.
The program in Listing 2-1 can help clarify the scope of class and local variables.
LISTING 2-1 A Program That Demonstrates Scope for Class and Local Variables
public class ScopeApp
{→2
static int x;
public static void main(String[] args)
{
x = 5;
System.out.println("main: x = " + x);
myMethod();
}
public static void myMethod()
{
int y;
y = 10;→13
if (y == x + 5)
{→15
int z;
z = 15;
System.out.println("myMethod: z = " + z);
}→19
System.out.println("myMethod: x = " + x);
System.out.println("myMethod: y = " + y);
}→22
}
The following paragraphs explain the scope of each of the variables used in this class:
x
is a class
variable. Its scope begins in line 2 and ends in line 23. As a result, both the main
method and the myMethod
method can access it.y
is a local variable that's initialized in line 13. As a result, its scope begins in line 13 and ends in line 22, which marks the end of the body of the myMethod
method.if
block that controls the scope of variable z
.z
.myMethod
method body and, therefore, the end of the scope of variable y
.When you run this program, you'll get the following output:
main: x = 5
myMethod: z = 15
myMethod: x = 5
myMethod: y = 10
A shadowed variable is a variable that would otherwise be accessible but is temporarily made unavailable because a variable with the same name has been declared in a more immediate scope. That’s a mouthful, but the example in Listing 2-2 makes the concept clear. Here a class variable named x
is declared. Then, in the main
method, a local variable with the same name is declared.
LISTING 2-2 A Class That Demonstrates Shadowing
public class ShadowApp
{
static int x;→3
public static void main(String[] args)
{
x = 5;→6
System.out.println("x = " + x);
int x;→8
x = 10;→9
System.out.println("x = " + x);
System.out.println("ShadowApp.x = " + ShadowApp.x);→11
}→12
}→14
The following paragraphs explain the scoping issues in this program:
x
is declared in line 3. Its scope is the entire class body, ending at line 14.x
is assigned a value in line 6. Then this value is printed to the console.x
is declared. The local variable shadows the class variable x
, so any reference to x
through the end of this method in line 12 refers to the local variable rather than the class variable.x
to the console. The local variable's value, not the class variable’s value, is printed here.ShadowApp.x
refers to the class variable.main
method ends in line 12, the class variable x
is no longer shadowed.ShadowApp
class body ends in line 14, the class variable x
falls out of scope.Here is the output you will get from this program:
x = 5
x = 10
ShadowApp.x = 5
You’ve already seen several programs that use System.out.println
to display output on the console. In the following sections, I officially show you how this method works, along with a related method called just print
.
Java applications are designed to work in a terminal input/output (I/O) environment. Every Java application has at its disposal three I/O streams that are designed for terminal-based input and output, which simply sends or receives data one character at a time. The three streams are
Scanner
, which makes it easy to read primitive data types from the standard input stream.To redirect standard output, you use a greater-than (>
) sign on the command that runs the Java
class, followed by the name of the file you want to save the standard output text to. Here's an example:
C:\Java>java TestApp >output.txt
Here the standard output created by the class TestApp
is saved in a file named output.txt
. Any text sent to the standard error stream still appears in the console window, however. As a result, the standard error stream is useful for programs that use output redirection to display status messages, error messages, or other information.
When you use a single >
sign for redirection, Windows overwrites the redirected file if it already exists. If you prefer to add to the end of an existing file, use two greater-than signs, like this:
C:\Java>java TestApp >>output.txt
Then, if the output.txt
file already exists, anything written to standard output by the TestApp
class will be added to the end of the existing output.txt
file.
All three standard streams are available to every Java program via the fields of the System
class, described in Table 2-5.
TABLE 2-5 Static Fields of the System Object
Field |
Description |
|
Standard input |
|
Standard output |
|
Standard error |
Both System.out
and System.err
represent instances of a class called PrintStream
, which defines the print
and println
methods used to write data to the console. You can use both methods with either a String
argument or an argument of any primitive data type.
The only difference between the print
and the println
methods is that the println
method adds a line-break character to the end of the output, so the output from the next call to print
or println
begins on a new line.
Because it doesn't start a new line, the print
method is useful when you want to print two or more items on the same line. Here’s an example:
int i = 64;
int j = 23;
System.out.print(i);
System.out.print(" and ");
System.out.println(j);
The console output produced by these lines is
64 and 23
Note that you could do the same thing with a single call to println
by using string concatenation, like this:
int i = 64;
int j = 23;
System.out.println(i + " and " + j);
The Scanner
class is used to get simple input values from the user in a console application. The techniques that I present here are used in many of the programs shown in the rest of this book.
Throughout the following sections, I refer to the program shown in Listing 2-3. This simple program uses the Scanner
class to read an integer value from the user and then displays the value back to the console to verify that the program received the value entered by the user. Here's a sample of the console window for this program:
Enter an integer: 5
You entered 5.
The program begins by displaying the message Enter an integer:
on the first line. Then it waits for you to enter a number. When you type a number (such as 5) and press the Enter key, it displays the confirmation message (You entered 5.
) on the second line.
LISTING 2-3 A Program That Uses the Scanner Class
import java.util.Scanner;→1
public class ScannerApp
{
static Scanner sc = new Scanner(System.in);→4
public static void main(String[] args)
{
System.out.print("Enter an integer: ");→7
int x = sc.nextInt();→8
System.out.println("You entered " + x + ".");→9
}
}
Before you can use the Scanner
class in a program, you must import it. To do that, you code an import
statement at the beginning of the program, before the class declaration, as shown in line 1 of Listing 2-3:
import java.util.Scanner;
Note that java
and util
aren't capitalized, but Scanner
is.
import java.util.*;
Before you can use the Scanner
class to read input from the console, you must declare a Scanner
variable and create an instance of the Scanner
class. I recommend that you create the Scanner
variable as a class variable and create the Scanner
object in the class variable initializer, as shown in line 4 of Listing 2-3:
static Scanner sc = new Scanner(System.in);
That way, you can use the sc
variable in any method in the class.
To create a Scanner
object, you use the new
keyword followed by a call to the Scanner
class constructor. Note that the Scanner
class requires a parameter that indicates the input stream that the input comes from. You can use System.in
here to specify standard keyboard console input.
To read an input value from the user, you can use one of the methods of the Scanner
class that are listed in Table 2-6. As you can see, the primitive data types have separate methods.
Notice in the first column of the table that each method listing begins with the type of the value that's returned by the method. The nextInt
method, for example, returns an int
value. Also, notice that each of the methods ends with an empty set of parentheses. That means that these methods don't require parameters. If a method does require parameters, the parameters are listed within these parentheses.
TABLE 2-6 Scanner Class Methods That Get Input Values
Method |
Explanation |
|
Reads a |
|
Reads a |
|
Reads a |
|
Reads a |
|
Reads an |
|
Reads a |
|
Reads a |
|
Reads a |
Because these methods read a value from the user and return the value, you most often use them in statements that assign the value to a variable. Line 8 in Listing 2-3, for example, reads an int
and assigns it to a variable named x
.
When the nextInt
method is executed, the program waits for the user to enter a value in the console window. To let the user know what kind of input the program expects, usually you should call the System.out.print
method before you call a Scanner
method to get input. Line 7 in Listing 2-3 calls System.out.print
to display the message Enter an integer:
on the console. That way, the user knows that the program is waiting for input.
Enter an integer: three Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:819)
at java.util.Scanner.next(Scanner.java:1431)
at java.util.Scanner.nextInt(Scanner.java:2040)
at java.util.Scanner.nextInt(Scanner.java:2000)
at ScannerApp.main(ScannerApp.java:11)
This message indicates that an exception called InputMismatchException
has occurred, which means that the program was expecting to see an integer but got something else instead. In Book 2, Chapter 8, you find out how to provide for exceptions like these so that the program can display a friendlier message and give the user another shot at entering a correct value. Until then, you have to put up with the fact that if the user enters incorrect data, your program crashes ungracefully.
TABLE 2-7 Scanner Class Methods That Check for Valid Input Values
Method |
Explanation |
|
Returns |
|
Returns |
|
Returns |
|
Returns |
|
Returns |
|
Returns |
|
Returns |
If you prefer to get your user input from a simple GUI rather than from a console, you can use the JOptionPane
class. As shown in Figure 2-2, JOptionPane
displays a simple dialog box to get text input from the user. Then you can use the parse
methods of the primitive-type wrapper classes to convert the text entered by the user to the appropriate primitive type.
Although the JOptionPane
class has many methods, the only one you need to use to get simple text input is the showInputDialog
method. This method uses a single parameter that specifies the prompting message that's displayed in the dialog box. It returns a string value that you can then parse to the proper type.
The JOptionPane
class is a part of the javax.swing
package, so you need to add an import javax.swing.JOptionPane
statement to the beginning of any program that uses this class.
Listing 2-4 shows a simple program that uses the JOPtionPane
class to get an integer value and display it on the console.
LISTING 2-4 A Program That Uses the JOptionPane Class to Get User Input
import javax.swing.JOptionPane;→1
public class DialogApp
{
public static void main(String[] args)
{
String s;
s = JOptionPane.showInputDialog→7
("Enter an integer:");→8
int x = Integer.parseInt(s);→9
System.out.println("You entered " + x + ".");→10
}
}
The following paragraphs describe the important lines in this program:
JOptionPane
class.Enter an integer:
and assigns the string entered by the user to the variable named s
.parseInt
method of the Integer
class to convert the string entered by the user to an integer.You will often find yourself using a String
or int
variable that you want to constrain to just a few different values. For example, suppose you're writing a program that plays a card game and you want a way to represent the suite of each card. You could do that with a String
variable whose value should be Hearts
, Spades
, Clubs
, or Diamonds
. Or you might use an int
and use the value 1 to represent Hearts, 2 for Spades, 3 for Clubs, or 4 for Diamonds. But such a scheme is error prone. What if you assign a value of 5 to the int
variable?
A better way is to create an enum, which is basically a custom variable type which has a limited set of possible values. To define an enum, you use the enum
keyword (usually modified by public
) followed by a list of possible values enclosed in brackets:
public enum CardSuit {HEARTS, SPADES, CLUBS, DIAMONDS}
You can declare variables using the enum’s name as the data type:
CardSuit suit;
Then, you can assign a value by using the enum name followed by a period and any of the enum values, as in this example:
suit = CardSuit.HEARTS;
Here’s a complete program that defines an enum, creates a variable of the enum’s type, assigns a value, and prints the result:
public class EnumTest
{
public enum CardSuit {HEARTS, SPADES, CLUBS, DIAMONDS}
public static void main(String[] args)
{
CardSuit suit;
suit = CardSuit.HEARTS;
System.out.println("The suit is " + suit);
}
}
This program displays the following line on the console:
The suit is HEARTS