Data Types
Objective #1: List the primitive data types and their characteristics.
- Java requires you to formally declare variables before they are used in a method or class. Variables can more formally be called primitive variables. A declaration statement such as the following examples is used to declare a variable.
int num = 0;
double grade = 89.555;
boolean isFinished = false;
When declaring a variable you should assign it a legal and logical name and you must assign a specific data type and an initial value. By the way, a data type is sometimes more simply called a type. For the AP exam, you are ony responsible for using three of Java's primitive data types: int, double, and boolean. However, it is a good idea to familiar with the other 5 primitive types as well.
- The following statement is a declaration statement because it declares the variable num to be a variable of the int data type
int num = 0;
- You should initialize a variable to a specific value in its declaration statement since Java does not automatically initialize local variables to zero like the programming language Visual Basic The line of code
int num;
is dangerous since an error would occur later if you tried to print out or make use of an unitialized variable with statements like
System.out.println(num);
What would Java display in the statement above if the programmer did not previously store a value in num? Remember that zero is not automatically stored in local variables.
- Later in a program after you have declared a variable you can store a value in that variable with an assignment statement as in
num = 15;
or
num = otherNum + 10;
- Two or more variables may be declared in the same statement but it is not considered to be good style. The following statements will not cause compile errors:
int num1, num2;
double grade1 = 35.45, grade2 = 9.99;
- String and other types are not primitive data types but are actually classes from which you can instantiate objects. In other words, a primitive variable is not considered to be an object.
- Primitive variables of the int data type can only store whole numbers and cannot store floating-point values (i.e. decimal numbers.) This data type is often referred to as the "integer" data type. An int variable has a size of 4 bytes.
The statement int num = 4.0; causes an error since num cannot store the .0 part of 4.0 even though it is equivalent to 4 mathematically.
- Primitive variables of the double data type can store whole numbers or floating-point values. Computer scientists refer to decimal numbers as "floating-point values". A double variable has a size of 8 bytes. The letter e can be used in a number to represent exponential (i.e. scientific) notation.
The statements double num = 1200; and double num = 1.2e3; and double num = 1.2E3; are equivalent.
The statements double num = 0.0012; and double num = 1.2e-3; and double num = 1.2e-3; are equivalent.
- Variables of the boolean data type can either store the boolean values true or false. A boolean variable has a size of 1 bit.
- Here are all 8 of the Java primitive data types. However the only ones that you have to know for the AP exam and unit tests are boolean, int, and double.
Type |
Stores |
Default Value |
Size |
Range |
| boolean |
true or false |
false |
1 bit |
true or false only |
| char |
Unicode character |
\u0000 |
2 bytes |
0 to 2^16 - 1 (\u0000 to \uFFFF) |
| byte |
signed integer |
0 |
1 byte |
-128 to 127 |
| short |
signed integer |
0 |
2 bytes |
-32768 to 32767 |
| int |
signed integer |
0 |
4 bytes |
-2147483648 to 2147483647 |
| long |
signed integer |
0 |
8 bytes |
-9223372036854775808 to 9223372036854775807 |
| float |
floating-point value |
0.0f |
4 bytes |
+- 1.4E-45 to +-1.797693134823157E+308 |
| double |
floating-point value |
0.0 |
8 bytes |
+-439E-324 to +-1.7976931348623157E+308 |
- Besides the familiar operators, *, /, +, and - for
multiplication, division, addition and subtraction, Java supports the use
of the % for modulus. Modulus
computes the remainder of dividing one integer by another. For example, num
= 8 % 3; would result with the variable num storing the value 2 since
2 is the remainder of 8 divided by 3. With the statement, num
= 3 % 8; would
cause 3 to be stored in num since 3 is the remainder of 3 divided by 8. In the order of operations, modulus ( % ) is performed along with multiplication and division,
from left to right. That is, the expression 11 % 3 * 4 - 9 % 4 evaluates as 7 since 11 % 3 is performed first and then 2 * 4 and then 9 % 4 and finally 8 - 1.
- The % symbol can also be used in Java to find the decimal part of a decimal value although this is not tested on the AP exam. For example
System.out.println(1.234 % 1); // displays .234
- Java also allows the use of the compound operators *=, /=, %=, +=, and
-=. That is instead of typing out the assignment statement
num = num + 2;
you can type the simpler
num += 2;
- Java allows the use of the incrementing and decrementing operators. The
incrementing operator ++ can be used to add one to a variable as in
num++;
Notice there is no space typed between the variable name and the ++ symbol.
This statement is equivalent to
num = num + 1;
and can even be rewritten as
++num;
The decrementing operator -- can be used to
subtract one from a variable as in
num--;
Objective #2: Explain how primitive types are copied and be able to trace their values.
- The data types, int, double,
and boolean are primitive
data types. They store numeric values (except boolean which stores true's
and false's) and are built-in to the Java
language.
- When you assign a variable with a primitive data type
to another one, there are two independent variables. For example, after the
following code executes
int num1 = 5;
int num2 = num1;
the variable num1 is located somwhere in the
memory of the computer and stores the value 5 while the separate variable num2 is
located somewhere else in the memory of the computer and it stores the value
5.
- It is illegal to redeclare a variable with a primitive data type a second time in a method. For example:
int num = 0;
num = 10;
System.out.println(num); // 10
int num = 20; // illegal to redeclare num with int typed again in front of num
The code should be written as
int num = 0;
num = 10;
System.out.println(num); // 10
num = 20;
where the assignment statement
num = 20;
is used rather than the declaration statement
int num = 20;
Objective #3: Explain problems such as loss of precision, overflow, and integer division that can occur when using int and double data types and how to work around some of the problems using casting.
- A compile error is generated if you initialize or assign
a value to an int variable that would overflow the limitation
of the int data type. The maximum
value that can be stored in an int variable
is 2147483647 (i.e. roughly 2 billion) which equals 2 to the 31st power minus
1. The minimum value that can be stored in an int variable
is -2147483648 which equals -2 to the 31st power. These limits are due to
the fact that an int variable occupies 4
bytes of memory. The constants Integer.MAX_VALUE and Integer.MIN_VALUE from
the Integer class can be used to refer to
these limits. Because zero can be stored in an int variable
and the two's complement method that is used to store binary values, the
last digit in the positive upper limit (i.e. 7) is not the same as the last
digit (i.e. 8) in the negative lower limit. MAX_VALUE and MIN_VALUE are
legal to use because they are already declared as public constants in the Integer class
as in
public static final int MAX_VALUE = 2147483647;
The Integer class does not need to be imported
at the top of a Java program because it is found in the java.lang package
which is automatically imported to all Java projects. We will eventually
study why the word static is used in this
declaration statement.
Note that if you add two integers whose sum is greater than 2147483647 and
store that resulting value into an int variable, an error will not occur.
The error occurs only if you directly initialize or assign such a value to
the variable. In the following code segment
int num = 2147483647 + 1;
System.out.println(num);
the value
-2147483648 displays since Java "wraps around" the number line.
- When using the double data type to store floating-point values, you can store numbers up to roughly 10 to the 300th power. This high value makes overflow less of a problem with double variables. Since a double variable is stored in 8 bytes of memory, there is a limit though to the overall number of digits, both before or after the decimal point, that can be stored without a loss of precision. About 15 significant digits can be stored at most in a double variable. The statements
grade = 0.123456789012345678901234567890;
System.out.println(grade);
will not cause a compile error. But the actual value that is displayed will be 0.12345678901234568. Note in the example above a 7 digit was changed to an 8 at the end of the number. In the example below,
grade = 96.55555555555555;
System.out.println(grade);
the value that will be displayed is 96.55555555555554 where the last 5 is changed to a 4. Because of the translation of decimal values to binary values, the number in the last decimal place may increase, decrease, or stay the same.
Be wary, this loop does not display the values that you think it displays since 0.1, 0.05, and 0.01 don't have exact binary representations:
for (double y = 1; y <= 2; y += 0.1)
System.out.println(y);
Try it out for yourself.
Here is another example that illustrates the loss of precision
double a = 1.1;
double b = 1.2;
System.out.println(a + b); // 2.3
System.out.println(a - b); //-0.09999999999999987
System.out.println((a + b)*(a - b)); //-0.22999999999999968
System.out.println(a * a);//1.2100000000000002
System.out.println(b * b);//1.44
System.out.println((a * a)- (b * b));//-0.22999999999999976
if ((a + b) * (a - b) != (a * a) - (b * b))
{
System.out.println("Math error"); // this displays even though the expressions should equal each other
}
- In some ways, the int type is easier for the computer to work with than the double type. An int is only 4 bytes as opposed to 8 so it uses less memory per variable. Also, it can be argued that mathematical computations with int's work faster on the computer's processor than double's. Also, it is occasionally safer to use an int since loss of precision and rounding errors affect double's in ways that int's are not affected. However, even with the int type a roundoff error (and not a lack of precision) can cause errors. As our author demonstrates on p. 104, the code segment
double f = 4.35;
int n = (int) (100 * f);
System.out.println(n);
causes the value 434 to be printed out and not 435
as you might expect. It is safer in this situation to use the round static
method from the Math class
as in
int n = (int) Math.round(100 * f);
Notice that the round method
is a static method and not an instance method. It is called by typing
the name of
its class in front of it and the dot
operator. It
is not
necessary
to
declare
a
Math object
and call the round method
on that object. The use of (int) is called
casting and is explained below.
- Decimal numbers are referred to as floating-point
values by computer scientists. An int variable
cannot store a floating-point value in Java. Unlike Visual Basic which
rounds a floating-point value to the nearest integer value, a "possible
loss of precision" compile error is generated if you try to initialize
or assign a value to an int variable
as in
int num = 1.2;
Be careful not to even assign a floating-point value to an int variable;
the compiler will generate an error. The following statement is not allowed in
Java even though there aren't any nonzero digits stored as decimal places in myDouble:
double myDouble = 1;
int myInt = 3 + myDouble;
However, you use casting (aka typecasting)
to purposefully but temporarily turn a double variable
into an int variable.
In the following example, no compile error occurs since myDouble is
casted to an int before
it is assigned to the int variable myInt.
double myDouble = 1.99;
int myInt = 3 + (int) myDouble;
System.out.println(myInt); //
the value 4 prints, not 4.99 or 5
In this code segment, int is
called a cast operator. In Java, casting a double to
an int does not
cause the floating-point value to be rounded. In the code segment, the 1.99 is
truncated to 1 before it is added to the value 3. But the
variable myDouble is
treated as a double variable
later
in the program and still stores the value
1.99.
You cannot cast an int or
a double into
a String or vice
versa. Casting only
applies to primitive data types.
- Be wary of integer division which is what we call the result of dividing one integer by another integer. This result is truncated to an integer even if the result would technically be a decimal number. The code segment
int num = 9;
double result = num / 2;
System.out.println(result);
causes the value 4 to be displayed even though 9 divided
by 2 is 4.5 to a mathematician and even though the variable result is a double. To avoid integer division, you can cast either one of the two division operands to a double. The other divisor is then automatically promoted to a double value as well. Therefore in the code segment
int num = 9;
double result = (double) num / 2;
System.out.println(result);
the programmer is casting the int variable
to a double to
avoid the problem of integer division. The value 2 is promoted by the Java
compiler to the double value
2.0 so that two double's
are being divided on the computer's processor.
Another way to avoid integer division in the example above is to type a decimal point along with the number 2 as in
int num = 9;
double result = num / 2.;
System.out.println(result);
causes the value 4.5 to be displayed since 2. is considered by the computer to be a double while 2 without a decimal point is considered to be an int.
- But integer division and the % operator can be used to pull apart the digits in a large number. Notice how the digits of 123 are extracted here
int num = 123;
int onesDigit = num % 10;
int tensDigit = (num % 100) / 10;
int hundredsDigit = (num % 1000) / 100;
- There is a curious side effect from using the addition compound operator +=.
int total = 0;
total = total + 5.4; // causes loss of precision compiler error
total += 5.4; // compiles and executes with x = 5 afterwards
The latter statement total += 5.4; is the same as total = (int) (total + 5.4);
Objective #4: Use the Integer and Double wrapper classes.
- The makers of Java created a class that allows you to work with integers in a more efficient manner than using int primitive variables. The Integer class is called a wrapper class because an Integer object wraps itself around a primitive int variable but gives a client programmer additional flexibility. Technically, Integer and Double are not primitive data types but are classes.
- The Integer class allows you to work with Integer wrapper objects that can store whole numbers. The statement
Integer num = new Integer(5);
declares and instantiates an Integer object that contains the whole number 5. The other constructor for the Integer class is passed the parameter value 5 which is stored in the private property for the num Integer object variable.
However, a recent Java upgrade now allows the statement
Integer num = 5;
to instantiate an Integer object as well. This is called autoboxing. Autoboxing is a feature of Java that allows a programmer to be lazy in this case and avoid typing the keyword new and the full constructor call statement. Java automatically invokes the constructor and stores the value 5 in the property of the num object variable.
- You can convert a string value into a primitive int using the parseInt method from the Integer class. This is similar to the Val and CInt functions in Visual Basic. The statement
int num = Integer.parseInt("5");
converts the string value "5.43" into a primitive double. An exception error is created if the string value is not in the correct format to be a valid number. We will later see that this method is particularly useful when getting user input from the keyboard.
- The Double class allows you to work with Double wrapper objects that can store floating-point values such as 5.43. The statement
Double num = new Double(5.43);
declares and instantiates a Double object that contains the whole number 5. With autoboxing, the statement
Double num = 5.43;
does the same thing.
- You can convert a string value into a primitive double using the parseDouble method from the Double class. The statement
double num = Double.parseDouble("5.43");
converts the string value "5.43" into a primitive double. An exception error is created if the string value is not in the correct format to be a valid number. We will later see that this method is particularly useful when getting user input from the keyboard.
- The Integer and Double classes are immutable because there are no modifier methods in these classes. An immutable class is one which does not contain any modifier methods and therefore doesn't allow a client programmer to change any properties of an object variable.
- The feature called auto-unboxing allows you to add an Integer object to a primitive int as in the following example
Integer num = 5;
int sum = 1 + num;
System.out.println(sum);
The value 6 will be displayed. The object variable num is auto-unboxed from an Integer wrapper object into a primitive int that is then added to the value 1 and correctly stored in the int variable sum. If it weren't for the auto-unboxing feature of Java, this would cause an error since an object variable could not be mathematically added to a primitive int value without using the Integer class' intValue method. We are not studying the intValue method in this course since auto-unboxing works in Java.