Everything You Wanted to Know About Java Data Types

by Divine Odazie

14 min read

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. 

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 
java data types

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.

java data types

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:

  • Widening primitive conversions
  • 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;

  • Narrowing Primitive Conversions
  • 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;

  • Boxing/Unboxing Conversions
  • 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;

  • String Conversions
  • 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:

    If you want to expand your knowledge about Java coding you can check out Java best practices as well as Java trends for 2021.

    FAQs

    Q: How to choose between primitive and wrapper data types for optimal performance?
    Choose primitive types for performance-critical operations due to lower memory usage and faster access. Use wrapper classes when you need to store them in collections that require objects or need to represent null values.
    Q: Examples of using var for type inference in complex scenarios?
    Using var for type inference allows for cleaner and more readable code, especially in complex scenarios like:
    • Declaring variables with long generic types: var list = new ArrayList<String>();
    • Stream API operations where the type is evident from the context.
    • When initializing variables with factory methods that have a clear return type.
    Q: Best practices for using arrays in Java for performance and memory management?
    Predefine array size to avoid resizing, use primitive types for memory efficiency, choose ArrayList for dynamic arrays, loop efficiently, and manage large arrays to prevent memory leaks. These strategies ensure optimal use of memory and performance.
    Divine Odazie
    Divine Odazie
    Product Engineer & Technical Writer

    Divine is a software engineer and technical writer who spends his days' building software and writing about it. Aside from the world of software he enjoys watching football (soccer), listening to good music, traveling, and having fun in his own way.

    Expertise
    • Software Architecture
    • Java

    Ready to start?

    Get in touch or schedule a call.