Java Data Types and Variables 2024

Building on the basics of your first Java program and syntax understanding, we can now delve into Data Types and Variables. Mastering these is crucial for managing data efficiently — int and boolean for direct value handling, String for complex structures, and arrays and enums for structured collections and constant values.
Overview of the Eight Primitive Data Types:
Each data type, crafted for a specific purpose, brings its own flavor to the Java programming language.
int – a commonly used type for whole numbers:
int score = 100;
byte – a compact data type, great for conserving memory:
byte age = 27;
short – a tad larger than byte but smaller than int:
short year = 2023;
long – for representing vast numbers:
long population = 7816253000L;
float – floating-point numbers with single precision:
float price = 10.99F;
double – floating-point numbers with double precision:
double distance = 384.4;
boolean – the epitome of simplicity, true or false:
boolean isJavaFun = true;
char – encapsulates single characters:
char initial = 'J';
Storage Size, Minimum and Maximum Values, and Examples
Each primitive type occupies a certain space in memory, ranging from byte's modest 8 bits to long and double's chunky 64 bits.
Likewise, they each have their own range of representable values. For instance, an int can stretch from -2^31 to 2^31-1, and a char, in its 16-bit purity, can represent Unicode characters.
Overflow and Underflow
Ever tried adding 1 to the maximum value an int can hold? Or subtracting 1 from its minimum value? These actions will result in overflow and underflow, respectively. While these might sound catastrophic, in Java, it usually just wraps the number around.
int maxValue = Integer.MAX_VALUE;
int overflow = maxValue + 1;
The world of primitive data types in Java is far from mundane — it’s the terrain where we first set our feet, grounding our understanding. From the basics of a boolean to the vastness of a long, these data types represent the core of Java's ability to interact with information.

Non-primitive data types
As we build on our understanding of primitive types, we now need to delve deeper into non-primitive data types, as they form the bedrock of object-oriented programming in Java.
In software development, precision and the right tool selection are paramount. Java’s non-primitive data types serve as essential tools, granting programmers the flexibility to define their own data types, store multiple data items, and harness the power of method invocations. We covered this in the Java Syntax section, but lets briefly touch upon it again.
Types of Non-Primitive Data Types:
Class: Think of a class as the blueprint of a building. Just as a building comprises various sections like rooms, corridors, and lobbies, a class consists of properties and methods. It’s identifiable by its name and can inherit attributes and behaviors from another class, termed as a superclass.
Example of a class:
class Demo {
int a, b;
// Constructor
Demo(int a, int b) {
this.a = a;
this.b = b;
}
// Method to add two numbers
int addition() {
return a + b;
}
// Method to subtract two numbers
int subtraction() {
return a - b;
}
}
String: A fundamental component in Java, the String class facilitates the creation and manipulation of a sequence of characters. It’s distinct from some other languages in that you don’t need to use a terminating null character.
Example of a string:
String s1 = "Scaler";
String s2 = new String("Academy");
Array: If we analogize an array to a bookshelf, each slot (or index) in an array holds a specific element (or value). Crucially, every element on that particular shelf (or array) is of the same data type.
Example of an array:
int[] arr1 = {1, 2, 3};
double[] arr2 = {1.1, 2.2, 3.3};
Interface: Interfaces in Java act as a contract. They outline a set of methods without specifying their implementations. Classes that decide to “sign” this contract (that is implement the interface) are bound to provide implementations for all its methods.
Example of an interface:
interface Operations {
int addition(int a, int b);
int subtraction(int a, int b);
}
class Solve implements Operations {
public int addition(int a, int b) {
return a + b;
}
public int subtraction(int a, int b) {
return a - b;
}
}
Difference between Primitive and Non-Primitive Data Types:
Origin: Primitive types are innately defined in Java. On the contrary, non-primitive types are predominantly user-defined, with notable exceptions such as the String.
Value Storage: Primitive data types are designed to hold a single value. In contrast, non-primitive types can encompass multiple values or even complex behaviors.
Memory Allocation: Primitive types are allocated memory on the stack. However, for non-primitive types, the stack merely contains a reference, while the actual object resides in the heap memory.

Type casting
Typcasting (translating one data type to another) is an integral concept in software development. You can use it to convert one type of information to another type, either explicitly (something you do yourself) or implicitly (via compiler compilation).
Understanding type casting is essential to writing efficient code as it impacts both program functionality and resource utilization.
What is Type Casting?
Type casting refers to the practice of changing one data type entity to another. You could think of type casting like trying to fit a square peg into a circular hole: sometimes you will need to reshape its form before fitting.
Also, as various sections interact within programs and compatibility issues become an issue between these components of code, type casting becomes necessary for compatibility purposes.
Implicit Casting (Automatic):
When the conversion is risk-free and the destination type can hold the original data without loss, the compiler steps in, handling it automatically.
int myInt = 9; double myDouble = myInt; // Implicit casting from int to double
Here, an int value fits comfortably into a double, so no explicit command is needed.
Explicit Casting (Manual):
At times, the conversion might be risky, potentially leading to data loss. Here, developers must step in, indicating the casting manually.
double myDouble = 9.78; int myInt = (int) myDouble; // Explicit casting from double to int
Note that 9.78 becomes 9, and the decimal portion (.78) is discarded. This is where potential data loss lurks.
Type Casting in Object-Oriented Programming
In OOP, casting isn’t just a data play — it extends to objects and their types.
Upcasting: It’s like looking at an object through a broader lens. A specific object (like a Dog) is viewed as a more general object (like an Animal). It's always safe.
class Animal {}
class Dog extends Animal {
void bark() {}
}
Animal myDog = new Dog(); // Upcasting the Dog object to Animal type
Downcasting: This is a tad riskier. It’s about viewing a general object through a specific lens. Explicit casting is needed since there’s an inherent risk.
Dog myNewDog = (Dog) myDog; // Downcasting the Animal object to Dog type
Checking Object Type: Before embarking on downcasting, it’s wise to check the type to avoid runtime errors.
if(myDog instanceof Dog) {
Dog anotherDog = (Dog) myDog;
}
Best Practices in Type Casting
Caution Over Casting: Not every situation requires casting. Only use it when necessary. Indiscriminate casting can make your code harder to read and maintain.
Stay Vigilant: Always be on the lookout for potential data loss. For instance, when casting float to int, remember the decimal truncation.
Exception Handling: Anticipate exceptions that might arise, like ClassCastException. When they do, handle them gracefully to ensure your program doesn't crash unexpectedly.
try {
Dog retrievedDog = (Dog) someAnimal;
} catch (ClassCastException e) {
System.out.println("Failed to cast the object.");
}
Common Pitfalls and How to Avoid Them
Loss of Precision: Remember, casting a float or double to an int truncates the decimal. Always ensure that’s the desired behavior.
float value = 3.14f;
int intValue = (int) value; // intValue will be 3
Overflows & Underflows: Casting might lead to unexpected results if the value doesn’t fit into the destination type.
long bigNumber = 5000000000L;
int smallerNumber = (int) bigNumber; // Potential for unexpected values
ClassCastException: Particularly in OOP languages, always check object types before attempting to downcast.
if (someAnimal instanceof Dog) {
Dog d = (Dog) someAnimal;
} else {
System.out.println("Can't cast this animal to a Dog.");
}
Resources
If you’re keen on furthering your Java knowledge, here’s a guide to help you conquer Java and launch your coding career. It’s perfect for those interested in AI and machine learning, focusing on effective use of data structures in coding. This comprehensive program covers essential data structures, algorithms, and includes mentorship and career support.
Additionally, for more practice in data structures, you can explore these resources:
Java Data Structures Mastery — Ace the Coding Interview: A free eBook to advance your Java skills, focusing on data structures for enhancing interview and professional skills.
Foundations of Java Data Structures — Your Coding Catalyst: Another free eBook, diving into Java essentials, object-oriented programming, and AI applications.
Visit LunarTech’s website for these resources and more information on the bootcamp.

