Casting and Converting

Things To Do First

Things To Do Later

Problems with Data Types

When working with various kinds of data, you can often encounter problems. The best way to understand the need for casting and converting of data is to try the following program:

public class TestData1 {

    public static void main(String[] args) {

        int val1 = 5;
        int val2 = 2;
        int result = val1 / val2;
        System.out.print("Result of " + val1 + " divided by " 
            + val2 + ":  ");
        System.out.println(result);
    }
}

What happens when you run this example; what output do you get?

Recall from the lesson on Arithmethic & Arithmetic Expressions that when you divide two integers, you get an integer result. In the first example, dividing 5 by 2 gives you 2 because 5 and 2 are integers. Since the result must be an integer, the .5 gets cut off.

We can solve this problem by turning one or both of the int values into a double. We do this with "casting".

Implicit Casting

To see how casting works, open your editor and copy the following program:

public class CastingEx {

    public static void main(String[] args) {

        int num1 = 5;
        double num2 = 8.2;
        char letter = 'A';
        int ascE = 69;

        int num3 = num2;		// statement 1
        double num4 = num1;		// statement 2
        int anA = letter;		// statement 3
        char anE = ascE;		// statement 4

        System.out.println("num3: " + num3);
        System.out.println("num4: " + num4);
        System.out.println("anA: " + anA);
        System.out.println("anE: " + anE);
    }
}

When you compile this program, you'll receive the following two errors for statements 1 and 4 (your actual line numbers given by the compiler might vary):

TestingCasts.java:10: possible loss of precision
found   : double
required: int
                int num3 = num2;
                           ^
TestingCasts.java:13: possible loss of precision
found   : int
required: char
                char anE = ascE;
                           ^
2 errors
                

Both of these errors occur for the same reason: a double value is 8 bytes in size, an int value is 4 bytes, and a char value is 2 bytes. It doesn't matter what the contents of the variables are -- a double is too big for an int and an int is too big for a char. Neither of these statements can be executed because they might cause a loss of precision (a loss of data). This has nothing to do with the values! A double is 8 bytes, and you can't take a value that's 8 bytes and stick it in a variable that is only capable of values that are 4 bytes. Similarly, a char is only 2 bytes, so you can't take an int value of 4 bytes and place it in a char variable. This is like trying to fit a basketball into your shoe!

Notice that statements 2 and 3 work fine! Why?? It seems okay to put an int value into a double and to put a char into an int. This is called implicit casting. To understand why statements 1 and 4 don't work, and why 2 and 3 do work, think of the data types we learned in Chapter 2.8. The integer types were byte (1 byte), short (2 bytes), int (4 bytes) and long (8 bytes). There was also char (2 bytes). The floating point types were float (4 bytes), and double (8 bytes). The rules for implicit casting to work are:

So how do you know what implicit casts are allowed? As long as the value on the right side of assignment operator is of a smaller range, then the assignment statement is valid.

Referring back to Table 2.1 in section 2.9 of your text book, the following might be helpful:

guide to implicit casting

Looking at the image above, imagine that each arrow is the same as the phrase "can go into" or "can be implicitly cast into". Anything to the left, if you follow the arrows, can go into what's on its path to the right.

For example, a char can go into an int, and since an int can go into a long or a float, then a char can also go into a long or a float. Similarly, an int can go into a long or a float, and a double can accept a long or a float, so therefore a double can accept an int, too.

You must follow the arrows on the path. For example, float is not pointing to int or long, so that means you can't assign a float to an int variable or a long variable.

Note that there are some special cases that might cause loss of data with large int and long values. Recall the following table that indicates how the bits of floats and doubles are allocated:

Data Type Description # bits for
Coefficient
# bits for
Exponent
# bits for
Sign
floatSingle-precision floating-point 2381
doubleDouble-Precision floating-point 52111

As you can see by the table, a float has 23 bits for the coefficient and 8 bits for the value of the exponent. If you were to assign a very large int into a float variable, you would lose some bits because a large int might use all 32 bits for its value, and you only have 23 of those available in a float.

As an example, take the int value 2,145,996,695. This is an int value that uses all 32 bits of the int (it's binary value is 0111 1111 1110 1001 0100 1111 1001 0111). We know that to store that as a float value, it gets converted to exponential notation: 2.145996695e9. However, if you try the following code:

int n = 2145996695;
float f = n;
System.out.println(f);

We get the output:

2.14599667E9

This is not the correct value for 2,145,996,695 in exponential notation! Why did it come out wrong?

If you look at the chart, 23 bits of a float are for the coefficient, and 8 bytes are for the exponent value. Our int value used up all 32 bits so we lost some of the lower bits when the value was converted to a float.

If you try the code with this value instead:

int n = 5842658;
float f = n;
System.out.println(f);

You'll get the output:

5842658.0

As you can see that's an accurate conversion of the value 5,842,658 into exponential notation. Here the value did not use all 32 bits of the int variable (0000 0000 0101 1001 0010 0110 1110 0010) so none were lost in the conversion from int to float.

This kind of exceptional circumstance occurs when you assign int to float, and when you assign a long to a float or to a double. Therefore, be careful when converting large ints and longs into floating point variables.

Exercise

Given the variable declarations below, which of the following assignment statements are invalid?

int num1 = 5;
double num2 = 5.5;
float num3 = 2.2f;
long num4 = 1234567;
  1. num1 = num2; [Solution]
  2. num2 = num3; [Solution]
  3. num3 = num1; [Solution]
  4. num3 = num2; [Solution]
  5. num4 = num3; [Solution]
  6. num3 = num4; [Solution]
  7. num1 = num3; [Solution]

So now we know when we can cast implicitly and when we can't. But what do we do if we need to place an int value into a char or a double value into an int? This is where explicit casting comes in.

Explicit Casting

Explicit casting is when you force a piece of data into some other data type. To explicitly cast, you use a cast operator. A cast operator is the desired data type in brackets. For example, if you want to cast something into an int value, you place the operator (int) directly in front of the value. We can use casting operators to make statements 1 and 4 work in our earlier example:

public class CastingEx {

    public static void main(String[] args) {

        int num1 = 5;
        double num2 = 8.2;
        char letter = 'A';
        int ascE = 69;

        int num3 = (int)num2;		// force the double to be an int
        double num4 = num1;		// statement 2
        int anA = letter;		// statement 3
        char anE = (char)ascE;		// force the int to be a char

        System.out.println("num3: " + num3);
        System.out.println("num4: " + num4);
        System.out.println("anA: " + anA);
        System.out.println("anE: " + anE);
    }
}

What happens if you try to cast two values when the value being assigned is too large for the type that is the recipient? For example, add this code to your TestCasts program:

double large = 1000000000000;
int fits = (int)large;
System.out.println(fits);

In this case, the double value is larger than the maximum value for an integer, and you'll get an error when you compile this program:

Error: integer number too large: 1000000000000

Be careful when casting from a larger type to a smaller type! Only cast when you're sure that the casted value will fit!

The chart below summarizes when you can do an Implicit Cast and when you must do an Explicit Cast. "I" means Implicit Cats, "E" means Explicit Cast. "I*" means you can do an implicit cast, but loss of precision will occur for very large numbers. "N" means casting for these types are NOT allowed at all.

 Into this type of variable
Assign
this type
intlongfloat doublecharbyteshortboolean
int-II*IE EEN
longE-I*I*E EEN
floatEE-IE EEN
doubleEEE-E EEN
charIIII- EEN
byteIIIIE -EN
shortIIIIE E-N
booleanNNNNN NN-

Exercises

1. How would you use casting to solve the problem in the TestData example in the first section?

2. Using the declaration/initialization statements below, determine the result of each of the following explicit casts.

double dNum1 = 5.5;
double dNum2 = 10.2;
double dNum3 = 1.1;
  1. (int)dNum1
  2. (int)dNum2
  3. (int)dNum3
  4. (int)(dNum1 + dNum3)
  5. (int)dNum1 + dNum3
  6. (double)((int)dNum1) + dNum3
  7. (double)((int)(dNum1 + dNum3))

[solutions]

Parse Methods

Recall from the session on Getting User Input that we learned about using the parse methods as an alternative to clearing the input buffer when using Scanner.

Each primitive type has a corresponding Wrapper Class. For example, the wrapper class for double is Double and the wrapper class for int is Integer. Inside each numeric wrapper class is a parse method that allows you to convert from a String to a primitive numeric type. For example:

String strIntNum = "2";
String strDblNum = "2.5";
int intNum = Integer.parseInt(strIntNum); // stores 2 in intNum
double dblNum = Double.parseDouble(strDblNum); // stores 2.5 in dblNum

You will use the parse methods whenever you have a string value and you want to convert it into an int or a double.

Exercise

Copy the following program. Compile it, and run it. Test the program with each of the input values below, and for each test, describe what happens and why.

  1. 5
  2. 5.0
  3. five
public class Conversions {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        System.out.print("Enter a value: ");
        String strValue = in.next();
        int intNum = Integer.parseInt(strValue);
        double dblNum = Double.parseDouble(strValue);
        System.out.println(intNum + ", " + dblNum);
    }
}

[solutions]

Case Study

Chapter 2.17 is a case study about a program that converts an amount of money into individual monetary units. Read about the case study, run the animation and try the live demo, then read the explanation of the program code.