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 Type | Value | Value Range | Examples (Literals) |
---|---|---|---|
byte | Integer | Min: -128 Max: 127 | 4, 0, 122, -83 |
short | Integer | Min: -32768 Max: 32767 | 1, 8005, -21958, -59 |
int | Integer | Min: -2147483648 Max: 2147483647 | 5, 93, -19925, 4000000 |
long | Integer | Min: -9223372036854775808 Max: 9223372036854775807 | 0L, 7L, 94392846147L, -299L |
float | Decimal/Fractional | n/a | -4.27f, 362.87f, 10.0f |
double | Decimal/Fractional | n/a | 9.99, 790.00, -541.1442 |
boolean | True/False | true/false | true, false |
char | Character | Min: 0 Max: 65535 | ‘b’, ‘@’, ‘3’, ‘G’ |
String | Text | n/a | “Hello”, “82”, “Where am I?”, “:)” |
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 int
s 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 short
s or byte
s. 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 double
s along with int
s 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
Boolean
s 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. char
s 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. String
s 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 float
s can be represented as double
s without issue. However, swap the data types around and we get an error since float
s do not have the same precision nor storage capacity as double
s:
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.