The Java Programming Language features eight primitive data types.
In this tutorial, we’ll look at what these primitives are and go over each type.
2. Primitive Data Types
The eight primitives defined in Java are int, byte, short, long, float, double, boolean and char. These aren’t considered objects and represent raw values.
They’re stored directly on the stack (check out this article for more information about memory management in Java).
We’ll take a look at storage size, default values and examples of how to use each type.
Let’s start with a quick reference:
||byte b = 100;
||short s = 30_000;
||int i = 100_000_000;
||long l = 100_000_000_000_000;
||float f = 1.456f;
||double f = 1.456789012345678;
||char c = ‘c’;
||boolean b = true;
The first primitive data type we’re going to cover is int. Also known as an integer, int type holds a wide range of non-fractional number values.
Specifically, Java stores it using 32 bits of memory. In other words, it can represent values from -2,147,483,648 (-231) to 2,147,483,647 (231-1).
In Java 8, it’s possible to store an unsigned integer value up to 4,294,967,295 (232-1) by using new special helper functions.
We can simply declare an int:
int x = 424_242;
The default value of an int declared without an assignment is 0.
If the variable is defined in a method, we must assign a value before we can use it.
We can perform all standard arithmetic operations on ints. Just be aware that decimal values will be chopped off when performing these on integers.
byte is a primitive data type similar to int, except it only takes up 8 bits of memory. This is why we call it a byte. Because the memory size is so small, byte can only hold the values from -128 (-27) to 127 (27 – 1).
Here’s how we can create byte:
byte b = 100;
The default value of byte is also 0.
The next stop on our list of primitive data types in Java is short.
If we want to save memory and byte is too small, we can use the type halfway between byte and int: short.
At 16 bits of memory, it’s half the size of int and twice the size of byte. Its range of possible values is -32,768(-215) to 32,767(215 – 1).
short is declared like this:
short s = 20_020;
Also similar to the other types, the default value is 0. We can use all standard arithmetic on it as well.
Our last primitive data type related to integers is long.
long is the big brother of int. It’s stored in 64 bits of memory, so it can hold a significantly larger set of possible values.
The possible values of a long are between -9,223,372,036,854,775,808 (-263) to 9,223,372,036,854,775,807 (263 – 1).
We can simply declare one:
long l = 1_234_567_890;
As with other integer types, the default is also 0. We can use all arithmetic on long that works on int.
We represent basic fractional numbers in Java using the float type. This is a single-precision decimal number. This means that if we get past six decimal points, the number becomes less precise and more of an estimate.
In most cases, we don’t care about the precision loss. But if our calculation requires absolute precision (e.g., financial operations, landing on the moon, etc.), we need to use specific types designed for this work. For more information, check out the Java class Big Decimal.
This type is stored in 32 bits of memory just like int. However, because of the floating decimal point, its range is much different. It can represent both positive and negative numbers. The smallest decimal is 1.40239846 x 10-45, and the largest value is 3.40282347 x 1038.
We declare floats the same as any other type:
float f = 3.145f;
And the default value is 0.0 instead of 0. Also, notice we add the f designation to the end of the literal number to define a float. Otherwise, Java will throw an error because the default type of a decimal value is double.
We can also perform all standard arithmetic operations on floats. However, it’s important to note that we perform floating point arithmetic very differently than integer arithmetic.
Next, we look at double. Its name comes from the fact that it’s a double-precision decimal number.
It’s stored in 64 bits of memory. This means it represents a much larger range of possible numbers than float.
Although, it does suffer from the same precision limitation as float does. The range is 4.9406564584124654 x 10-324 to 1.7976931348623157 x 10308. That range can also be positive or negative.
Declaring double is the same as other numeric types:
double d = 3.13457599923384753929348D;
The default value is also 0.0 as it is with float. Similar to float, we attach the letter D to designate the literal as a double.
The simplest primitive data type is boolean. It can contain only two values: true or false. It stores its value in a single bit.
However, for convenience, Java pads the value and stores it in a single byte.
Here’s how we declare boolean:
boolean b = true;
Declaring it without a value defaults to false. boolean is the cornerstone of controlling our programs flow. We can use boolean operators on them (e.g., and, or, etc.).
The final primitive data type to look at is char.
Also called a character, char is a 16-bit integer representing a Unicode-encoded character. Its range is from 0 to 65,535. In Unicode, this represents ‘\u0000’ to ‘\uffff’.
For a list of all possible Unicode values, check out sites such as Unicode Table.
Let’s now declare a char:
char c = 'a';
char c = 65;
When defining our variables, we can use any character literal, and they will get automatically transformed into their Unicode encoding for us. A character’s default value is ‘/u0000’.
The primitive data types have size limits. But what happens if we try to store a value that’s larger than the maximum value?
We run into a situation called overflow.
When an integer overflows, it rolls over to the minimum value and begins counting up from there.
Floating point numbers overflow by returning Infinity:
int i = Integer.MAX_VALUE;
int j = i + 1;
// j will roll over to -2_147_483_648
double d = Double.MAX_VALUE;
double o = d + 1;
// o will be Infinity
Underflow is the same issue except it involves storing a value smaller than the minimum value. When the numbers underflow, they return 0.0.
Each primitive data type also has a full Java class implementation that can wrap it. For instance, the Integer class can wrap an int. There is sometimes a need to convert from the primitive type to its object wrapper (e.g., using them with generics).
Luckily, Java can perform this conversion for us automatically, a process called Autoboxing:
Character c = 'c';
Integer i = 1;
In this article, we’ve covered the eight primitive data types supported in Java.
These are the building blocks used by most, if not all, Java programs out there, so it’s well worth understanding how they work.