In the world of coding, how you represent data (name, age, height) is key to how that piece of data can be used and manipulated.
Pieces of data can be represented in code using data types. A data type is an aspect of data that tells the compiler how the programmer intends to use that data and to which type it belongs.
This guide will step you through data types in the Java programming language. At the end of the guide, you would’ve gained a good understanding of Java data types and which to select for your data while coding.
Table of contents
Java Data Types
Java is a strongly typed programming language. When declaring the types of variables in Java, the programmer must declare them of a specific data type. Once declared, that variable cannot hold data of other types. Although in Java 10 var was presented as a type, Java is still a strong, static-typed language.
In Java, data types are either:
- Primitive data types,
- Non-primitive or reference data types or
- Var type - local variable type inference
Primitive Data Types
The primitive data types in Java are predefined in the Java programming language that serves as basic building blocks. There are 8 primitive data types, and they are:
Boolean
You use the boolean Java data type when the data has only two possible values: true and false. Boolean is mainly associated with conditional statements, which control the program flow depending on whether the variable of boolean data type evaluates true or false.
Syntax:
boolean boolVariable;
Size:
1 bit
Range:
true or false
Default value:
false
Demo:
class BooleanDemo {
public static void main(String[] args) {
boolean booleanVar = true; // boolean variable is hard coded to true
if (booleanVar == true){ // condition is always met
System.out.println("Hello world!");
}
}
}
The code above outputs:
Hello world!
Byte
The byte data type is an 8 bit two's complement integer—variables of type byte store numeric values between -128 to 127 (inclusive). The range defines the minimum (-128) and maximum (127) value a byte can store.
A byte data type is 4 times smaller than an int, which makes it useful for saving memory in large arrays where saving memory is important.
Syntax:
byte byteVar;
Size:
8 bits (1 byte)
Default value:
0
Range:
-128 to 127
Example:
class ByteDemo {
public static void main(String[] args) {
byte byteVar = 126;
// byteVar is of 8 bit
System.out.println(byteVar);
// Increment of byteVar value
byteVar++;
System.out.println(byteVar);
// It overflows here because
// byte hold values of range -128 to 127
byteVar++;
System.out.println(byteVar);
// Looping back within the range
byteVar++;
System.out.println(byteVar);
}
}
The code above outputs the following:
126
127
-128
-127
Short
The short data type is a 16 bit signed two's complement integer. The range of short data types in Java to use in order to store numbers is between -32,768 to 32,767 (inclusive). The range defines the minimum and maximum value a short can store.
Just as you use the byte type to save memory, you can use short to do the same as it's 2 times smaller than an int data type.
Syntax:
short shortVar;
Size:
16 bits (2 bytes)
Default value:
0
Range:
-32,768 to 32,767
Demo:
class ShortDemo {
public static void main(String[] args) {
short shortVar = 134;
System.out.println(shortVar);
}
}
The code above outputs the integral value:
134
Int
The int data type is a 32 bit signed two's complement integer. This numeric data type is used to store numbers that lie between the range of -2,147,483,648 (-231) to 2,147,483,647 (231-1) (inclusive). The range defines the minimum and maximum value of the int array in Java for storing.
Syntax:
int wholeNum;
Size:
32-bit (4 bytes)
Default value:
0
Range:
-2,147,483,648 to 2,147,483,647
Example:
class IntDemo {
public static void main(String[] args) {
int wholeNum = 132;
System.out.println(wholeNum);
}
}
The code above outputs the integral value:
132
In Java 8 and later, you can use the int data type to represent an unsigned 32 bit integer, which has value in the range [0, 232-1].
Long
The long data type in Java is a 64 bit two's complement integer used to store numbers that lie between the range of -9,223,372,036,854,775,808(-263) to 9,223,372,036,854,775,807(263-1)(inclusive). The range defines the minimum and maximum value a long data type can store.
You can use this data type when you need a range of values wider than those provided by int.
Syntax:
long num;
Size:
64-bit (8 bytes)
Default value:
0
Range:
-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
Demo:
class LongDemo {
public static void main(String[] args) {
long num = 42903420404L;
System.out.println(num);
}
}
In the code example above, the L suffix of the num variable tells the compiler that it's a long literal. Without it, the code will return an error.
The code outputs the integral value:
42903420404
In Java 8 and later, you can represent an unsigned 64-bit long using the long data type, which has value in the range [0, 264-1].
Float
The float data type is a single-precision 32 bit size IEEE 754 ( arithmetic standard) floating-point. This numeric type’s range is unlimited. You should use the float in Java (instead of double) if you need to save memory in large arrays of floating-point numbers.
Syntax:
float floatVar;
Size:
32-bit (4 bytes)
Default value:
0.0
Range:
unlimited
Demo:
class FloatDemo {
public static void main(String[] args) {
float floatVar = 1.402398464444F;
System.out.println(floatingPoint);
}
}
In the code example above, the F suffix of the floatVar variable tells the compiler that it's a float literal. Without it, the above code will return an error.
The code outputs the rounded up floating-point value:
1.4023985
Double
The double data type is a double-precision 64 bit IEEE 754 (arithmetic standard) floating-point. This numeric type range is unlimited.
Syntax:
double doubleVar;
Size:
64-bit (8 bytes)
Default value:
0.0
Range:
unlimited
Example:
class DoubleDemo {
public static void main(String[] args) {
double doubleVar = 1.402398464444;
System.out.println(doubleVar);
}
}
The code outputs the floating-point value:
1.402398464444
Important: Monetary calculations like currency, float, and double data types are subject to rounding error and may not be suitable. It's recommended you use BigDecimal which has better precision than other floating-point types. BigDecimal is frequently used in banking and insurance production projects.
Check out this Java language specification to learn more about Java floating-point types, formats, and values.
Char
The char data type is a single 16 bit Unicode character. This data type's range lies between '\u0000' (or 0) to '\uffff' (or 65,535 inclusive). You use char data type variables to store characters.
Syntax:
char charVar;
Size:
16-bit (2 bytes)
Default value:
'\u0000'
Range:
'\u0000' (or 0) to '\uffff'
In the above range, '\u0000' and '\uffff' are the Unicode system's lowest and highest values, respectively.
Demo:
class CharDemo {
public static void main(String[] args) {
char charVar = 'G';
System.out.println(charVar);
}
}
The code outputs a character value:
G
Why does the char data type in Java use 16 bits (2 bytes)?
Java uses the Unicode system. 8 bits is not enough to represent all characters in the Unicode system, so Java uses 16 bits (2 bytes) for characters.
To learn more about the Unicode system, check out the Java documentation on Unicode.
Non-Primitive or Reference Data Types
Non-primitive or reference data types don't store their variable data in memory. Still, they contain a memory address of that variable value. These data types aren't predefined in Java. Programmers create them.
Non-primitive data types are created and used to store a group of values.
String
A String is a sequence/array of characters held in a single variable. In Java, strings are objects. Programmers create and manipulate strings using the String class provided by the Java platform. The String class is immutable, which means once a variable of String data type is created, it cannot be changed.
The String class has a lot of methods to perform operations on strings such as compare(), compareTo(), equals(), concat(), split(), length(), replace() etc.
The String class implements Serializable, Comparable, and CharSequence interfaces.
Syntax:
String <string_variable> = “<sequence_of_characters>”;
Demo:
How to declare variables of String data type:
class StringDemo{
public static void main(String args[]){
// Declaring String variable
String stringVar = "Hello world!";
// Declaring String variable using new operator
String stringVar2 = new String("Hello world!");
System.out.println(stringVar);
System.out.println(stringVar2);
}
}
The code above prints out:
Hello world!
Hello world!
The code snippet below tests the concept of string immutability:
class TestingStringImmutability{
public static void main(String args[]){
String stringVar = "Hello";
//concat() method appends the new string at the end
stringVar.concat(" world!");
//will print "Hello" only because strings are immutable objects
System.out.println(stringVar);
}
}
Class
A class is a programmer-defined blueprint from which you create objects along with their attributes and methods. For example: in real life, a bicycle is an object. The bicycle has attributes, like size and color, and methods, such as speed-up and apply-brakes.
Generally, class declarations can include these parts:
- Access modifiers: This refers to the accessibility of a class. A class access could be public, private, or default (don't use any modifier).
- Class name: The class name should begin with an initial letter capitalized.
- Superclass (if any): The name of the parent (superclass) it inherits, if any, preceded by the extends keyword. A class can extend to only one parent.
- Interfaces (if any): A list of comma-separated interfaces implemented by the class, preceded by the implements keyword. A class can implement more than one interface.
- Class body: The class body containing attributes and methods surrounded by curly braces { }.
Bicycle class:
// Class Declaration
public class Bicycle {
// Instance Variables
String name;
int size;
String color;
// Constructor Declaration of Class
public bicycle(String name, int size, String color){
this.name = name;
this.size = size;
this.color = color;
}
// method 1
public void speedUp(){
}
// method 2
public void applyBrakes(){
}
}
Interface
An Interface is similar to a class and can have methods and variables like a class. Still, the methods in an interface are abstract. An abstract method is a method without a body (no implementation).
An interface can also contain default methods, static methods, constants, and nested types. In an interface, only default methods and static methods have bodies.
Why use Interfaces?
- You can achieve multiple inheritance in Java using interfaces.
- They are used to capture similarities among unrelated classes without forcing a class relationship.
- They are used to achieve loose coupling and total abstraction.
Interface:
interface Car {
void changeGear(int newValue);
void speedUp(int increment);
void applyBrakes(int decrement);
}
A class implementing the Car interface:
class HondaCar implements Car {
// The compiler will now require that methods
// changeGear, speedUp, and applyBrakes all be implemented.
// Compilation will fail if those methods are missing from this class.
}
Enumeration
An enumeration is a set of named constants. Each enumeration constant in the set is public, static, and final by default. An Enumeration can have constructors, instance variables, and methods.
Why use an enumeration?
- An enumeration offers an easy way to work with sets of related constants.
- Programmers use enumeration when they know all possible values at compile time.
Enumeration:
enum CompassDirection{
NORTH, SOUTH, WEST, EAST
}
Main class:
class EnumerationDemo{
public static void main(String args[]){
CompassDirection direction; //direction is an enumeration variable of type CompassDirection
direction = CompassDirection.NORTH; //direction can be assigned only the constants defined under enum type CompassDirection
System.out.println("Direction is " + direction);
}
}
The code above in the Main class will output:
Direction is North
Array
In Java, an array is an object used to store a group of values of the same data type. These values can be of primitive or non-primitive data types.
In Java arrays:
- Have fixed length specified during creation.
- Elements in an array starting at index 0, and second element 1, and so on.
- Have fast access due to indexing.
Syntax:
int scores[] = new int[10]; // array of primitive type values
Student students[] = new Student[10]; // array of non-primitive (class student) type values
Example:
class ArrayDemo{
public static void main(String args[]){
//declaration, instantiation and initialization of an array of primitive type
int scores[] = {100,60,75,45};
// printing the array
for(int j=0; j < scores.length; j++){
System.out.println(scores[i]);
}
}
}
The code above will output the following:
100
60
75
45
Var Type - Local Variable Type Inference
The Oracle Corporation introduced the var type (Local variable type inference) in Java 10. You use var to reduce boilerplate variable type definitions and increase code readability.
Map<String,String> map=new HashMap<String,String>();
Map<User,List<String>> listofGames=new HashMap<>();
The code above can be simplified using the var keyword, which allows the local variable type to be inferred by the compiler, so you don’t need to declare it. Hence, you can write the above two statements as shown below:
var map=new HashMap<String,String>();
var listofGames=new HashMap<User,List<String>>();
The var is not like every other variable type definition in Java. You need to keep in mind the following point about local variable type inference in Java 10:
- Every statement containing the var keyword has a static type which is the declared type of value. This means that assigning a value of a different type will result in a compilation error. Hence, Java is still a strongly typed language.
var num=0;// At this point, the compiler interprets variable num as integer.
num="34"; // This will result in compilation error
//because of incompatible types: java.lang.String
//can't be converted to int.
- You cannot use the var local variable type inference:
- With method arguments
public long count (var num);// Compilation
//error because compiler cannot infer type of local
//variable num; cannot use 'var' on variable without
//initializer
- To initialize a null variable
var num=null;// Compilation error because
//compiler cannot infer type for local variable
//num since any Java object reference can be null
- With lambda expressions
var p = () -> {} // Compilation error because
//compiler cannot infer type for local variable p;
//lambda expression needs an explicit target type
To learn more about var type, check out the Java 10 local variable type reference docs.
Conversion of Primitive Data Types
You can convert Java primitive types in the following ways:
A widening primitive conversion is done when you need to convert a primitive data type to a larger primitive type.
int intVar = 154;
long longVar = intVar;
The above is possible because the smaller primitive value is placed into a wider container (larger type). The extra space ensures that no information is lost.
This can also be used to go from integer types to floating points:
float floatVar = longVar;
double doubleVar = floatVar;
Sometimes there is a need to store a larger value than the primitive type used in the variable declaration. This conversion can result in information loss since some bytes are shed in the process. This conversion is done by using a cast.
int intVar = (int) doubleVar;
byte byteVar = (byte) intVar;
Converting a primitive data type into its equivalent Wrapper type is known as boxing. The opposite operation is known as unboxing.
Integer theIntegerReference = intVar;
int anotherIntVar = theIntegerReference;
All primitive data types can be converted to String using their wrapper classes, which override the toString() method:
String stringVar = theIntegerReference.toString();
If you need to go back, you need to use a parse method defined by the corresponding Wrapper class:
byte newByte = Byte.parseByte(stringVar);
short newShort = Short.parseShort(stringVar);
int newInt = Integer.parseInt(stringVar);
long newLong = Long.parseLong(stringVar);
float newFloat = Float.parseFloat(stringVar);
double newDouble = Double.parseDouble(stringVar);
boolean newBoolean = Boolean.parseBoolean(stringVar);
There is an exception here for the char data type because a string is of a char sequence. To perform the conversion, you can use the charAt() of the String class:
char newChar = stringVar.charAt(0);
To learn more about primitive data type conversion, check out Java primitive conversions.
Conclusion
In this guide, you learned about Java data types, what they are, and how they work through easy-to-understand code examples. There is a lot more to data types in Java, and the following helpful resources can help Java developers learn more:
- Java documentation on primitive data types
- A deep dive into Java: Primitive data types
- Boxing/Unboxing conversions
- Non-Primitive Data types in Java with Example
If you want to expand your knowledge about Java coding you can check out Java best practices as well as Java trends for 2021.