Data Types in Java

Java data types are generally used to determine the kind of values a variable may contain and define the amount of memory that should be assigned to the variable. Since Java is a statically typed programming language, all variables must be declared with some data type before they are used. This simply enables type safety and prevents unexpected behavior during the runtime of Java Code.

The choice of the right Java data type is generally very important for optimizing performance, conserving memory, and avoiding type mismatch errors. Java typically supports a rich collection of data types that are generally categorized as primitive data types (e.g., int, double, char, boolean) and non-primitive data types (e.g., String, Arrays, Classes, and Interfaces). 

Table of Contents:

What are Data Types in Java?

A data type in Java generally helps to determine the type of value a variable may contain and what operations can be performed on that data type. These data types are basic building blocks of Java code as they determine the memory allocation, performance of the program, and type safety.

As Java is a strongly typed programming language, all the variables need to be declared with a particular data type before using it. This generally prevents type mismatches and simply ensures that all operations performed on the variables are valid.

For example, if any variable is defined as an int, it cannot hold decimal numbers or characters:

int number = 10; // Correct
number = 10.5;   // Compilation Error: Type mismatch

Importance of Java Data Types

  • Prevents Errors: Java typically offers compile-time type checking in order to reduce any errors that can occur during the runtime.
  • Optimizes Memory: Selecting the correct data types is very important to prevent memory wastage and increase overall efficiency.
  • Ensures Accuracy: Using any advanced data type like BigDecimal that is used for financial calculations simply prevents precision issues.
  • Enhances Code Readability: Also, defining the data types using the informative variable simply enhances the code readability and maintainability.

Categories of Data Types

Java classifies data types under two general categories:

  • Primitive Data Types
  • Non-Primitive Data Types

Primitive Data Types in Java

Primitive data types are the basic data types of Java programming. They are already defined in Java and contain simple values directly in memory. Primitives are not objects like non-primitive data types and they do not have any additional memory for references, so they are efficient in memory and faster in operations.

Java supports a total of 8 primitive data types, which are categorized into three groups:

  • Integer: byte, short, int, long
  • Floating point: float, double 
  • Character and Boolean types: char, boolean

These data types have predefined memory sizes and value ranges, which simply remain the same for all Java platforms.

Look at the below table to know about all the Primitive Data Types:1. byte (1 byte)

Data Type Size Default Value Range
byte 1 byte 0 -128 to 127
short 2 bytes 0 -32,768 to 32,767
int 4 bytes 0 -2³¹ to 2³¹-1v
long 8 bytes 0L -2⁶³ to 2⁶³-1
float 4 bytes 0.0f ±3.4e−038 to ±3.4e+038
double 8 bytes 0.0d ±1.7e−308 to ±1.7e+308
char 2 bytes ‘\u0000’ (null) Unicode characters (0 to 65,535)
boolean 1 bit false true or false

The byte data type in Java is a signed 8-bit integer and thus can hold whole numbers between -128 and 127. Basically, it is the smallest integer type in Java and is often used when memory is an issue.

1.1 Why Use byte?

  • It uses less memory compared to larger integer data types like int and long.
  • Ideal for large data sets where memory constraints are an issue (e.g., file processing, raw data processing).
  • Frequently used for binary data processing such as image processing or network communications.

1.2 Example of Memory Efficiency of Byte Data Type

Suppose you have thousands of small numbers in the range of (-128 and 127), then it would be better if you store those numbers in a byte of 1 byte rather than int of 4 bytes as it will increase the memory efficiency.

byte age = 25;
System.out.println("Age: " + age);

1.3 Overflow Behavior of bytes

Whenever you want to store the numbers outside the range of bytes in the byte variable, it gets wrapped around to the minimum value, this is generally called the overflow of byte.

byte num = 127; // Maximum value for byte
num++;          // Increments beyond limit
System.out.println(num); // Output: -128 (Wraps around)

2. short (2 bytes) 

The short data type in Java is simply a 16-bit signed integer that can store the values range from -32768 to 32767. They have a larger range than bytes but they occupy less space than int.

2.1 When Should You Use short?

  • When byte is too small, but int is too large for your data.
  • They are very useful in older programs and systems where memory is a major constraint.
  • Majorly used in the development of games, graphical processing, and embedded systems for better optimization.

2.2 Code Example

short distance = 15000;
System.out.println("Distance: " + distance);

2.3 Overflow Behavior

short maxShort = 32767; 
maxShort++; // Overflows and wraps around
System.out.println(maxShort);

This example shows the wrapping around of numbers when they exceed their limit.

3. int (4 bytes)

int data type is the most common integer data type in Java and they are generally the default data type for integers. It is a 32-bit signed integer, which ranges from -2,147,483,648 to 2,147,483,647.

3.1 Why is int the Default?

  • It provides a reasonable compromise between memory use and range.
  • Perfect for loop counters, array indexing, and mathematical computations.
  • Most operations on integers default to int, so it’s the best type to use.

3.2 Example Usage

int population = 1400000000; // 1.4 billion
System.out.println("Population: " + population);

3.3 Performance Considerations

 

Although the default is int, byte, or short can be more suitable if your values are very small (e.g., 0-127) in memory-conscious applications.

4. long (8 bytes)

When int is not enough, we use long. This signed 64-bit integer can store values from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.

4.1 Where is long used?

  • Ideal for extremely large numbers, such as timestamps, financial calculations, and astronomical calculations.
  • Used while working with large data or while performing operations beyond int ranges.

4.2 Code Example

long worldPopulation = 8000000000L; // 8 billion
System.out.println("World Population: " + worldPopulation);

Notice the “L” suffix at the end? That’s required to specify that the number is of type long, otherwise, Java will treat it as an int.

5. float (4 bytes)

float is a 32-bit floating-point data type that is generally used for storing decimal numbers. It is particularly useful when memory is a concern and high precision is not required.

5.1 Key Characteristics

  • Can hold values in the range ±3.4e−038 to ±3.4e+038.
  • Less precise than double, so it’s not appropriate for monetary calculations.
  • Requires “f” suffix when defining values.

5.2 Example Usage

float price = 99.99f;
System.out.println("Price: " + price);

5.3 Precision Issue Example

float num1 = 1.0000001f;
float num2 = 1.0000002f;
System.out.println(num1 == num2); // Output: true (Precision loss)

Because of restricted precision, float is not preferred for high-precision calculations.

6. double (8 bytes)

If you need more precision, then double is the route to take. It is basically the default decimal data type in Java. It is a 64-bit floating-point number and the default for decimal arithmetic.

6.1 Why Choose double Over float?

  • It basically provides much more precision than floating point.
  • It is majorly used in scientific calculations, simulations, and machine learning.
  • Also, it eliminates rounding errors that arise in float.

6.2 Example Usage

double pi = 3.141592653589793;
System.out.println("Pi: " + pi);

7. char (2 bytes)/h3>
Unlike most of the other languages in which char is 1 byte, Java reserves 2 bytes (16 bits) to hold characters. The reason is that it is Unicode-supported, i.e., it is able to support global alphabets, symbols, and special characters beyond the basic set of characters in ASCII.

7.1 Why 2 Bytes for char in Java?

  • ASCII (employed in old languages) is 1 byte, and it only supports 256 characters.
  • Unicode requires 2 bytes, and it can support 65,536 characters, including Greek, Arabic, Chinese, emojis, and math symbols.
  • This enables Java programs to provide internationalization support and handle multiple-language text.

7.2 Examples of char in Java

char letter = 'A';
char numberChar = '5';
char symbol = '$';
System.out.println(letter + " " + numberChar + " " + symbol)

7.3 Key Points About char

  • Holds a character, not a string
  • Accepts letters, digits, and special characters.
  • Takes single quotes (‘A’), unlike String, which takes double quotes (“Hello”).

8. boolean (1 bit)

The boolean data type is a 1-bit data type that can hold only two values: true or false. It is utilized primarily in decision-making, in conditions, and in logical operations.

8.1 Why is boolean Only 1 Bit?

  • Since there is only one of two possible values (true or false), a whole byte is not required.
  • It is Java-optimized internally, albeit it requires more than 1 memory position in memory due to array alignment.
  • Necessary for control of flow (if-else, loops, logical operations, flags, and conditions).

8.2 Example of boolean Usage

boolean isJavaFun = true;
boolean isSkyGreen = false;
System.out.println("Is Java fun? " + isJavaFun);

8.3 Key Points About boolean

  • Only two options (true or false).
  • Used in logical expressions, conditionals, and in loops.
  • Cannot be converted to numbers (for example, in other languages).

Here’s the executable Java code consisting of all the examples mentioned:

Java

Output:

Key Points About boolean

Non-Primitive Data Types in Java

Non-primitive data types or reference types are typically more complex compared to primitive data types. In essence, non-primitive types do not store actual values like primitives but rather store references (memory addresses) to objects. Non-primitive data types are typically used to handle dynamic and structured data that typically supports strong object-oriented programming (OOP) aspects of Java.

Key Characteristics of Non-Primitive Data Types

  1. Stored in Heap Memory: Unlike the primitive data types stored in stack memory, the non-primitive data types are stored in heap memory, and their reference is stored in stack memory.
  2. Can Store More Than One Value: Primitive data types hold a single value, whereas non-primitive data types hold more than one related value, i.e., a set of integers or a collection of strings.
  3. Have Properties and Methods: Unlike primitive types that hold just values, non-primitive types hold methods that allow processing and manipulation.
  4. Nullable: Non-primitive variables can be assigned a null reference, i.e., they do not point to any object in memory currently.

Types of Non-Primitive Data Types in Java

There are majorly four types of non-primitive data types in Java:

  • Strings: They are an Immutable sequence of characters (String class).
  • Arrays: They consist of values of the same data types.
  • Classes and Objects: They are mostly used concepts in Java as they are basic Java OOPS building blocks.
  • Interfaces: They define the templates for class behavior implementations.

Non-Primitive Data Type Explanation

1. Java Strings

A Java String is basically a non-primitive data type that is generally used to contain the sequence of characters. These strings are typically objects present inside Java that have many built-in methods that are used in string manipulation. Unlike char, String can hold more than one character.

1.1 Key Features of Strings

  • Immutable: Once a String is created in Java you cannot change or modify it.
  • Stored in String Pool: Strings in Java are stored in String Pool in order to Optimize the memory use.
  • Comes with inbuilt methods: Strings in Java generally come with many built-in methods that simply allow for easy manipulation and comparison,

1.2 String Declaration and Initialization

String str1 = "Hello"; // String literal (stored in String Pool)
String str2 = new String("World"); // Using new keyword (stored in Heap)

1.3 Why Strings are Immutable?

In Java, a modification to a String creates a new object rather than modifying the current one. This ensures security, thread safety, and performance.

String name = "Java";
name.concat(" Intelllipaat"); // Creates a new String, doesn't change 'name'
System.out.println(name);

To change a string, you have to assign the result to a new variable:

String fullName = name.concat("Intellipaat");
System.out.println(fullName);

1.4 Final Code

public class Main{
public static void main (String[] args){

String name = "Java";
name.concat("Intellipaat"); // Creates a new String, doesn't change 'name'
System.out.println(name);
String fullName = name.concat(" Intellipaat");
System.out.println(fullName); 
}
}

Output:

Final Code

Strings are utilized in Java programs throughout, ranging from simple text manipulation to more complex processes such as data validation and encryption.

2. Java Arrays

An array in Java is a non-primitive data structure that generally consists of multiple instances of the same type of data in sequential memory. An array generally facilitates index-based access to the elements of the array and eventually increases performance in the case of large datasets.

2.1 Key Features of Arrays

  • Fixed Size: The arrays are generally fixed in size and you cannot change their size after their declaration.
  • Zero-Based Indexing: They start at 0 indices in order to access the elements.
  • Efficient Retrieval: They also enable speedy access to elements using indices.
  • Homogeneous Storage: They store only one type of data at a time.

2.2 Declaring and Initializing Arrays

Arrays are declared in a declaration of the data type in conjunction with a pair of brackets and can be initialized using the new keyword or using values directly.

// Declaration
int[] numbers; 
// Initialization
numbers = new int[5]; // Array of size 5
// Direct Declaration and Initialization
int[] values = {10, 20, 30, 40, 50};

2.3 Why Use Arrays?

Arrays are useful when you need fixed-size storage and speedy access to large quantities of data. They do not support dynamic resizing, though, so lists like ArrayList would be a better option in certain cases.

3. Classes and Objects in Java

Java classes and objects form a fundamental type of non-primitive data types. As compared to primitive data types that store individual values, classes define composite data structure, and objects store actual data at runtime. As objects are reference types, they store memory addresses in place of actual values.

3.1 Classes in Java

A Java class is typically a user-defined data type that merely serves as the template for creating objects. It also includes various types of variables, methods, and constructors.

Key Characteristics of Classes

  • Reference Type: Stores a memory address of an object instead of actual data.
  • Encapsulation: Bundles data (fields) and behavior (methods) together. Can Store
  • Multiple Values: Classes can hold multiple values, unlike primitive types.

3.2 Objects: Instance of Class

An object is a realization of a class that consists of concrete data. Every object is distinct in nature and can be created multiple times using a single declaration of a class.

Java

Output:

Objects Instance of Class

3.3 Why Are Classes and Objects Considered Non-Primitive?

  • Stored in Heap Memory: Unlike the primitive types stored in the stack, objects are stored in the heap.
  • Holds Multiple Attributes: Unlike int or char, which store a single value, objects store multiple values.
  • Works with Methods: Objects can have behavior, but primitive types can’t.
  • Can Be Null: Objects can hold a null reference, meaning they don’t point to any actual data.x`

4. Interfaces in Java

Interfaces in Java are a collection of abstract methods (methods without body) defining a set of behaviors that a class can implement. An interface is an agreement between two classes, i.e. the interface defines what a class must implement, but it does not define anything about how it must be implemented. Interfaces in Java can contain Abstract Methods, Default and Static Methods, or Private Methods.

Key Features of Interfaces

  • Reference Type: Interfaces hold no values; they hold references to implementing objects.
  • Full Abstraction: They provide a design without any actual implementations. Multiple
  • Inheritance Support: A class can inherit from more than one interface, circumventing Java’s single inheritance limitation.
  • Cannot Be Instantiated: Interfaces, in contrast to classes, cannot be instantiated explicitly.

4.1 Declaring an Interface in Java

An interface is declared using the interface keyword and includes abstract methods (without any body).

// Defining an interface
interface Vehicle {
    void start();  // Abstract method (no implementation)
}

Type Conversion (Widening)

Type Conversion (or widening conversion) occurs automatically when a data type of smaller size is assigned to a data type of larger size.

Rules for Automatic Type Conversion

  1. The two kinds must be compatible (e.g., int to double is OK, but boolean to int is not).
  2. The target type should be larger than the source type to prevent data loss.

Example of Type Conversion

Java

Output:

Rules for Automatic Type Conversion

Here, int (4 bytes) is automatically converted to double (8 bytes) without casting, since it is a widening conversion.

Type Casting (Narrowing) – Explicit Conversion

Type Casting (or narrowing conversion) is done when a bigger data type is explicitly cast to a smaller data type. Since this may lead to data loss, explicit casting using parentheses ( ) is required.

Rules for Explicit Type Casting

  1. Data loss can occur when switching from a larger type to a smaller type.
  2. Syntax: (targetType) value
  3. Must be accomplished manually because narrowing conversion is not done by Java automatically.

Example of Type Casting

Java

Output:

Rules for Explicit Type Casting

Here, double (8 bytes) is cast to int (4 bytes), losing the decimal part (99.99 -> 99).

Type Promotion in Expressions

When performing arithmetic, Java will implicitly promote smaller data types to a larger data type in mixed-type expressions.

Example of Type Promotion

Java

Output:

Example of Type Promotion

Here, byte (1 byte) is promoted to int (4 bytes) before multiplication.

Type Casting in Reference Types (Upcasting and Downcasting)

Type casting is also applied to objects when dealing with inheritance and polymorphism.

Upcasting (Implicit Conversion – Safe)

Upcasting is done when a subclass reference is assigned to a superclass reference implicitly.

Example:

Java

Output:

Upcasting (Implicit Conversion – Safe)

Here, the Dog object is implicitly cast to an Animal reference.

Downcasting (Explicit Conversion – Requires Casting)

Downcasting is the conversion of a superclass reference to a subclass reference, and explicit type casting is required.

Java

Output:

Downcasting (Explicit Conversion – Requires Casting)

Here, Animal reference is explicitly cast to Dog to call bark().

Wrapper Classes in Java 

Wrapper classes in Java enable primitive data types (int, char, double, etc.) to be handled as objects. Since Java is an object-oriented language, objects are required in most situations, e.g., if we are using collections (ArrayList, HashMap) or generics, where primitives can’t be used directly.

Java has a wrapper class for every primitive type, which is a member of the java.lang package:

Primitive Type Wrapper Class
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

Example of Using Wrapper Classes

Java

Output:

Using Wrapper Classes

Why Use Wrapper Classes?

  • Allows primitives to be used in collections (e.g., ArrayList<Integer>, HashMap<Character, String>).
  • Provides object-oriented features like null assignment (e.g., Integer obj = null;)
  • Provides utility methods (e.g., Integer.parseInt(“123”) to parse a string into an integer).
  • Supports autoboxing & unboxing, which automatically converts between primitive types and their wrapper classes.

Although wrapper classes give you flexibility, they require more memory than primitives. Use them whenever you need to.

Autoboxing and Unboxing in Java

  • Autoboxing: Autoboxing is the automatic conversion of primitive data types to their corresponding wrapper class objects. It happens when a primitive value is assigned to a reference variable of the wrapper class.
  • Unboxing: Unboxing is the reverse process, where a value of a wrapper class is automatically converted back to a primitive type.

These conversions are accomplished internally by Java, and they render code more concise and manual conversions less.

Example of Autoboxing and Unboxing

Java

Output:

Autoboxing and Unboxing

Enumerated Types (Enums) in Java

A Java enumeration (enum) is a special data type that defines a fixed set of constants. It is used when a variable can only be one of a small number of possible predefined values (e.g., days of the week, directions, levels). 

Enums are more type-safe and readable than final static constants.

Syntax and Example of Enums

Java

Output:

Syntax and Example of Enums

BigInteger and BigDecimal Classes in Java

The primitive data types in Java like int, long, and double generally provide a limited range and precision for high-level programming calculations. The package in Java like java.math has classes like BigInteger and BigDecimal that are simply used for high-precision arithmetic calculations of large numbers in Java

1. BigInteger Class

1.1 Why Use BigInteger?

  • The Java Data types like int and long have limited predefined values that do not support numbers out of their range.
  • With the use of BigInteger, you can store and calculate arbitrarily larger integer values without any size limitations.
  • BigInteger in Java also provides support for the basic arithmetic operations like addition, subtraction, division, multiplication, and modular arithmetic.

Example: Creating and Using BigInteger

Java

Output:

Creating and Using BigInteger

1.2 Common BigInteger Methods

Method Description
add(BigInteger val) Adds two BigInteger values
subtract(BigInteger val) Subtracts one BigInteger from another
multiply(BigInteger val) Multiplies two BigInteger values
divide(BigInteger val) Divides one BigInteger by another
mod(BigInteger val) Returns remainder of division
pow(int exponent) Computes power of a BigInteger
gcd(BigInteger val) Returns the greatest common divisor
isProbablePrime(int certainty) Checks if a number is prime

2. BigDecimal Class

Why Use BigDecimal?

  • The data type like Floating Point in Java (double and float) does not provide the exact values in the computations of financial and scientific problems due to rounding errors.
  • With BigDecimal, it generally provides the precision of any scale for the exact monetary, financial, and scientific computations.
  • It typically supports the exact arithmetic operation without the loss of precision.

Example: Using BigDecimal for Precise Arithmetic Calculations

Java

Output:

Using BigDecimal for Precise Arithmetic Calculations

2.1 Common BigDecimal Methods

Method Description
add(BigDecimal val) Adds two BigDecimal values
subtract(BigDecimal val) Subtracts one BigDecimal from another
multiply(BigDecimal val) Multiplies two BigDecimal values
divide(BigDecimal val, RoundingMode mode) Divides two BigDecimal values with rounding
setScale(int newScale, RoundingMode mode) Sets the decimal places with a rounding mode

2.2 Handling Rounding Issues

Unlike double, BigDecimal avoids rounding errors. However, when dividing numbers, you must specify a rounding mode:

Example:

Java

Output:

Handling Rounding Issues

Conclusion

With this, you have come to the end of this Java Data types tutorial. Learning Java data types is very important for writing effective and error-free codes. Java generally supports a rich set of data types like int, double, char, and boolean to perform basic tasks efficiently while it also supports the nonprimitive data types like Strings, Arrays, Classes, and Interfaces that simply provide flexibility and Object Oriented features to perform the complex operations. Choosing the efficient data type based on your requirements is an important factor for performance optimization and type mismatch errors.

Understanding advanced features like type conversion, type casting, Wrapper classes, BigInteger, BigDecimal, and best practices generally allows developers to write scalable and efficient Java programs.

FAQs on Java Data Types
1. What are the main data types in Java?

Java has typically two data type categories, Primitive data types like byte, short, int, long, float, double, char, and boolean, and Non-Primitive data types like String, Arrays, Classes, and Interfaces.

2. Why does Java have both primitive and non-primitive data types?

Java is generally a high-level language therefore it offers more functionality and features where primitive data types are very compact and faster but non primitive data types typically provide versatility, more methods, and object-oriented features.

3. Why are char 2 bytes in Java?

Java supports Unicode encoding which generally takes 2 bytes to encode the characters of multiple languages around the world.

4. What is the difference between float and double in Java?

float is 32 bit which is less accurate but comparatively faster whereas double of 64 bit is more precise and is used for high-level scientific calculations.

About the Author

Technical Research Analyst - Full Stack Development

Kislay is a Technical Research Analyst and Full Stack Developer with expertise in crafting Mobile applications from inception to deployment. Proficient in Android development, IOS development, HTML, CSS, JavaScript, React, Angular, MySQL, and MongoDB, he’s committed to enhancing user experiences through intuitive websites and advanced mobile applications.