Data Types

There are more data types than just the int data type. The int data type is just one of eight primitive data types that Java supports. The following table shows all the primitive data types (plus an additional data type, String, which isn’t primitive but is very commonly used):

Data TypeValueValue RangeExamples (Literals)
byteIntegerMin: -128
Max: 127
4, 0, 122, -83
shortIntegerMin: -32768
Max: 32767
1, 8005, -21958, -59
intIntegerMin: -2147483648
Max: 2147483647
5, 93, -19925, 4000000
longIntegerMin: -9223372036854775808
Max: 9223372036854775807
0L, 7L, 94392846147L, -299L
floatDecimal/Fractionaln/a-4.27f, 362.87f, 10.0f
doubleDecimal/Fractionaln/a9.99, 790.00, -541.1442
booleanTrue/Falsetrue/falsetrue, false
charCharacterMin: 0
Max: 65535
‘b’, ‘@’, ‘3’, ‘G’
StringTextn/a“Hello”, “82”, “Where am I?”, “:)”
A table of the eight primitive data type in Java, plus one reference data type (String)

Note
The term “data type” is often shortened to “type”, especially when working in OOP.

Integer Data Types

Look at the first four rows in the table above (byte, short, int, and long). We can see from the Value column that they all hold integers but the difference between them is the range of integers they can hold, as shown in the Value Range column. You can declare variables of these data types similar to how you declare int variables. For example:

byte a = 95;
short b = 2243;
int c = 392;
long d = 72915;

Line 1 is a byte variable called a with a value of 95. Line 2 is a short variable called b with a value of 2243. Line 3 is an int variable called c with a value of 392. Line 4 is a long variable called d with a value of 72915. All four statements are valid since each value is in range with respect to the data type. If you do try to store an integer that is out of range, then you’ll get an error. For instance, in variable a, trying to store the value -441 won’t work because the minimum a byte variable can hold is -128. The value range is determined by the amount of memory each data type occupies. A byte occupies—you guessed it—1 byte. A short occupies 2 bytes, an int 4 bytes, and a long 8 bytes. Note that if you want to store a really big integer that requires a long variable, then you may have to append the letter L to the end e.g.

long d = 210498964295L;

Don’t worry, the L doesn’t affect the number itself, it just lets Java know that the number is a long type. Without the L, Java may still treat the number itself as an int type even though it’s clearly too big to be an int. This is simply because integers that are written in the code directly (called literals) are treated as ints by default. Appending an L turns it into a long literal.

So why use one data type over the other if they can all store integers? Again, if you are dealing with numbers too big for int variables then you may have to use long variables. Another reason is if you are writing a program for a device with limited memory, it might benefit you to use data types which take up less memory such as shorts or bytes. This is especially true for embedded systems. A third reason is if you are sending data over a network, it may help to send smaller data packets, such as for video calls and multiplayer games.

Lucky for us, we can practically ignore byte, short, and long. The int is by far the most commonly used data type and is the default type for integers in Java. So, we’ll almost exclusively use int in our programs and only concern ourselves with byte, short, and long if we have a reason to.

Floating-point Data Types

If you want decimal numbers, the float and double data types are the easiest solution. You may have tried to put a decimal number in an int variable yourself and found out it doesn’t work. For example:

int x = 4.7;

In IntelliJ IDEA, this line of code will by underlined in red since it’s invalid code. By hovering the cursor over it, a box pops up with an explanation:

It tells us that an int value is required, but a double value has been provided. To make x into a double variable instead, you just replace the int keyword with double:

double x = 4.7;

We can use doubles along with ints in the same expression, no problem, as shown in the following code:

double x = 8.5;
int y = 4;
System.out.print(x / y);
Output:
2.215

Notice that the output is a decimal number this time. When we use a double in a division, Java doesn’t not perform integer division and gives us the true result instead of truncating the number to an integer.

What happens if we try changing x from a double to a float?

float x = 8.5;
int y = 4;
System.out.print(x / y);

We get a similar error to before:

This is because x is a float variable but 8.5 is a double value. The problem is that decimal numbers written plainly in the code, like 8.5, are treated as a double by default. In order to turn 8.5 into a float, we need to put an f at the end:

float x = 8.5f;
int y = 4;
System.out.print(x / y);

The f does not affect the number itself; the number is still 8.5. It just tells Java to treat it as a float data type.

Note
The names float and double come from the fact that float is a single-precision floating point number and double is a double-precision floating point number.

You should know that floating-point types cannot represent all decimal numbers exactly. They are very precise, however. For example, 2.35 * 0.79 = 1.8565. Now let’s try the same thing in a program:

double x = 2.35 * 0.79;
System.out.print(x);
Output:
1.8565000000000003

The result is a number very slightly more than 1.8565 but for most purposes this isn’t a problem. These rounding errors don’t just apply to the computer’s binary-based system either. Even our base-10 system cannot represent certain numbers exactly. For instance, the fraction ⅓ is 0.33333… forever. The difference between float and double is that float is 32 bits (4 bytes) whereas double is 64 bits (8 bytes), therefore double will give you more precision. Floating-point types in general may not be suitable if you require exactness, like if you’re working on the atomic scale or dealing with currency.

Just like we can use int over the other integer types, we can stick to using double over float for most fraction-based tasks.

Boolean Data Type

The boolean data type can be one of two values: true or false. For example:

boolean x = true;
System.out.print(x);
Output:
true

Booleans are very useful for decision making as you will see in the chapter on Conditionals.

Character Data Type

The char data type is a single character. A character between single-quotes is treated as a char. For example:

char x = '#';
System.out.print(x);
Output:
#

On line 1 the character ‘#’ is stored is variable x, which is of type char. Line 2 prints x, resulting in # being outputted. chars are based on Unicode so each character has a numeric equivalent. For example, the number 65 represents uppercase A. If 65 is stored in a char variable (excluding single-quotes) and then printed, A should be the result.

char x = 65;
System.out.print(x);
Output:
A

The number 65 is A, 66 is B, 67 is C, until 90, which is Z. A char can be any number from 0 to 65535. Within this range are all sorts of symbols and characters from different languages. For instance, 169 is the copyright symbol (©). Each character also has a hexadecimal equivalent, which goes between single quotes and starts with a \u backslash-u, followed by a hex number, like 005A, which is the letter Z.

char x = '\u005A';
System.out.print(x);
Output:
Z

String Data Type

The String data type is text between double-quotes. We used them a lot in the previous chapter. Strings are useful when you need to store words, sentences, or just a sequence of characters. For example:

String x = "England is snowy.";
System.out.print(x);
Output:
England is snowy.

String is the type, x is the name, and “England is snowy.” is the value. Notice that the String data type starts with an uppercase letter, unlike the other data types we’ve covered. Also, sometimes I’ll write the word “string” (plain) and sometimes I’ll write String (highlighted). The difference is that “string” refers to strings in the general sense whereas String refers to the data type.

Sometimes you’ll have two or more strings that you need to join together. We can join two strings together using the concatenation operator, which is just the plus sign (+). For example, if we have one string that reads “Abso” and another that reads “lutely” then we can concatenate them like so:

String s = "Abso" + "lutely";
System.out.print(s);
Output:
Absolutely

The two strings are joined together and the resultant string is stored in the variable s. This variable is then printed.

The Printing Methods are Overloaded

When we use printing methods like print and println, we pass them data to output to the screen. Up to this point we have passed data of various types to these methods, such as int, double, char, boolean, and String, and this data was printed without a problem. However, the ability to accept different data types isn’t automatic; multiple versions of the print method had to be written to accept and process different data types. That’s why there are so many print options to choose from when you type System.out., as shown below.

Each version of print/println accepts a different type of data, which can be seen between the parentheses. These are basically variables that the data you pass gets stored in. For example, the third print method in the list reads print(int i). int i is nothing more than a variable called i (of type int). When you call System.out.print(5), Java automatically calls this specific version of the method and the value 5 gets stored in variable i. The print method then processes i (5) for printing. When you call System.out.print(5.5), Java will call the print(double d) method whereby 5.5 gets stored in d. d is then processed and printed. Writing multiple versions of a method that accept different data types is called method overloading (covered in chapter 10).

A piece of data that is passed to a method is called an argument. For example, in the line

System.out.print(5);

a single argument (5) is passed to System.out.print.

In the line

System.out.print(“Bowl of cereal.”);

the String “Bowl of cereal.” is being passed as an argument.

However, you cannot call the print method and not pass any arguments:

System.out.print(); // This is an error

This is because there is no overloaded version that accepts no data. However, a version of the println method does exist that accepts no data; therefore, the following line is valid:

System.out.println(); // This works

Variable Naming and Rules

The naming of variables is important in the pursuit of clarity. So far, I’ve given variables 1-letter names like x and y, which is fine for certain purposes, but variables can have longer names too. The name you give to a variable should reflect its purpose and/or the data it contains. For instance, if we were to walk around a mall and ask people for their name and age, we wouldn’t label this data x and y:

x: Fred
y: 59

x: Ashley
y: 24

x: Mike
y: 27

Instead, we would label this data name and age, as these are the most descriptive labels for the data we’re collecting:

Name: Fred
Age: 59

Name: Ashley
Age: 24

Name: Mike
Age: 27

In a program it may look something like this:

public static void main(String[] args) {
   String name1 = "Fred";
   int age1 = 59;

   String name2 = "Ashley";
   int age2 = 24;

   String name3 = "Mike";
   int age3 = 27;
}

Since names are textual data it makes the most sense to use String, and since ages are generally whole numbers it makes most sense to use an int. You’ll often find that there is a most appropriate data type for every piece of data.

Variable names that are composed of multiple words are traditionally written in camel case. This is a style of writing where every word is capitalized apart from the very first word, and there are no spaces between words (although variable names can’t have spaces anyway). Sometimes, thinking of names for variables can be tricky as there’s often a trade-off between brevity and clarity, and there’s also context to consider as well. Let’s look at a few examples of variables you might find in real-world programs.

Use int variables for integers:

int yearsAsMember = 7; // The number of years a person has been a member of a club.

int connectionCount = 45; // The number of users connected to a server.

Use double variables for decimals:

double statueHeightInMetres = 15.97; // The height of a statue in a park.

double humidity = 90.2; // The humidity in London.

Use boolean variables for true or false data. boolean variables often start with “is” or “has” as this allows you to read it as a statement, but this is not always the case:

boolean hasDriversLicense = true; /* Government data about whether a citizen
possesses a driver’s license. Read as: (Person) has (a) driver’s license: true. */

boolean isOffline = false; /* Whether or not a website is offline.
Read as: (Website) is offline: false. */

Use char variables for when you require exactly one character:

char keyPressed = ‘R’; // The key just pressed by the user.

char confirmationCharacter = ‘y’; // The character that represents a confirmation.

Use String when you have textual data:

String taxNumber = “123ABC4D”; // The tax number for a business.

String bookTitle = “The Alien Who Lost His Way.” // The title of a book.

Note that some characters are not allowed in variable names. Variable names can consist of four things: letters, numbers, underscores, and dollar signs. So, something like a1$zq_44_K is a valid variable name. What it means is anyone’s guess, but it’s still a perfectly valid name. Even something like ___ is a valid name (yes, that is three underscores in a row) e.g.

public static void main(String[] args) {
   int ___ = 150;
   System.out.print(___);
}
Output:
150

Typically, you should never use dollar signs. Underscores are rarely used either, barring some styling preferences. Underscores are more common in languages like C where variables are written in snake case e.g. int total_blue_cars = 19; instead of int totalBlueCars = 19;. Variables can also have numbers in the name but cannot start with a number as this is invalid.

Really, all you need to remember is that variables are best written with letters. Numbers are fine, too, just don’t start with one.

Type Casting

Type casting is converting one data type to another. Java converts certain types automatically but there are situations where Java does not perform a type conversion due to a possible loss of data, such as in this line:

int x = 5.7;

This will produce an error because it’s trying to store a double in an int variable. If Java converted 5.7 into an int, it would cut off the .7 to give us 5, hence we lose some data in the conversion. If we change the value to 5.0 it will still produce an error even though 5.0 and 5 are technically the same number. This is because they are still fundamentally two different types of data and Java doesn’t want to take the risk that we’ll lose something in the conversion. If we run the program the error that appears in the Run window confirms this: “Error:(3, 17) java: incompatible types: possible lossy conversion from double to int”. In situations where we are unlikely to lose any data, Java will perform a conversion automatically:

double x = 5;

The 5 is an int but Java will convert it to a double before assigning it to x. This is called an implicit conversion or implicit type cast.

Conversely, an explicit type cast is a conversion you perform manually. In order to convert a value, before the value you put a pair of parentheses containing the data type you wish to convert it to. For example, to cast 5.7 to an int, you would do:

int x = (int)5.7;

This will convert 5.7 to an int so it can be stored in x. Of course, this means you will lose the .7 and x will be 5.

Here is another example:

float x = 29.15f;
double y = x; // Fine, no loss of data

In this example we have a float variable x set to 29.15 as well as a double variable y set to x. Therefore, both x and y would contain 29.15f. This works fine since floats can be represented as doubles without issue. However, swap the data types around and we get an error since floats do not have the same precision nor storage capacity as doubles:

double x = 29.15;
float y = x; // Error, possible loss of data

We need to type cast x to a float before we can copy it into y:

double x = 29.15;
float y = (float)x; // Cast x to a float

Note that type casting doesn’t affect the original value (the value being converted). Instead, it makes a copy of the value that is of the new data type. This means that x still contains 29.15 as a double and y will contains 29.15 as a float, even after the conversion.

Leave a Reply

Your email address will not be published. Required fields are marked *