Chapter 2

Working with Variables and Data Types

IN THIS CHAPTER

check Creating proper variable declarations

check Discovering the difference between primitive and reference types

check Looking at Java’s built-in data types

check Introducing strings

check Getting input from the console

check 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.

Declaring Variables

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.

Warning Allowing you to use variables that you haven’t explicitly declared might seem a pretty good idea at first glance, but it’s a common source of bugs that result from misspelled variable names. Java requires that you explicitly declare variables so that if you misspell a variable name, the compiler can detect your mistake and display a compiler error.

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

Tip Notice that variable declarations end with semicolons. That's because a variable declaration is itself a type of statement.

Remember Variable names follow the same rules as other Java identifiers, as I describe in Book 2, Chapter 1, so see that chapter for details. In short, a variable name can be any combination of letters, numerals, or underscores and dollar signs – but must start with a letter. Most programmers prefer to start variable names with lowercase letters and capitalize the first letter of individual words within the name. firstName and salesTaxRate, for example, are typical variable names.

Declaring two or more variables in one statement

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.

Tip As a rule, I suggest that you avoid declaring multiple variables in a single statement. Your code is easier to read and maintain if you give each variable a separate declaration.

Declaring class variables

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:

  • You must place the declaration within the body of the class but not within any of the class methods.
  • You must include the word static in the declaration. The word static comes before the variable type.

Tip Class variables are often called static variables. The key distinction between a static variable and an instance variable, which I cover in the next section, is that the value of a static variable is the same for all instances of the class. In contrast, each instance of a class has distinct values for its instance variables.

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.

Tip You don't have to place class variable declarations at the beginning of a class. Some programmers prefer to place them at the end of the class, as in this example:

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.

Tip I think classes are easier to read if the variables are declared first, so that's where you see them in this book.

Declaring instance variables

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.

Declaring local variables

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

Tip Unlike class and instance variables, a local variable is fussy about where you position the declaration for it. In particular, you must place the declaration before the first statement that actually uses the variable. Thus the following program won’t compile:

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

Initializing Variables

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.

Tip Unlike local variables, class variables and instance variables are given default values. Numeric types are automatically initialized to zero, and String variables are initialized to empty strings. As a result, you don’t have to initialize a class variable or an instance variable, although you can if you want them to have an initial value other than the default.

Initializing variables with assignment statements

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.

Initializing variables with initializers

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;

Warning When you declare two class or instance variables in a single statement but use only one initializer, you can mistakenly think that the initializer applies to both variables. Consider this statement:

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

Using Final Variables (Constants)

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;

Tip Although it isn't required, using all capital letters for static final variable names is common. When you do so, you can easily spot the use of constants in your programs.

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:

  • If you decide later that the radius of the balls should be 7, you make the change in just one place: the initializer for the BALL_RADIUS constant.
  • The constant helps document the inner workings of your program. The operation of a complicated calculation that uses the ball's radius is easier to understand if it specifies BALL_RADIUS rather than 6, for example.

Working with Primitive Data Types

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.

Remember Java makes an important distinction between primitive types and reference types.

  • Primitive types are the data types defined by the language itself.
  • Reference types are types defined by classes in the Java application programming interface (API) or by classes you create rather than by the language itself.

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.

Technical stuff It isn’t quite true that reference types are defined by the Java API and not by the Java language specification. A few reference types, such as Object and String, are defined by classes in the API, but those classes are specified in the Java Language API. Also, a special type of variable called an array, which can hold multiple occurrences of primitive- or reference-type variables, is considered to be a reference type.

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.

Integer types

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

int

A 32-bit (4-byte) integer value

byte

An 8-bit (1-byte) integer value

short

A 16-bit (2-byte) integer value

long

A 64-bit (8-byte) integer value

float

A 32-bit (4-byte) floating-point value

double

A 64-bit (8-byte) floating-point value

char

A 16-bit character using the Unicode encoding scheme

boolean

A true or false value

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.

Technical stuff In Java, the size of integer data types is specified by the language and is the same regardless of what computer a program runs on. This is a huge improvement over the C and C++ languages, which let compilers for different platforms determine the optimum size for integer data types. As a result, a C or C++ program written and tested on one type of computer may not execute identically on another computer.

Tip Java allows you to promote an integer type to a larger integer type. Java allows the following, for example:

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 types

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.

Technical stuff Floating-point numbers actually use exponential notation (also called scientific notation) to store their values. That means that a floating-point number actually records two numbers: a base value (also called the mantissa) and an exponent. The actual value of the floating-point number is calculated by multiplying the mantissa by 2 raised to the power indicated by the exponent. For float types, the exponent can range from –127 to +128. For double types, the exponent can range from –1,023 to +1,024. Thus both float and double variables are capable of representing very large and very small numbers.

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.

Technical stuff Interestingly, floating-point numbers have two distinct zero values: a negative zero and a positive zero. You don't have to worry about these much, because Java treats them as equal. Still, they would make for a good question on Jeopardy! (“I’ll take Weird Numbers for $200, Alex.”)

The char type

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.

Tip For more information about the Unicode character set, see the official Unicode website at www.unicode.org.

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

\b

Backspace

\t

Horizontal tab

\n

Line feed

\f

Form feed

\r

Carriage return

\"

Double quote

\'

Single quote

\\

Backslash

The Boolean type

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.

Warning In some languages, such as C or C++, integer values can be treated as Booleans, with 0 equal to false and any other value equal to true. Not so in Java. In Java, you can't convert between an integer type and a boolean type.

Using wrapper classes

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

int

Integer

short

Short

long

Long

byte

Byte

float

Float

double

Double

char

Character

boolean

Boolean

As you find out later in this chapter, you can use these wrapper classes to convert primitive values to strings, and vice versa.

Using reference types

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

Remember One of the key concepts in working with reference types is the fact that a variable of a particular type doesn't actually contain an object of that type. Instead, it contains a reference to an object of the correct type. An important side effect is that two variables can refer to the same object.

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.

Using inferred variable types

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:

  • When you use the 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();

  • The var type can be used only for local variables. You must still explicitly state the type for class variables.
  • After you've created a 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

  • You can use var only for local variables. You can't use it for method parameters, method return types, or class fields.

Remember Note that in some programming languages, including JavaScript, the keyword var is used to indicate that a variable does not have a type and, therefore, can be used to store any type of data. That is not the case in Java. In Java, all variables have a specific type. When you use var as a variable type in Java, you're simply allowing the compiler to infer the variable’s type based on the value that is assigned to it. Thus, using var in Java does not create an untyped variable.

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.

Working with Strings

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.

Declaring and initializing strings

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

Tip Class variables and instance variables are automatically initialized to empty strings, but local variables aren't. To initialize a local string variable to an empty string, use a statement like this:

String s = "";

Combining strings

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

Tip When Java concatenates strings, it doesn't insert any blank spaces between the strings. Thus, if you want to combine two strings and have a space appear between them, make sure that the first string ends with a space or the second string begins with a space. (In the preceding example, the first string ends with a space.)

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.

Converting primitives to strings

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.

Warning Be careful here: Java can confuse you about when the numbers are converted to strings in the course of evaluating the complete expression. Consider this admitedly far-fetched example:

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

Tip You can explicitly convert a primitive value to a string by using the toString method of the primitive type's wrapper class. To convert the int variable x to a string, for example, you use this statement:

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 strings to primitives

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

Integer

parseInt(String)

int x = Integer.parseInt("100");

Short

parseShort(String)

short x = Short.parseShort("100");

Long

parseLong(String)

long x = Long.parseLong("100");

Byte

parseByte(String)

byte x = Byte.parseByte("100");

Float

parseByte(String)

float x = Float.parseFloat("19.95");

Double

parseByte(String)

double x = Double.parseDouble("19.95");

Character

(none)

Boolean

parseBoolean

boolean x = Boolean.parseBoolean

(String)

("true");

Converting and Casting Numeric Data

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.

Automatic conversions

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:

  • If one of the values is a double, the other value is converted to a double.
  • If neither is a double but one is a float, the other is converted to a float.
    Illustration of numeric type conversions that Java allows, depicted with dotted arrows may cause some of the value’s precision to be lost - an int can be converted to a float.

    FIGURE 2-1: Numeric type conversions that are done automatically.

  • If neither is a double nor a float but one is a long, the other is converted to a long.
  • If all else fails, both values are converted to int.

Type casting

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.

Warning When you use casting, you run the risk of losing information. A double can hold larger numbers than an int, for example. In addition, an int can't hold the fractional part of a double. As a result, if you cast a double to an int, you run the risk of losing data or accuracy, so 3.1415 becomes 3, for example.

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.

Thinking Inside the Box

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.

Understanding Scope

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.

Remember In Java, a block is marked by a matching pair of braces. Java has many kinds of blocks, including class bodies, method bodies, and block statements that belong to statements such as if or for statements. But in each case, a block marks the scope boundaries for the variables declared within it.

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:

  • →2 The variable 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.
  • →13 The variable 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.
  • →15 The line markes the beginning of an if block that controls the scope of variable z.
  • →19 This line marks the end of the scope of variable z.
  • →22 This line marks the end of the 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

Technical stuff Strictly speaking, the scope of a local variable begins when the variable is initialized and ends when the block that contains the variable’s declaration ends. By contrast, the scope for a class or instance variable is the entire class in which the variable is declared. That means you can use a class or instance variable in a method that physically appears before the variable is declared, but you can’t use a local variable before it’s declared.

Shadowing Variables

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:

  • →3 The class variable x is declared in line 3. Its scope is the entire class body, ending at line 14.
  • →6 The class variable x is assigned a value in line 6. Then this value is printed to the console.
  • →8 A local variable named 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.
  • →9 This line prints the value of x to the console. The local variable's value, not the class variable’s value, is printed here.
  • →11 While a class variable is shadowed, you can access it by specifying the class name as shown in line 11. Here ShadowApp.x refers to the class variable.
  • →12 When the main method ends in line 12, the class variable x is no longer shadowed.
  • →14 When the 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

Technical stuff Note that the scope and of the local variable begins when it's declared, and the shadowing also begins when the local variable is declared. So, if you try to access the variable between the declaration and the initialization, the Java compiler complains that the variable hasn’t been initialized yet.

Warning Because shadowing is a common source of errors, I suggest that you avoid it as much as possible.

Printing Data with System.out

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.

Using standard input and output streams

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

  • Standard input: A stream designed to receive input data. This stream is usually connected to the keyboard at the computer where the program is run. That way, the user can type characters directly into the standard input stream. In the section “Getting Input with the Scanner Class,” later in this chapter, you connect this input stream to a class called Scanner, which makes it easy to read primitive data types from the standard input stream.
  • Standard output: A stream designed to display text output onscreen. When you run a Java program under Windows, a special console window opens, and the standard output stream is connected to it. Then any text you send to standard output is displayed in that window.
  • Standard error: Another stream designed for output. This stream is also connected to the console window. As a result, text written to the standard output stream is often intermixed with text written to the error stream.

Tip Windows and other operating systems allow you to redirect standard output to some other destination — typically a file. When you do that, only the standard output data is redirected. Text written to standard error is still displayed in the console window.

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

System.in

Standard input

System.out

Standard output

System.err

Standard error

Using System.out and System.err

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

Getting Input with the Scanner Class

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

}

}

Importing the Scanner class

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.

Tip If you’re using other classes in the java.util package, you can import the entire package by coding the import statement like this:

import java.util.*;

Declaring and creating a Scanner object

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.

Getting 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

boolean nextBoolean()

Reads a boolean value from the user.

byte nextByte()

Reads a byte value from the user.

double nextDouble()

Reads a double value from the user.

float nextFloat()

Reads a float value from the user.

int nextInt()

Reads an int value from the user.

String nextLine()

Reads a String value from the user.

long nextLong()

Reads a long value from the user.

short nextShort()

Reads a short value from the user.

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.

Technical stuff If the user enters a value that can't be converted to the correct type, the program crashes, which means that it terminates abruptly. As the program crashes, it displays a cryptic error message that indicates what caused the failure. If you enter three instead of an actual number, for example, the console window looks something like this:

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.

Tip You can prevent the nextInt and similar methods from crashing with incorrect input data by first using one of the methods listed in Table 2-7 to test the next input to make sure it's valid. I haven’t yet covered the Java statements you need to perform this test, but don’t worry; in Book 2, Chapter 8, I show you the solution.

TABLE 2-7 Scanner Class Methods That Check for Valid Input Values

Method

Explanation

boolean hasNextBoolean()

Returns true if the next value entered by the user is a valid boolean value.

boolean hasNextByte()

Returns true if the next value entered by the user is a valid byte value.

boolean hasNextDouble()

Returns true if the next value entered by the user is a valid double value.

boolean hasNextFloat()

Returns true if the next value entered by the user is a valid float value.

boolean hasNextInt()

Returns true if the next value entered by the user is a valid int value.

boolean hasNextLong()

Returns true if the next value entered by the user is a valid long value.

boolean hasNextShort()

Returns true if the next value entered by the user is a valid short value.

Getting Input with the JOptionPane Class

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.

Screenshot of a dialog box displayed by the JOptionPane class to enter an integer.

FIGURE 2-2: A dialog box displayed by the JOptionPane class.

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:

  • →1 This line imports the JOptionPane class.
  • →7–8 This statement displays an input dialog box with the prompt Enter an integer: and assigns the string entered by the user to the variable named s.
  • →9 This statement uses the parseInt method of the Integer class to convert the string entered by the user to an integer.
  • →10 This statement displays the integer value to confirm that the data entered by the user was converted properly to an integer.

Technical stuff This program terminates abruptly if the user enters anything other than an integer in the input dialog box. If the user enters ten, for example, the program terminates, and a cryptic message indicating that a NumberFormatException has occurred is displayed. In Book 2, Chapter 8, you learn how to provide a more understandable message in this situation. Until then, just be careful to enter correct numbers when you use the JOptionPane class.

Using enum to Create Your Own Data Types

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