# Numbers

Most of the computer programs we’ll write must deal with numbers in some way. So, it makes perfect sense to start working with the numerical data types, since we’ll use them very often. Let’s dive in and see how we can use these numerical data types in Java!

Java has built in primitive types for various numeric, text and logic values. A variable in Java can refer to either a primitive type or a full fledged object.

## Integers

The first data types we’ll learn about in Java are the ones for storing whole numbers. There are actually 4 different types that can perform this task, each with different characteristics.

Name Type Size Minimum Maximum
Byte byte 8 bits $-128$ $127$
Short short 16 bits $-32\,768$ $32\,767$
Integer int 32 bits $-2\,147\,483\,648$ $2\,147\,483\,647$
Long long 64 bits $-2^{63}$ $2^{63} - 1$

As we can see, each data type in this list has a different size, and can store numbers within a different range. So, if we know the minimum and maximum values that could possibly be stored in a particular variable, we can use the smallest corresponding data type that can store that value. This would allow us to conserve the amount of memory used in our programs.

However, in practice, most modern computers have more than enough memory available to handle our programs, so this is typically not a concern for most developers. Instead, it is best to use the largest possible data type, to avoid errors in the future as the program is updated and data values may become larger than initially anticipated.

In this program, and most of the code in this book, we’ll typically use the integer, or int data type for all whole numbers. Even though it isn’t the largest data type for storing whole numbers, it is generally large enough. In addition, the int data type is supported universally across many different programming languages, so learning how to use it will make it easier to switch between languages later on.

## Floating Points

The next data types we’ll learn about in Java are the ones for storing rational and irrational numbers. There are actually 2 different types that can perform this task, each with different characteristics.

Name Type Size Range
Float float 32 bits $\pm 10^{\pm 38}$
Double double 64 bits $\pm 10^{\pm 308}$

Unlike the data types for whole numbers, it is more difficult to discuss the minimum and maximum values for these data types, as it requires a thorough understanding of how they are stored in binary and interpreted by the processor in a computer. In general, each one can handle large numbers as well as small numbers extremely well.

However, just like scientific notation, the numbers it stores at best can only be as accurate as the number of digits it holds. So, when storing an extremely large number, there will be some rounding error.

In this program, and most of the code in this book, we’ll typically use the Double, or double data type for all decimal numbers.

## Using Numbers in Code

Now that we’ve discussed the various data types available in Java, let’s look at how we can actually create variables that can store data in our programs.

### Declaring

In Java, we can declare a variable using this syntax:

<type> <identifier>;

So, to declare a variable of type int named x, we would write:

int x;

We can also do the same for each of the types listed above:

byte b;
short s;
int i;
long l;

float f;
double d;

As with any other part of our program, we must first declare it before we can use it.

### Assigning

Once a variable has been declared, we can give it a value using an assignment statement. Assignment uses this syntax:

<destination> = <expression>

In that example above, <destination> is the identifier of the variable we’d like to store data in, and <expression> is any valid Java expression that produces a value. It could be a number, another variable, a mathematical operation, or even a method call, which we’ll learn about in a later chapter. The variable we are storing the value in must always be on the left side of the equals = sign.

For example, if we want to store the value $5$ in an int variable named x, we could write the following:

int x;
x = 5;

We can even combine the declaration and assignment statements into a single statement, like this:

int x = 5;

The same syntax applies to all of these types in Java:

byte b = 1;
short s = 2;
int i = 3;
long l = 4;

float f = 1.2f;
double d = 3.4;

When assigning values from one variable to another using primitive data types, the value is copied in memory. So, changing the value of the first variable would not affect the others, as in this example:

int x = 5;
int y = x;
x = 6;

At the end of that code, the value of x is $6$, but y still contains $5$. This is important to remember.

### Printing

We can also use the System.out.println and System.out.print methods we learned earlier to output the current value of a variable to the screen. Here’s an example:

int x = 5;
System.out.println(x);

Notice that the variable x is not in quotation marks. This way, we’ll be able to print the value stored in the variable x to the screen. If we place it in quotation marks, we’ll just print the letter x instead.

Later, in the project for this chapter, we’ll learn how to combine multiple variables into a single output.

### Casting

When writing our programs, sometimes we need to change the data type that a particular value is stored as, especially when we want to store it in a new variable. Ideally, we would construct our programs to avoid this issue, but in the real world we aren’t always so lucky.

To change the data type of a value, we can cast that value to a different data type. To cast a value to a different data type, we put the data type we’d like it to be in parentheses in front of the value.

Let’s look at the example below:

int x = 120;
byte y = x;
System.out.println(y);

In this example, we’ve created an int variable x, and stored $120$ in that variable. We then create a byte variable y, and try to store the value from x into y.

When we try to compile that example, we should get the following compiler error:

Since the int data type is larger than the byte data type, the compiler will give us an error stating that we might lose data when we perform that conversion. Of course, if we reverse the int and byte data types, and try to assign a byte to and int, it will work just fine.

In general, we should try to avoid this problem by redesigning our program to eliminate the need to store a variable in a smaller type, but sometimes it is necessary. To do this, we’ll need to cast the value to the correct data type. Let’s update the example above:

int x = 120;
byte y = (byte) x;
System.out.println(y);

In this example, we have added a (byte) in front of the variable x when we are assigning it to y. This tells the compiler that we would like to convert the data type of x to byte before storing it in y. Now, when we try to compile and run this program, it will act as we expect.

However, let’s look at one final example to see why the compiler would warn us about converting to a smaller data type:

int x = 128;
byte y = (byte) x;
System.out.println(y);

In this example, instead of storing $120$ in x, we have instead stored $128$. When we compile and run this program, we get this unexpected output:

We expect it to output $128$, but instead it outputs $-128$. That’s strange, isn’t it?

What’s happening is an error known as integer overflow. Since $128$ is too large to fit in a byte variable, the computer will truncate, or remove, the bits that are at the front of the number that won’t fit. This could cause data to be lost or misinterpreted, which is what happens here.

So, we must always be careful and not try to cast a variable to a smaller data type if it is too large to fit in that data type. This is why the compiler will always warn us when we try to do so, unless we add an explicit cast to our code.