As you learned in the previous chapter, an object stores its state in fields.
int cadence = 0; int speed = 0; int gear = 1;
The What Is an Object? section (page 33) introduced you to fields, but you probably still have a few questions, such as: What are the rules and conventions for naming a field? Besides int
, what other data types are there? Do fields have to be initialized when they are declared? Are fields assigned a default value if they are not explicitly initialized? We’ll explore the answers to such questions in this chapter, but before we do, there are a few technical distinctions you must first become aware of. In the Java programming language, the terms “field” and “variable” are both used; this is a common source of confusion among new developers, since both often seem to refer to the same thing.
The Java programming language defines the following kinds of variables:
Instance Variables (Non-Static Fields). Technically speaking, objects store their individual state in “non-static fields,” that is, fields declared without the static
keyword. Non-static fields are also known as instance variables because their values are unique to each instance of a class (to each object, in other words); the currentSpeed
of one bicycle is independent from the currentSpeed
of another.
Class Variables (Static Fields). A class variable is any field declared with the static
modifier; this tells the compiler that there is exactly one copy of this variable in existence, regardless of how many times the class has been instantiated. A field defining the number of gears for a particular kind of bicycle could be marked as static
since conceptually the same number of gears will apply to all instances. The code static int numGears = 6;
would create such a static field. Additionally, the keyword final
could be added to indicate that the number of gears will never change.
Local Variables. Similar to how an object stores its state in fields, a method will often store its temporary state in local variables. The syntax for declaring a local variable is similar to declaring a field (for example, int count = 0;
). There is no special keyword designating a variable as local; that determination comes entirely from the location in which the variable is declared—which is between the opening and closing braces of a method. As such, local variables are only visible to the methods in which they are declared; they are not accessible from the rest of the class.
Parameters. You’ve already seen examples of parameters, both in the Bicycle
class and in the main
method of the “Hello World!” application. Recall that the signature for the main
method is public static void main(String[] args)
. Here, the args
variable is the parameter to this method. The important thing to remember is that parameters are always classified as “variables,” not “fields.” This applies to other parameter-accepting constructs as well (such as constructors and exception handlers) that you’ll learn about later in the tutorial.
Having said that, the remainder of this tutorial uses the following general guidelines when discussing fields and variables. If we are talking about “fields in general” (excluding local variables and parameters), we may simply say “fields.” If the discussion applies to “all of the above,” we may simply say “variables.” If the context calls for a distinction, we will use specific terms (static field, local variable, etc.) as appropriate. You may also occasionally see the term “member” used as well. A type’s fields, methods, and nested types are collectively called its members.
Every programming language has its own set of rules and conventions for the kinds of names that you’re allowed to use, and the Java programming language is no different. The rules and conventions for naming your variables can be summarized as follows:
Variable names are case sensitive. A variable’s name can be any legal identifier—an unlimited-length sequence of Unicode letters and digits, beginning with a letter, the dollar sign, “$
”, or the underscore character, “_
”. The convention, however, is to always begin your variable names with a letter, not “$
” or “_
”. Additionally, the dollar sign character, by convention, is never used at all. You may find some situations were auto-generated names will contain the dollar sign, but your variable names should always avoid using it. A similar convention exists for the underscore character; while it’s technically legal to begin your variable’s name with “_
”, this practice is discouraged. White space is not permitted.
Subsequent characters may be letters, digits, dollar signs, or underscore characters. Conventions (and common sense) apply to this rule as well. When choosing a name for your variables, use full words instead of cryptic abbreviations. Doing so will make your code easier to read and understand. In many cases it will also make your code self-documenting; fields named cadence
, speed
, and gear
, for example, are much more intuitive than abbreviated versions, such as s
, c
, and g
. Also keep in mind that the name you choose must not be a keyword or reserved word. See Appendix A, “Java Language Keywords” on page 603.
If the name you choose consists of only one word, spell that word in all lowercase letters. If it consists of more than one word, capitalize the first letter of each subsequent word. The names gearRatio
and currentGear
are prime examples of this convention. If your variable stores a constant value, such as static final int NUM_GEARS = 6
, the convention changes slightly, capitalizing every letter and separating subsequent words with the underscore character. By convention, the underscore character is never used elsewhere.
The Java programming language is strongly typed, which means that all variables must first be declared before they can be used. This involves stating the variable’s type and name, as you’ve already seen:
int gear = 1;
Doing so tells your program that a field named “gear” exists, holds numerical data, and has an initial value of “1”. A variable’s data type determines the values it may contain, plus the operations that may be performed on it. In addition to int
, the Java programming language supports seven other primitive data types. A primitive type is predefined by the language and is named by a reserved keyword. Primitive values do not share state with other primitive values. The eight primitive data types supported by the Java programming language are:
byte. The byte
data type is an 8-bit signed two’s complement integer. It has a minimum value of –128 and a maximum value of 127 (inclusive). The byte
data type can be useful for saving memory in large arrays, where the memory savings actually matters. You’ll learn about arrays on page 49. They can also be used in place of int
, where their limits help to clarify your code; the fact that a variable’s range is limited can serve as a form of documentation.
short. The short
data type is a 16-bit signed two’s complement integer. It has a minimum value of –32,768 and a maximum value of 32,767 (inclusive). As with byte
, the same guidelines apply: you can use a short
to save memory in large arrays, in situations where the memory savings actually matters.
int. The int
data type is a 32-bit signed two’s complement integer. It has a minimum value of –2,147,483,648 and a maximum value of 2,147,483,647 (inclusive). For integral values, this data type is generally the default choice unless there is a reason (like the above) to choose something else. This data type will most likely be large enough for the numbers your program will use, but if you need a wider range of values, use long
instead.
long. The long
data type is a 64-bit signed two’s complement integer. It has a minimum value of –9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807 (inclusive). Use this data type when you need a range of values wider than those provided by int
.
float. The float
data type is a single-precision 32-bit IEEE 754 floating point. Its range of values is beyond the scope of this discussion, but is specified in section 4.2.3 of the Java Language Specification.[1] As with the recommendations for byte
and short
, use a float
(instead of double
) if you need to save memory in large arrays of floating point numbers. This data type should never be used for precise values, such as currency. For that, you will need to use the java.math.BigDecimal
class instead.[2] Chapter 8 covers BigDecimal
and other useful classes provided by the Java platform.
double. The double
data type is a double-precision 64-bit IEEE 754 floating point. Its range of values is beyond the scope of this discussion, but is specified in section 4.2.3 of the Java Language Specification. For decimal values, this data type is generally the default choice. As mentioned above, this data type should never be used for precise values, such as currency.
boolean. The boolean
data type has only two possible values: true
and false
. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its “size” isn’t something that’s precisely defined.
char. The char
data type is a single 16-bit Unicode character. It has a minimum value of 'u0000'
(or 0) and a maximum value of 'uffff'
(or 65,535 inclusive).
In addition to the eight primitive data types listed above, the Java programming language also provides special support for character strings via the java.lang.String
class.[3] Enclosing your character string within double quotes will automatically create a new String
object; for example, String s = "this is a string";
. String
objects are immutable, which means that once created, their values cannot be changed. The String
class is not technically a primitive data type, but considering the special support given to it by the language, you’ll probably tend to think of it as such. You’ll learn more about the String
class in Chapter 8.
It’s not always necessary to assign a value when a field is declared. Fields that are declared but not initialized will be set to a resonable default by the compiler. Generally speaking, this default will be zero or null
, depending on the data type. Relying on such default values, however, is generally considered bad programming style.
Table 3.1 summarizes the default values for the above data types.
Local variables are slightly different; the compiler never assigns a default value to an uninitialized local variable. If you cannot initialize your local variable where it is declared, make sure to assign it a value before you attempt to use it. Accessing an uninitialized local variable will result in a compile-time error.
You may have noticed that the new
keyword isn’t used when initializing a variable of a primitive type. Primitive types are special data types built into the language; they are not objects created from a class. A literal is the source code representation of a fixed value; literals are represented directly in your code without requiring computation. As shown below, it’s possible to assign a literal to a variable of a primitive type:
boolean result = true; char capitalC = 'C'; byte b = 100; short s = 10000; int i = 100000;
The integral types (byte
, short
, int
, and long
) can be expressed using decimal, octal, or hexadecimal number systems. Decimal is the number system you already use every day; it’s based on 10 digits, numbered 0 through 9. The octal number system is base 8, consisting of the digits 0 through 7. The hexadecimal system is base 16, whose digits are the numbers 0 through 9 and the letters A through F. For general-purpose programming, the decimal system is likely to be the only number system you’ll ever use. However, if you need octal or hexadecimal, the following example shows the correct syntax. The prefix 0
indicates octal, whereas 0x
indicates hexadecimal.
int decVal = 26; // The number 26, in decimal int octVal = 032; // The number 26, in octal int hexVal = 0x1a; // The number 26, in hexadecimal
The floating point types (float
and double
) can also be expressed using E
or e
(for scientific notation), F
or f
(32-bit float literal), and D
or d
(64-bit double literal; this is the default and by convention is omitted).
double d1 = 123.4; double d2 = 1.234e2; // same value as d1, // but in scientific notation float f1 = 123.4f;
Literals of types char
and String
may contain any Unicode (UTF-16) characters. If your editor and file system allow it, you can use such characters directly in your code. If not, you can use a “Unicode escape” such as 'u0108'
(capital C with circumflex) or "Su00ED seu00F1or"
(Sí Señor in Spanish). Always use ‘single quotes’ for char
literals and “double quotes” for String
literals. Unicode escape sequences may be used elsewhere in a program (such as in field names, for example), not just in char
or String
literals.
The Java programming language also supports a few special escape sequences for char
and String
literals: (backspace),
(tab),
(line feed), f
(form feed),
(carriage return), "
(double quote), '
(single quote), and \
(backslash).
There’s also a special null
literal that can be used as a value for any reference type. null
may be assigned to any variable, except variables of primitive types. There’s little you can do with a null
value beyond testing for its presence. Therefore, null
is often used in programs as a marker to indicate that some object is unavailable.
Finally, there’s also a special kind of literal called a class literal, formed by taking a type name and appending “.class
”; for example, String.class
. This refers to the object (of type Class
) that represents the type itself.
An array is a container object that holds a fixed number of values of a single type. The length of an array is established when the array is created. After creation, its length is fixed. You’ve seen an example of arrays already, in the main
method of the “Hello World!” application. This section discusses arrays in greater detail.
Each item in an array is called an element, and each element is accessed by its numerical index. As shown in Figure 3.1, numbering begins with 0. The 9th element, for example, would therefore be accessed at index 8.
The following program, ArrayDemo
,[4] creates an array of integers, puts some values in it, and prints each value to standard output.
class ArrayDemo { public static void main(String[] args) { int[] anArray; // declares an array of integers anArray = new int[10]; // allocates memory for 10 integers anArray[0] = 100; // initialize first element anArray[1] = 200; // initialize second element anArray[2] = 300; // etc. anArray[3] = 400; anArray[4] = 500; anArray[5] = 600; anArray[6] = 700; anArray[7] = 800; anArray[8] = 900; anArray[9] = 1000; System.out.println("Element at index 0: " + anArray[0]); System.out.println("Element at index 1: " + anArray[1]); System.out.println("Element at index 2: " + anArray[2]); System.out.println("Element at index 3: " + anArray[3]); System.out.println("Element at index 4: " + anArray[4]); System.out.println("Element at index 5: " + anArray[5]); System.out.println("Element at index 6: " + anArray[6]); System.out.println("Element at index 7: " + anArray[7]); System.out.println("Element at index 8: " + anArray[8]); System.out.println("Element at index 9: " + anArray[9]); } }
The output from this program is:
Element at index 0: 100 Element at index 1: 200 Element at index 2: 300 Element at index 3: 400 Element at index 4: 500 Element at index 5: 600 Element at index 6: 700 Element at index 7: 800 Element at index 8: 900 Element at index 9: 1000
In a real-world programming situation, you’d probably use one of the supported looping constructs to iterate through each element of the array, rather than write each line individually as shown above. However, this example clearly illustrates the array syntax. You’ll learn about the various looping constructs (for
, while
, and do-while
) in the Control Flow Statements section (page 69).
The above program declares anArray
with the following line of code:
int[] anArray; // declares an array of integers
Like declarations for variables of other types, an array declaration has two components: the array’s type and the array’s name. An array’s type is written as type[]
, where type is the data type of the contained elements; the square brackets are special symbols indicating that this variable holds an array. The size of the array is not part of its type (which is why the brackets are empty). An array’s name can be anything you want, provided that it follows the rules and conventions as previously discussed in the Naming section (page 44). As with variables of other types, the declaration does not actually create an array—it simply tells the compiler that this variable will hold an array of the specified type.
Similarly, you can declare arrays of other types:
byte[] anArrayOfBytes; short[] anArrayOfShorts; long[] anArrayOfLongs; float[] anArrayOfFloats; double[] anArrayOfDoubles; boolean[] anArrayOfBooleans; char[] anArrayOfChars; String[] anArrayOfStrings;
You can also place the square brackets after the array’s name:
float anArrayOfFloats[]; // this form is discouraged
However, convention discourages this form; the brackets identify the array type and should appear with the type designation.
One way to create an array is with the new
operator. The next statement in the ArrayDemo
program allocates an array with enough memory for ten integer elements and assigns the array to the anArray
variable.
anArray = new int[10]; // create an array of integers
If this statement were missing, the compiler would print an error like the following, and compilation would fail:
ArrayDemo.java:4: Variable anArray may not have been initialized.
The next few lines assign values to each element of the array:
anArray[0] = 100; // initialize first element anArray[1] = 200; // initialize second element anArray[2] = 300; // etc.
Each array element is accessed by its numerical index:
System.out.println("Element 1 at index 0: " + anArray[0]); System.out.println("Element 2 at index 1: " + anArray[1]); System.out.println("Element 3 at index 2: " + anArray[2]);
Alternatively, you can use the shortcut syntax to create and initialize an array:
int[] anArray = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
Here the length of the array is determined by the number of values provided between {
and }
.
You can also declare an array of arrays (also known as a multidimensional array) by using two or more sets of square brackets, such as String[][] names
. Each element, therefore, must be accessed by a corresponding number of index values.
In the Java programming language, a multidimensional array is simply an array whose components are themselves arrays. This is unlike arrays in C or Fortran. A consequence of this is that the rows are allowed to vary in length, as shown in the following MultiDimArrayDemo
[5] program:
class MultiDimArrayDemo { public static void main(String[] args) { String[][] names = {{"Mr. ", "Mrs. ", "Ms. "}, {"Smith", "Jones"}}; System.out.println(names[0][0] + names[1][0]); // Mr. Smith System.out.println(names[0][2] + names[1][1]); // Ms. Jones } }
The output from this program is:
Mr. Smith Ms. Jones
Finally, you can use the built-in length
property to determine the size of any array. The code
System.out.println(anArray.length);
will print the array’s size to standard output.
The System
class has an arraycopy
method that you can use to efficiently copy data from one array into another:
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
The two Object
arguments specify the array to copy from and the array to copy to. The three int
arguments specify the starting position in the source array, the starting position in the destination array, and the number of array elements to copy.
The following program, ArrayCopyDemo
, declares an array of char
elements, spelling the word “decaffeinated.” It uses arraycopy
to copy a subsequence of array components into a second array:
class ArrayCopyDemo { public static void main(String[] args) { char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd' }; char[] copyTo = new char[7]; System.arraycopy(copyFrom, 2, copyTo, 0, 7); System.out.println(new String(copyTo)); } }
The output from this program is:
caffein
The Java programming language uses both “fields” and “variables” as part of its terminology. Instance variables (non-static fields) are unique to each instance of a class. Class variables (static fields) are fields declared with the static
modifier; there is exactly one copy of a class variable, regardless of how many times the class has been instantiated. Local variables store temporary state inside a method. Parameters are variables that provide extra information to a method; both local variables and parameters are always classified as “variables” (not “fields”). When naming your fields or variables, there are rules and conventions that you should (or must) follow.
The eight primitive data types are: byte, short, int, long, float, double, boolean, and char. The java.lang.String
class represents character strings. The compiler will assign a reasonable default value for fields of the above types; for local variables, a default value is never assigned. A literal is the source code representation of a fixed value. An array is a container object that holds a fixed number of values of a single type. The length of an array is established when the array is created. After creation, its length is fixed.
Now that you’ve learned how to declare and initialize variables, you probably want to know how to do something with them. Learning the operators of the Java programming language is a good place to start. Operators are special symbols that perform specific operations on one, two, or three operands, and then return a result.
As we explore the operators of the Java programming language, it may be helpful for you to know ahead of time which operators have the highest precedence. The operators in Table 3.2 are listed according to precedence order. The closer to the top of the table an operator appears, the higher its precedence. Operators with higher precedence are evaluated before operators with relatively lower precedence. Operators on the same line have equal precedence. When operators of equal precedence appear in the same expression, a rule must govern which is evaluated first. All binary operators except for the assignment operators are evaluated from left to right; assignment operators are evaluated right to left.
Table 3.2. Operator Precedence
Operators | Precedence |
---|---|
postfix |
|
unary |
|
multiplicative |
|
additive |
|
shift |
|
relational |
|
equality |
|
bitwise AND |
|
bitwise exclusive OR |
|
bitwise inclusive OR |
|
logical AND |
|
logical OR |
|
ternary |
|
assignment |
|
In general-purpose programming, certain operators tend to appear more frequently than others; for example, the assignment operator “=
” is far more common than the unsigned right shift operator “>>>
”. With that in mind, the following discussion focuses first on the operators that you’re most likely to use on a regular basis, and ends focusing on those that are less common. Each discussion is accompanied by sample code that you can compile and run. Studying its output will help enforce what you’ve just learned.
One of the most common operators that you’ll encounter is the simple assignment operator “=
”. You saw this operator in the Bicycle
class; it assigns the value on its right to the operand on its left:
int cadence = 0; int speed = 0; int gear = 1;
This operator can also be used on objects to assign object references, as discussed in Chapter 8.
The Java programming language provides operators that perform addition, subtraction, multiplication, and division. There’s a good chance you’ll recognize them by their counterparts in basic mathematics. The only symbol that might look new to you is “%
”, which divides one operand by another and returns the remainder as its result.
+ additive operator (also used for String concatenation) - subtraction operator * multiplication operator / division operator % remainder operator
The following program, ArithmeticDemo
,[6] tests the arithmetic operators.
class ArithmeticDemo { public static void main (String[] args){ int result = 1 + 2; // result is now 3 System.out.println(result); result = result - 1; // result is now 2 System.out.println(result); result = result * 2; // result is now 4 System.out.println(result); result = result / 2; // result is now 2 System.out.println(result); result = result + 8; // result is now 10 result = result % 7; // result is now 3 System.out.println(result); } }
You can also combine the arithmetic operators with the simple assignment operator to create compound assignments. For example, x+=1;
and x=x+1;
both increment the value of x
by 1.
The +
operator can also be used for concatenating (joining) two strings together, as shown in the following ConcatDemo
[7] program:
class ConcatDemo { public static void main(String[] args){ String firstString = "This is"; String secondString = " a concatenated string."; String thirdString = firstString+secondString; System.out.println(thirdString); } }
By the end of this program, the variable thirdString
contains “This is a concatenated string.”, which gets printed to standard output.
The unary operators require only one operand; they perform various operations such as incrementing/decrementing a value by one, negating an expression, or inverting the value of a boolean.
+ Unary plus operator; indicates positive value (numbers are positive without this, however) - Unary minus operator; negates an expression ++ Increment operator; increments a value by 1 -- Decrement operator; decrements a value by 1 ! Logical complement operator; inverts the value of a boolean
The following program, UnaryDemo
,[8] tests the unary operators:
class UnaryDemo { public static void main(String[] args){ int result = +1; // result is now 1 System.out.println(result); result--; // result is now 0 System.out.println(result); result++; // result is now 1 System.out.println(result); result = -result; // result is now -1 System.out.println(result); boolean success = false; System.out.println(success); // false System.out.println(!success); // true } }
The increment/decrement operators can be applied before (prefix) or after (postfix) the operand. The code result++;
and ++result;
will both end in result
being incremented by one. The only difference is that the prefix version (++result
) evaluates to the incremented value, whereas the postfix version (result++
) evaluates to the original value. If you are just performing a simple increment/decrement, it doesn’t really matter which version you choose. But if you use this operator in part of a larger expression, the one that you choose may make a significant difference.
The following program, PrePostDemo
, illustrates the prefix/postfix unary increment operator:
class PrePostDemo { public static void main(String[] args){ int i = 3; i++; System.out.println(i); // "4" ++i; System.out.println(i); // "5" System.out.println(++i); // "6" System.out.println(i++); // "6" System.out.println(i); // "7" } }
The equality and relational operators determine if one operand is greater than, less than, equal to, or not equal to another operand. The majority of these operators will probably look familiar to you as well. Keep in mind that you must use “==
”, not “=
”, when testing if two primitive values are equal.
== equal to != not equal to > greater than >= greater than or equal to < less than <= less than or equal to
The following program, ComparisonDemo
,[9] tests the comparison operators:
class ComparisonDemo { public static void main(String[] args) { int value1 = 1; int value2 = 2; if(value1 == value2) System.out.println("value1 == value2"); if(value1 != value2) System.out.println("value1 != value2"); if(value1 > value2) System.out.println("value1 > value2"); if(value1 < value2) System.out.println("value1 < value2"); if(value1 <= value2) System.out.println("value1 <= value2"); } }
Output: value1 != value2 value1 < value2 value1 <= value2
The &&
and ||
operators perform Conditional-AND and Conditional-OR operations on two boolean expressions. These operators exhibit “short-circuiting” behavior, which means that the second operand is evaluated only if needed.
&& Conditional-AND || Conditional-OR
The following program, ConditionalDemo1
,[10] tests these operators:
class ConditionalDemo1 { public static void main(String[] args){ int value1 = 1; int value2 = 2; if((value1 == 1) && (value2 == 2)) System.out.println("value1 is 1 AND value2 is 2"); if((value1 == 1) || (value2 == 1)) System.out.println("value1 is 1 OR value2 is 1"); } }
Another conditional operator is ?:
, which can be thought of as shorthand for an if-then-else
statement (discussed in the Control Flow Statements section, page 69). This operator is also known as the ternary operator because it uses three operands. In the following example, this operator should be read as: “If someCondition
is true
, assign the value of value1
to result
. Otherwise, assign the value of value2
to result
.”
The following program, ConditionalDemo2
,[11] tests the ?:
operator:
class ConditionalDemo2 { public static void main(String[] args){ int value1 = 1; int value2 = 2; int result; boolean someCondition = true; result = someCondition ? value1 : value2; System.out.println(result); } }
Because someCondition
is true, this program prints “1” to the screen. Use the ?:
operator instead of an if-then-else
statement if it makes your code more readable; for example, when the expressions are compact and without side-effects (such as assignments).
The instanceof
operator compares an object to a specified type. You can use it to test if an object is an instance of a class, an instance of a subclass, or an instance of a class that implements a particular interface.
The following program, InstanceofDemo
,[12] defines a parent class (named Parent
), a simple interface (named MyInterface
), and a child class (named Child
) that inherits from the parent and implements the interface.
class InstanceofDemo { public static void main(String args[]) { Parent obj1 = new Parent(); Parent obj2 = new Child(); System.out.println("obj1 instanceof Parent: " + (obj1 instanceof Parent)); System.out.println("obj1 instanceof Child: " + (obj1 instanceof Child)); System.out.println("obj1 instanceof MyInterface: " + (obj1 instanceof MyInterface)); System.out.println("obj2 instanceof Parent: " + (obj2 instanceof Parent)); System.out.println("obj2 instanceof Child: " + (obj2 instanceof Child)); System.out.println("obj2 instanceof MyInterface: " + (obj2 instanceof MyInterface)); } }
class Parent{} class Child extends Parent implements MyInterface{} interface MyInterface{} Output: obj1 instanceof Parent: true obj1 instanceof Child: false obj1 instanceof MyInterface: false obj2 instanceof Parent: true obj2 instanceof Child: true obj2 instanceof MyInterface: true
When using the instanceof
operator, keep in mind that null
is not an instance of anything.
The Java programming language also provides operators that perform bitwise and bit shift operations on integral types. The operators discussed in this section are less commonly used. Therefore, their coverage is brief; the intent is to simply make you aware that these operators exist.
The unary bitwise complement operator “~
” inverts a bit pattern; it can be applied to any of the integral types, making every “0” a “1” and every “1” a “0”. For example, a byte
contains 8 bits; applying this operator to a value whose bit pattern is “00000000” would change its pattern to “11111111”.
The signed left shift operator “<<
” shifts a bit pattern to the left, and the signed right shift operator “>>
” shifts a bit pattern to the right. The bit pattern is given by the left-hand operand, and the number of positions to shift by the right-hand operand. The unsigned right shift operator “>>>
” shifts a zero into the leftmost position, while the leftmost position after ">>"
depends on sign extension.
The bitwise &
operator performs a bitwise AND operation.
The bitwise ^
operator performs a bitwise exclusive OR operation.
The bitwise |
operator performs a bitwise inclusive OR operation.
For &
and |
above, the result has a 1 in each bit position for which both of the operands have a 1.
The following program, BitDemo
,[13] uses the bitwise AND operator to print the number “2” to standard output.
class BitDemo { public static void main(String[] args) { int bitmask = 0x000F; int val = 0x2222; System.out.println(val & bitmask); // prints "2" } }
The following quick reference summarizes the operators supported by the Java programming language.
Simple Assignment Operator
= simple assignment operator
Arithmetic Operators
+ additive operator (also used for String concatenation) - subtraction operator * multiplication operator / division operator % remainder operator
Unary Operators
+ Unary plus operator; indicates positive value (numbers are positive without this, however) - Unary minus operator; negates an expression ++ Increment operator; increments a value by 1 -- Decrement operator; decrements a value by 1 ! Logical complement operator; inverts the value of a boolean
Equality and Relational Operators
== equal to != not equal to > greater than >= greater than or equal to < less than <= less than or equal to
Conditional Operators
&& Conditional-AND || Conditional-OR ?: Ternary (shorthand for if-then-else statement)
Type Comparison Operator
instanceof compares an object to a specified type
Bitwise and Bit Shift Operators
~ unary bitwise complement << signed left shift >> signed right shift >>> unsigned right shift & bitwise AND ^ bitwise exclusive OR | bitwise inclusive OR
Now that you understand variables and operators, it’s time to learn about expressions, statements, and blocks. Operators may used in building expressions, which compute values; expressions are the core components of statements; statements may be grouped into blocks.
An expression is a construct made up of variables, operators, and method invocations, which are constructed according to the syntax of the language, that evaluates to a single value. You’ve already seen examples of expressions, illustrated in bold below:
int cadence = 0 ; anArray[0] = 100 ; System.out.println("Element 1 at index 0: " + anArray[0]); int result = 1 + 2 ; // result is now 3 if(value1 == value2 ) System.out.println("value1 == value2" );
The data type of the value returned by an expression depends on the elements used in the expression. The expression cadence = 0
returns an int
because the assignment operator returns a value of the same data type as its left-hand operand; in this case, cadence
is an int
. As you can see from the other expressions, an expression can return other types of values as well, such as boolean
or String
.
The Java programming language allows you to construct compound expressions from various smaller expressions as long as the data type required by one part of the expression matches the data type of the other. Here’s an example of a compound expression:
1 * 2 * 3
In this particular example, the order in which the expression is evaluated is unimportant because the result of multiplication is independent of order; the outcome is always the same, no matter in which order you apply the multiplications. However, this is not true of all expressions. For example, the following expression gives different results, depending on whether you perform the addition or the division operation first:
x + y / 100 // ambiguous
You can specify exactly how an expression will be evaluated using balanced parenthesis: (
and )
. For example, to make the previous expression unambiguous, you could write the following:
(x + y) / 100 // unambiguous, recommended
If you don’t explicitly indicate the order for the operations to be performed, the order is determined by the precedence assigned to the operators in use within the expression. Operators that have a higher precedence get evaluated first. For example, the division operator has a higher precedence than does the addition operator. Therefore, the following two statements are equivalent:
x + y / 100 x + (y / 100) // unambiguous, recommended
When writing compound expressions, be explicit and indicate with parentheses which operators should be evaluated first. This practice makes code easier to read and to maintain.
Statements are roughly equivalent to sentences in natural languages. A statement forms a complete unit of execution. The following types of expressions can be made into a statement by terminating the expression with a semicolon (;
).
Assignment expressions
Any use of ++
or --
Method invocations
Object creation expressions
Such statements are called expression statements. Here are some examples of expression statements.
aValue = 8933.234; // assignment statement aValue++; // increment statement System.out.println("Hello World!"); // method invocation // statement Bicycle myBike = new Bicycle(); // object creation // statement
In addition to expression statements, there are two other kinds of statements: declaration statements and control flow statements. A declaration statement declares a variable. You’ve seen many examples of declaration statements already:
double aValue = 8933.234; // declaration statement
Finally, control flow statements regulate the order in which statements get executed. You’ll learn about control flow statements in the Control Flow Statements section (page 69).
A block is a group of zero or more statements between balanced braces and can be used anywhere a single statement is allowed. The following example, BlockDemo
,[14] illustrates the use of blocks:
class BlockDemo { public static void main(String[] args) { boolean condition = true; if (condition) { // begin block 1 System.out.println("Condition is true."); } // end block one else { // begin block 2 System.out.println("Condition is false."); } // end block 2 } }
The statements inside your source files are generally executed from top to bottom, in the order that they appear. Control flow statements, however, break up the flow of execution by employing decision making, looping, and branching, enabling your program to conditionally execute particular blocks of code. This section describes the decision-making statements (if-then
, if-then-else
, switch
), the looping statements (for
, while
, do-while
), and the branching statements (break
, continue
, return
) supported by the Java programming language.
The if-then
statement is the most basic of all the control flow statements. It tells your program to execute a certain section of code only if a particular test evaluates to true
. For example, the Bicycle
class could allow the brakes to decrease the bicycle’s speed only if the bicycle is already in motion. One possible implementation of the applyBrakes
method could be as follows:
void applyBrakes(){ if (isMoving){ // the "if" clause: bicycle must moving currentSpeed--; // the "then" clause: // decrease current speed } }
If this test evaluates to false
(meaning that the bicycle is not in motion), control jumps to the end of the if-then
statement.
In addition, the opening and closing braces are optional, provided that the “then” clause contains only one statement:
void applyBrakes(){ if (isMoving) currentSpeed--; // same as above, // but without braces }
Deciding when to omit the braces is a matter of personal taste. Omitting them can make the code more brittle. If a second statement is later added to the “then” clause, a common mistake would be forgetting to add the newly required braces. The compiler cannot catch this sort of error; you’ll just get the wrong results.
The if-then-else
statement provides a secondary path of execution when an “if” clause evaluates to false
. You could use an if-then-else
statement in the applyBrakes
method to take some action if the brakes are applied when the bicycle is not in motion. In this case, the action is to simply print an error message stating that the bicycle has already stopped.
void applyBrakes(){ if (isMoving) { currentSpeed--; } else { System.err.println("The bicycle has already stopped!"); } }
The following program, IfElseDemo
,[15] assigns a grade based on the value of a test score: an A for a score of 90% or above, a B for a score of 80% or above, and so on.
class IfElseDemo { public static void main(String[] args) { int testscore = 76; char grade; if (testscore >= 90) { grade = 'A'; } else if (testscore >= 80) { grade = 'B'; } else if (testscore >= 70) { grade = 'C'; } else if (testscore >= 60) { grade = 'D'; } else { grade = 'F'; } System.out.println("Grade = " + grade); } }
The output from the program is:
Grade = C
You may have noticed that the value of testscore
can satisfy more than one expression in the compound statement: 76 >= 70
and 76 >= 60
. However, once a condition is satisfied, the appropriate statements are executed (grade = 'C';)
and the remaining conditions are not evaluated.
Unlike if-then
and if-then-else
, the switch
statement allows for any number of possible execution paths. A switch
works with the byte
, short
, char
, and int
primitive data types. It also works with enumerated types discussed in the Enum Types section (page 128) and a few special classes that “wrap” certain primitive types: Character
,[16] Byte
,[17] Short
,[18] and Integer
[19] discussed in Chapter 8.
The following program, SwitchDemo
,[20] declares an int
named month
whose value represents a month out of the year. The program displays the name of the month, based on the value of month, using the switch
statement.
class SwitchDemo { public static void main(String[] args) { int month = 8; switch (month) { case 1: System.out.println("January"); break; case 2: System.out.println("February"); break; case 3: System.out.println("March"); break; case 4: System.out.println("April"); break; case 5: System.out.println("May"); break; case 6: System.out.println("June"); break; case 7: System.out.println("July"); break; case 8: System.out.println("August"); break; case 9: System.out.println("September"); break; case 10: System.out.println("October"); break; case 11: System.out.println("November"); break; case 12: System.out.println("December"); break; default: System.out.println("Invalid month.");break; } } }
In this case, “August” is printed to standard output.
The body of a switch
statement is known as a switch block. Any statement immediately contained by the switch
block may be labeled with one or more case
or default
labels. The switch
statement evaluates its expression and executes the appropriate case
.
Of course, you could also implement the same thing with if-then-else
statements:
int month = 8; if (month == 1) { System.out.println("January"); } else if (month == 2) { System.out.println("February"); } ... // and so on
Deciding whether to use if-then-else
statements or a switch
statement is sometimes a judgment call. You can decide which one to use based on readability and other factors. An if-then-else
statement can be used to make decisions based on ranges of values or conditions, whereas a switch
statement can make decisions based only on a single integer or enumerated value.
Another point of interest is the break
statement after each case
. Each break
statement terminates the enclosing switch
statement. Control flow continues with the first statement following the switch
block. The break
statements are necessary because without them, case
statements fall through; that is, without an explicit break
, control will flow sequentially through subsequent case
statements. The following program, SwitchDemo2
,[21] illustrates why it might be useful to have case
statements fall through:
class SwitchDemo2 { public static void main(String[] args) { int month = 2; int year = 2000; int numDays = 0; switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: numDays = 31; break; case 4: case 6: case 9: case 11: numDays = 30; break; case 2: if ( ((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0) ) numDays = 29; else numDays = 28; break; default: System.out.println("Invalid month."); break; } System.out.println("Number of Days = " + numDays); } }
This is the output from the program:
Number of Days = 29
Technically, the final break
is not required because flow would fall out of the switch
statement anyway. However, we recommend using a break
so that modifying the code is easier and less error-prone. The default
section handles all values that aren’t explicitly handled by one of the case
sections.
The while
statement continually executes a block of statements while a particular condition is true
. Its syntax can be expressed as:
while (expression) { statement(s) }
The while
statement evaluates expression, which must return a boolean
value. If the expression evaluates to true
, the while
statement executes the statement(s) in the while
block. The while
statement continues testing the expression and executing its block until the expression evaluates to false
. Using the while
statement to print the values from 1 through 10 can be accomplished as in the following WhileDemo
[22] program:
class WhileDemo { public static void main(String[] args){ int count = 1; while (count < 11) { System.out.println("Count is: " + count); count++; } } }
You can implement an infinite loop using the while
statement as follows:
while (true){ // your code goes here }
The Java programming language also provides a do-while
statement, which can be expressed as follows:
do { statement(s) } while (expression);
The difference between do-while
and while
is that do-while
evaluates its expression at the bottom of the loop instead of the top. Therefore, the statements within the do
block are always executed at least once, as shown in the following DoWhileDemo
[23] program:
class DoWhileDemo { public static void main(String[] args){ int count = 1; do { System.out.println("Count is: " + count); count++; } while (count <= 11); } }
The for
statement provides a compact way to iterate over a range of values. Programmers often refer to it as the “for loop” because of the way in which it repeatedly loops until a particular condition is satisfied. The general form of the for
statement can be expressed as follows:
for (initialization; termination; increment) { statement(s) }
When using this version of the for
statement, keep in mind that:
The initialization expression initializes the loop; it’s executed once, as the loop begins.
When the termination expression evaluates to false
, the loop terminates.
The increment expression is invoked after each iteration through the loop; it is perfectly acceptable for this expression to increment or decrement a value.
The following program, ForDemo
,[24] uses the general form of the for
statement to print the numbers 1 through 10 to standard output:
class ForDemo { public static void main(String[] args){ for(int i=1; i<11; i++){ System.out.println("Count is: " + i); } } }
The output of this program is:
Count is: 1 Count is: 2 Count is: 3 Count is: 4 Count is: 5 Count is: 6 Count is: 7 Count is: 8 Count is: 9 Count is: 10
Notice how the code declares a variable within the initialization expression. The scope of this variable extends from its declaration to the end of the block governed by the for
statement, so it can be used in the termination and increment expressions as well. If the variable that controls a for
statement is not needed outside of the loop, it’s best to declare the variable in the initialization expression. The names i
, j
, and k
are often used to control for
loops; declaring them within the initialization expression limits their life span and reduces errors.
The three expressions of the for
loop are optional; an infinite loop can be created as follows:
for ( ; ; ) { // infinite loop // your code goes here }
The for
statement also has another form designed for iteration through collections (see Chapter 11) and arrays (see the Arrays section beginning on page 49). This form is sometimes referred to as the enhanced for statement, and can be used to make your loops more compact and easy to read. To demonstrate, consider the following array, which holds the numbers 1 through 10:
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
The following program, EnhancedForDemo
,[25] uses the enhanced for
to loop through the array:
class EnhancedForDemo { public static void main(String[] args){ int[] numbers = {1,2,3,4,5,6,7,8,9,10}; for (int item : numbers) { System.out.println("Count is: " + item); } } }
In this example, the variable item
holds the current value from the numbers array. The output from this program is the same as before:
Count is: 1 Count is: 2 Count is: 3 Count is: 4 Count is: 5 Count is: 6 Count is: 7 Count is: 8 Count is: 9 Count is: 10
We recommend using this form of the for
statement instead of the general form whenever possible.
The break
statement has two forms: labeled and unlabeled. You saw the unlabeled form in the previous discussion of the switch
statement.
You can also use an unlabeled break
to terminate a for
, while
, or do-while
loop, as shown in the following BreakDemo
[26] program:
class BreakDemo {
public static void main(String[] args) {
int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076,
2000, 8, 622, 127 };
int searchfor = 12;
int i;
boolean foundIt = false;
for (i = 0; i < arrayOfInts.length; i++) {
if (arrayOfInts[i] == searchfor) {
foundIt = true;
break;
}
}
if (foundIt) {
System.out.println("Found " + searchfor +
" at index " + i);
} else {
System.out.println(searchfor + " not in the array");
}
}
}
This program searches for the number 12 in an array. The break
statement, shown in boldface, terminates the for
loop when that value is found. Control flow then transfers to the print statement at the end of the program.
Found 12 at index 4
An unlabeled break
statement terminates the innermost switch
, for
, while
, or do-while
statement, but a labeled break
terminates an outer statement. The following program, BreakWithLabelDemo
,[27] is similar to the previous program, but uses nested for
loops to search for a value in a two-dimensional array. When the value is found, a labeled break
terminates the outer for
loop (labeled “search”):
class BreakWithLabelDemo { public static void main(String[] args) { int[][] arrayOfInts = { { 32, 87, 3, 589 }, { 12, 1076, 2000, 8 }, { 622, 127, 77, 955 } }; int searchfor = 12; int i; int j = 0; boolean foundIt = false; search: for (i = 0; i < arrayOfInts.length; i++) { for (j = 0; j < arrayOfInts[i].length; j++) { if (arrayOfInts[i][j] == searchfor) { foundIt = true; break search; } } } if (foundIt) { System.out.println("Found " + searchfor + " at " + i + ", " + j); } else { System.out.println(searchfor + " not in the array"); } } }
This is the output of the program:
Found 12 at 1, 0
The break
statement terminates the labeled statement; it does not transfer the flow of control to the label. Control flow is transferred to the statement immediately following the labeled (terminated) statement.
The continue
statement skips the current iteration of a for
, while
, or do-while
loop. The unlabeled form skips to the end of the innermost loop’s body and evaluates the boolean
expression that controls the loop. The following program, ContinueDemo
,[28] steps through a String
, counting the occurrences of the letter “p”. If the current character is not a p, the continue
statement skips the rest of the loop and proceeds to the next character. If it is a p, the program increments the letter count.
class ContinueDemo { public static void main(String[] args) { String searchMe = "peter piper picked a peck of " + "pickled peppers"; int max = searchMe.length(); int numPs = 0; for (int i = 0; i < max; i++) { //interested only in p's if (searchMe.charAt(i) != 'p') continue; //process p's numPs++; } System.out.println("Found " + numPs + " p's in the string."); } }
Here is the output of this program:
Found 9 p's in the string.
To see this effect more clearly, try removing the continue
statement and recompiling. When you run the program again, the count will be wrong, saying that it found 35 p’s instead of 9.
A labeled continue
statement skips the current iteration of an outer loop marked with the given label. The following example program, ContinueWithLabelDemo
,[29] uses nested loops to search for a substring within another string. Two nested loops are required: one to iterate over the substring and one to iterate over the string being searched. The following program, ContinueWithLabelDemo
, uses the labeled form of continue to skip an iteration in the outer loop.
class ContinueWithLabelDemo { public static void main(String[] args) { String searchMe = "Look for a substring in me"; String substring = "sub"; boolean foundIt = false; int max = searchMe.length() - substring.length(); test: for (int i = 0; i <= max; i++) { int n = substring.length(); int j = i; int k = 0; while (n-- != 0) { if (searchMe.charAt(j++) != substring.charAt(k++)) { continue test; } } foundIt = true; break test; } System.out.println(foundIt ? "Found it" : "Didn't find it"); } }
Here is the output from this program:
Found it
The last of the branching statements is the return
statement. The return
statement exits from the current method, and control flow returns to where the method was invoked. The return
statement has two forms: one that returns a value, and one that doesn’t. To return a value, simply put the value (or an expression that calculates the value) after the return
keyword.
return ++count;
The data type of the returmed value must match the type of the method’s declared return value. When a method is declared void
, use the form of return
that doesn’t return a value.
return;
The Calling an Object’s Methods section (page 105) will cover everything you need to know about writing methods.
The if-then
statement is the most basic of all the control flow statements. It tells your program to execute a certain section of code only if a particular test evaluates to true
.
The if-then-else
statement provides a secondary path of execution when an “if” clause evaluates to false
.
Unlike if-then
and if-then-else
, the switch
statement allows for any number of possible execution paths.
The while
and do-while
statements continually execute a block of statements while a particular condition is true
.
The difference between do-while
and while
is that do-while
evaluates its expression at the bottom of the loop instead of the top. Therefore, the statements within the do
block are always executed at least once.
The for
statement provides a compact way to iterate over a range of values. It has two forms, one of which was designed for looping through collections and arrays.
[1] docs/books/jls/third_edition/html/typesValues.html
[2] docs/api/java/math/BigDecimal.html
[3] docs/api/java/lang/String.html
[4] tutorial/java/nutsandbolts/examples/ArrayDemo.java
[5] tutorial/java/nutsandbolts/examples/MultiDimArrayDemo.java
[6] tutorial/java/nutsandbolts/examples/ArithmeticDemo.java
[7] tutorial/java/nutsandbolts/examples/ConcatDemo.java
[8] tutorial/java/nutsandbolts/examples/UnaryDemo.java
[9] tutorial/java/nutsandbolts/examples/ComparisonDemo.java
[10] tutorial/java/nutsandbolts/examples/ConditionalDemo1.java
[11] tutorial/java/nutsandbolts/examples/ConditionalDemo2.java
[12] tutorial/java/nutsandbolts/examples/InstanceofDemo.java
[13] tutorial/java/nutsandbolts/examples/BitDemo.java
[14] tutorial/java/nutsandbolts/examples/BlockDemo.java
[15] tutorial/java/nutsandbolts/examples/IfElseDemo.java
[16] docs/api/java/lang/Character.html
[17] docs/api/java/lang/Byte.html
[18] docs/api/java/lang/Short.html
[19] docs/api/java/lang/Integer.html
[20] tutorial/java/nutsandbolts/examples/SwitchDemo.java
[21] tutorial/java/nutsandbolts/examples/SwitchDemo2.java
[22] tutorial/java/nutsandbolts/examples/WhileDemo.java
[23] tutorial/java/nutsandbolts/examples/DoWhileDemo.java
[24] tutorial/java/nutsandbolts/examples/ForDemo.java
[25] tutorial/java/nutsandbolts/examples/EnhancedForDemo.java
[26] tutorial/java/nutsandbolts/examples/BreakDemo.java
[27] tutorial/java/nutsandbolts/examples/BreakWithLabelDemo.java
[28] tutorial/java/nutsandbolts/examples/ContinueDemo.java
[29] tutorial/java/nutsandbolts/examples/ContinueWithLabelDemo.java
18.225.57.126