Welcome back, future Java master! In our last chapter, we got your Java Development Kit (JDK) set up (we’re using JDK 25, the latest stable release as of September 2025, though JDK 21 remains the current Long-Term Support, or LTS, version), and you even wrote your very first “Hello, World!” program. That was a fantastic start! If you haven’t done that yet, please hop back to Chapter 1 and get yourself sorted.

Now that we know how to make Java say something, it’s time to teach it how to remember things and do calculations. Think of it like learning to speak a language: “Hello, World!” is a simple phrase, but to have a real conversation, you need words (data), ways to store them (variables), and ways to combine them (operators). That’s exactly what we’ll be tackling today!

By the end of this chapter, you’ll understand the fundamental concepts of variables (where you store information), data types (what kind of information you can store), and operators (how you manipulate that information). These are the absolute bedrock of any programming language, and mastering them will unlock your ability to write much more dynamic and useful programs. Ready to dive in? Let’s go!


2.1 Variables: Your Program’s Memory Boxes

Imagine you’re baking a cake. You need to keep track of the amount of flour, sugar, and eggs. You wouldn’t just dump them all into one pile, right? You’d put them in separate, labeled containers. In programming, variables are exactly like those labeled containers! They are names that refer to a storage location in your computer’s memory, where you can store different pieces of information.

Every variable has three main characteristics:

  1. A Name: How you refer to it (e.g., flourAmount, sugarCups).
  2. A Type: What kind of data it can hold (e.g., whole numbers, decimal numbers, text).
  3. A Value: The actual data stored inside (e.g., 2 for flourAmount, "all-purpose" for flourType).

2.1.1 Declaring and Initializing Variables

Before you can use a variable, you need to tell Java about it. This is called declaring a variable. You specify its type and its name.

Then, you often give it an initial value, which is called initializing the variable.

Let’s see this in action. Open your HelloWorld.java file (or create a new VariablesDemo.java file if you prefer to keep things separate) and add the following lines inside your main method:

// Inside your public static void main(String[] args) method

// 1. Declaring a variable:
int myFirstNumber;

// 2. Initializing the variable (assigning a value):
myFirstNumber = 10;

// 3. Declaring and initializing in one go (very common!):
int mySecondNumber = 25;

// Let's print them out to see what's inside!
System.out.println("My first number is: " + myFirstNumber);
System.out.println("My second number is: " + mySecondNumber);

Explanation:

  • int myFirstNumber;: Here, we declare a variable named myFirstNumber. The int keyword tells Java that this variable will hold a whole number (an integer).
  • myFirstNumber = 10;: This line initializes myFirstNumber by assigning it the value 10. The = symbol is the assignment operator.
  • int mySecondNumber = 25;: This is the more common way: declaring and initializing a variable in a single line. It saves space and is often clearer.
  • System.out.println(...): You’ve seen this before! We’re using it to print the values stored in our variables to the console. Notice how we can combine text (a String) with a variable’s value using the + operator – this is called string concatenation, and it’s super useful for showing variable values.

Go ahead, compile and run your code! You should see:

My first number is: 10
My second number is: 25

2.1.2 Variable Naming Rules & Best Practices

Just like in real life, good labels make things easier to understand. Java has rules and best practices for naming variables:

  • Must start with: A letter (a-z, A-Z), an underscore (_), or a dollar sign ($). (Starting with $ or _ is generally discouraged for regular variables, but you might see it in generated code or special contexts).
  • Cannot start with: A number.
  • Can contain: Letters, numbers, underscores, and dollar signs.
  • Cannot be: A Java keyword (like int, public, class, void).
  • Case-sensitive: myNumber is different from mynumber.
  • Best Practice (CamelCase): For multi-word variable names, start the first word with a lowercase letter and capitalize the first letter of subsequent words (e.g., totalStudentCount, userAge). This is called “camelCase” and it’s the standard in Java.
  • Be Descriptive: Choose names that clearly indicate the variable’s purpose. age is better than a, firstName is better than fn.

2.1.3 Constants with final

Sometimes, you have a value that should never change during your program’s execution, like the value of Pi or a maximum number of attempts. For these, you use the final keyword. A final variable can only be assigned a value once.

// Add this to your main method
final double PI = 3.14159; // Declaring a constant
// PI = 3.14; // If you uncomment this line, Java will give you a compile-time error!
System.out.println("The value of Pi is: " + PI);

Explanation:

  • final double PI = 3.14159;: The final keyword makes PI a constant. By convention, constant names are written in ALL_CAPS with underscores separating words.
  • If you try to reassign PI after its initial assignment, the Java compiler will prevent you, which is a great way to catch errors early!

2.2 Data Types: What Kind of Data Are We Storing?

Just as you wouldn’t store water in a flour bag, you need to tell Java what kind of data each variable will hold. This is where data types come in. Java is a “statically typed” language, meaning you must declare the type of a variable before you use it. This helps Java allocate the right amount of memory and prevents many common programming errors.

Java’s data types fall into two main categories:

  1. Primitive Data Types: These are the basic building blocks, storing simple values directly.
  2. Reference Data Types: These store references (addresses) to objects in memory. We’ll touch on String here, but dive much deeper into objects later.

2.2.1 Primitive Data Types

Java has 8 primitive data types, which are categorized by the type of value they hold:

  • Whole Numbers (Integers):
    • byte: Very small whole numbers (-128 to 127).
    • short: Small whole numbers (-32,768 to 32,767).
    • int: The most commonly used integer type (around -2 billion to 2 billion). This is your go-to for whole numbers.
    • long: Very large whole numbers (requires L suffix, e.g., 10000000000L).
  • Decimal Numbers (Floating-Point):
    • float: Single-precision decimal numbers (requires f suffix, e.g., 3.14f).
    • double: Double-precision decimal numbers. This is your go-to for decimal numbers and is more precise than float.
  • Characters:
    • char: A single character (e.g., 'A', '7', '@'). Enclosed in single quotes.
  • Boolean:
    • boolean: Represents true or false. Essential for logic and decision-making.

Let’s add some examples to your main method:

// Inside your public static void main(String[] args) method

// --- Primitive Data Types ---

// Integer types
byte smallNumber = 100;
int normalNumber = 1_000_000; // Underscores for readability in large numbers (JDK 7+)
long veryBigNumber = 1234567890123L; // Note the 'L' suffix for long

System.out.println("Byte: " + smallNumber);
System.out.println("Int: " + normalNumber);
System.out.println("Long: " + veryBigNumber);

// Floating-point types
float preciseFloat = 3.14159f; // Note the 'f' suffix for float
double veryPreciseDouble = 3.14159265359;

System.out.println("Float: " + preciseFloat);
System.out.println("Double: " + veryPreciseDouble);

// Character type
char initial = 'J'; // Single quotes for a single character
System.out.println("Initial: " + initial);

// Boolean type
boolean isJavaFun = true;
boolean isCoffeeCold = false;
System.out.println("Is Java fun? " + isJavaFun);
System.out.println("Is coffee cold? " + isCoffeeCold);

Explanation:

  • We’ve declared and initialized variables for each of the main primitive types.
  • Notice the L suffix for long and f suffix for float. Without these, Java would treat 123... as an int (potentially causing an overflow if too large) and 3.14 as a double by default.
  • The underscores in 1_000_000 are purely for human readability and were introduced in JDK 7. Java ignores them.
  • char uses single quotes, boolean uses the keywords true or false.

For more details on primitive data types, you can always refer to the official Oracle documentation: Primitive Data Types (JDK 25)

2.2.2 Reference Data Types: An Introduction to String

While primitive types store simple values directly, reference types (also called object types) store references to objects. Think of a reference as an address to a house, rather than the house itself. The most common reference type you’ll encounter immediately is String.

A String is used to store sequences of characters (text). Unlike char which holds a single character, String can hold words, sentences, or even entire documents.

// Add this to your main method

// --- Reference Data Type: String ---
String greeting = "Hello, Java learners!"; // Double quotes for String literals
String programmingLanguage = "Java";
String message = greeting + " Welcome to " + programmingLanguage + "!";

System.out.println(message);

Explanation:

  • String greeting = "Hello, Java learners!";: We declare a variable greeting of type String and assign it a text value. Notice String starts with a capital S – this is a strong hint that it’s a class (an object type), not a primitive.
  • String message = greeting + " Welcome to " + programmingLanguage + "!";: We’re concatenating multiple strings and variables together using the + operator to form a new String. This is a powerful and common operation.

Compile and run your code again! You’ll see all your variable values printed.


2.3 Operators: Performing Actions on Data

Now that we know how to store data, how do we do things with it? That’s the job of operators! Operators are special symbols that tell the compiler to perform specific mathematical, relational, or logical operations and produce a result.

2.3.1 Arithmetic Operators

These are the ones you remember from math class!

  • + (Addition)
  • - (Subtraction)
  • * (Multiplication)
  • / (Division)
  • % (Modulo - returns the remainder of a division)
// Add this to your main method

// --- Arithmetic Operators ---
int num1 = 10;
int num2 = 3;

int sum = num1 + num2;
int difference = num1 - num2;
int product = num1 * num2;
int quotient = num1 / num2; // Watch out for integer division!
int remainder = num1 % num2;

System.out.println("\n--- Arithmetic Operations ---");
System.out.println("Sum: " + sum);          // Expected: 13
System.out.println("Difference: " + difference); // Expected: 7
System.out.println("Product: " + product);    // Expected: 30
System.out.println("Quotient (int): " + quotient); // Expected: 3 (not 3.33! Why? See Pitfalls!)
System.out.println("Remainder: " + remainder); // Expected: 1 (10 divided by 3 is 3 with 1 left over)

// Using double for accurate division
double dNum1 = 10.0;
double dNum2 = 3.0;
double preciseQuotient = dNum1 / dNum2;
System.out.println("Quotient (double): " + preciseQuotient); // Expected: 3.333...

Explanation:

  • Most of these are straightforward.
  • Integer Division: When you divide two int types, Java performs integer division, meaning it truncates (chops off) any decimal part, resulting in an int. 10 / 3 gives 3, not 3.33. To get a precise decimal result, at least one of the operands must be a double or float.
  • Modulo (%): This is super useful for checking if a number is even/odd (if num % 2 == 0, it’s even) or for tasks like cycling through a fixed number of items.

2.3.2 Assignment Operators

You’ve already met the basic assignment operator =. But Java offers shorthand operators that combine an arithmetic operation with assignment:

  • = (Assign)
  • += (Add and assign: x += y is same as x = x + y)
  • -= (Subtract and assign: x -= y is same as x = x - y)
  • *= (Multiply and assign: x *= y is same as x = x * y)
  • /= (Divide and assign: x /= y is same as x = x / y)
  • %= (Modulo and assign: x %= y is same as x = x % y)
// Add this to your main method

// --- Assignment Operators ---
int score = 100;
System.out.println("\n--- Assignment Operations ---");
System.out.println("Initial score: " + score);

score += 50; // score = score + 50;
System.out.println("Score after += 50: " + score); // Expected: 150

score -= 20; // score = score - 20;
System.out.println("Score after -= 20: " + score); // Expected: 130

score *= 2; // score = score * 2;
System.out.println("Score after *= 2: " + score);  // Expected: 260

score /= 10; // score = score / 10;
System.out.println("Score after /= 10: " + score); // Expected: 26

2.3.3 Increment and Decrement Operators

These are special unary operators (they operate on a single operand) that add or subtract 1 from a variable. They’re very common in loops (which we’ll cover soon!).

  • ++ (Increment by 1)
  • -- (Decrement by 1)

These have two forms:

  • Prefix: ++x or --x (increments/decrements then uses the value)
  • Postfix: x++ or x-- (uses the value then increments/decrements)
// Add this to your main method

// --- Increment/Decrement Operators ---
int counter = 5;
System.out.println("\n--- Increment/Decrement Operations ---");
System.out.println("Initial counter: " + counter); // Expected: 5

counter++; // Postfix increment: uses 5, then becomes 6
System.out.println("Counter after postfix increment: " + counter); // Expected: 6

++counter; // Prefix increment: becomes 7, then uses 7
System.out.println("Counter after prefix increment: " + counter); // Expected: 7

int result1 = counter++; // result1 gets 7, then counter becomes 8
System.out.println("Result1 (postfix): " + result1 + ", Counter: " + counter); // Expected: Result1: 7, Counter: 8

int result2 = ++counter; // counter becomes 9, then result2 gets 9
System.out.println("Result2 (prefix): " + result2 + ", Counter: " + counter); // Expected: Result2: 9, Counter: 9

Explanation:

  • The difference between prefix and postfix matters when the operator is part of a larger expression. If it’s just counter++; or ++counter; on its own line, the effect on counter is the same (it increases by 1).

2.3.4 Comparison (Relational) Operators

These operators compare two values and return a boolean (either true or false). They are fundamental for making decisions in your code.

  • == (Equal to) - CRITICAL: This is two equals signs!
  • != (Not equal to)
  • > (Greater than)
  • < (Less than)
  • >= (Greater than or equal to)
  • <= (Less than or equal to)
// Add this to your main method

// --- Comparison Operators ---
int a = 10;
int b = 20;
int c = 10;

System.out.println("\n--- Comparison Operations ---");
System.out.println("a == b: " + (a == b)); // Expected: false
System.out.println("a == c: " + (a == c)); // Expected: true
System.out.println("a != b: " + (a != b)); // Expected: true
System.out.println("a > b: " + (a > b));   // Expected: false
System.out.println("a < b: " + (a < b));   // Expected: true
System.out.println("a >= c: " + (a >= c)); // Expected: true
System.out.println("b <= c: " + (b <= c)); // Expected: false

Explanation:

  • Notice the parentheses around (a == b) etc. This ensures the comparison happens before string concatenation, otherwise, you might get unexpected results or compilation errors in complex scenarios. It’s good practice.
  • CRITICAL PITFALL: Remember == for comparison, not =! = is for assignment. This is a very common beginner mistake.

2.3.5 Logical Operators

These combine boolean expressions to create more complex conditions.

  • && (Logical AND): Returns true if both operands are true.
  • || (Logical OR): Returns true if at least one operand is true.
  • ! (Logical NOT): Inverts the boolean value (flips true to false, and false to true).
// Add this to your main method

// --- Logical Operators ---
boolean isRaining = true;
boolean hasUmbrella = false;
boolean isSunny = false;

System.out.println("\n--- Logical Operations ---");
System.out.println("isRaining && hasUmbrella: " + (isRaining && hasUmbrella)); // Expected: false (both not true)
System.out.println("isRaining || hasUmbrella: " + (isRaining || hasUmbrella)); // Expected: true (at least one is true)
System.out.println("!isSunny: " + (!isSunny)); // Expected: true (NOT false is true)

// Combining with comparison operators
int age = 25;
boolean isAdult = (age >= 18);
boolean isSenior = (age >= 65);

System.out.println("Is adult: " + isAdult); // Expected: true
System.out.println("Is adult AND not senior: " + (isAdult && !isSenior)); // Expected: true (25 is >=18 and NOT >=65)

Explanation:

  • Logical operators are crucial for conditional statements (like if statements, coming next chapter!) where you need to check multiple conditions simultaneously.

For a comprehensive list of Java operators and their precedence, consult the official documentation: Operators (JDK 25)


Mini-Challenge: The Simple Calculator!

Alright, time to put your new knowledge to the test!

Challenge: Create a small Java program (you can call it Calculator.java) that performs a few basic calculations.

  1. Declare two int variables, operand1 and operand2, and assign them any whole numbers you like.
  2. Declare a double variable, taxRate, and assign it a decimal value (e.g., 0.05 for 5%).
  3. Calculate and print the sum, difference, product, and remainder of operand1 and operand2. Make sure the output is clear (e.g., “Sum: 15”).
  4. Calculate the quotient of operand1 divided by operand2, ensuring the result is a precise decimal. Store it in a double variable and print it.
  5. Imagine operand1 is a price. Calculate the finalPrice after applying the taxRate. Print this finalPrice.
  6. Increment operand1 by 1 using the ++ operator and print its new value.
  7. Check if operand1 is now greater than operand2. Print the boolean result clearly.

Hint:

  • Remember how to get precise division with int variables. You might need to temporarily convert one of them to a double during the calculation! (This is called type casting, we’ll cover it more formally later, but for now, you can do (double)operand1 / operand2).

What to Observe/Learn:

  • How to declare and initialize different data types.
  • The behavior of various arithmetic operators.
  • The difference between integer and floating-point division.
  • How to use variables in calculations and print formatted output.
Click for Solution (but try it yourself first!)
// Calculator.java
public class Calculator {
    public static void main(String[] args) {
        System.out.println("--- Simple Calculator Challenge ---");

        // 1. Declare two int variables
        int operand1 = 25;
        int operand2 = 7;

        // 2. Declare a double variable for taxRate
        double taxRate = 0.08; // 8% tax

        System.out.println("Operand 1: " + operand1);
        System.out.println("Operand 2: " + operand2);
        System.out.println("Tax Rate: " + taxRate);

        // 3. Calculate and print sum, difference, product, remainder
        int sum = operand1 + operand2;
        int difference = operand1 - operand2;
        int product = operand1 * operand2;
        int remainder = operand1 % operand2;

        System.out.println("Sum: " + sum);
        System.out.println("Difference: " + difference);
        System.out.println("Product: " + product);
        System.out.println("Remainder: " + remainder);

        // 4. Calculate precise quotient
        // We cast operand1 to a double to ensure floating-point division
        double preciseQuotient = (double) operand1 / operand2;
        System.out.println("Precise Quotient: " + preciseQuotient);

        // 5. Calculate final price with tax
        double price = operand1; // Let's use operand1 as the base price for this
        double taxAmount = price * taxRate;
        double finalPrice = price + taxAmount;
        System.out.println("Original Price: " + price);
        System.out.println("Tax Amount: " + taxAmount);
        System.out.println("Final Price (with tax): " + finalPrice);

        // 6. Increment operand1 and print
        operand1++;
        System.out.println("Operand 1 after increment: " + operand1);

        // 7. Check if operand1 is greater than operand2
        boolean isGreater = (operand1 > operand2);
        System.out.println("Is Operand 1 greater than Operand 2 now? " + isGreater);
    }
}

Common Pitfalls & Troubleshooting

Even experienced programmers make mistakes, especially with these fundamental building blocks. Here are a few common ones to watch out for:

  1. Type Mismatch Errors:

    • Mistake: Trying to assign a value of one type to a variable of an incompatible type (e.g., int myNum = "hello"; or boolean flag = 1;).
    • Troubleshooting: The compiler will usually catch this with a clear error message like “incompatible types: String cannot be converted to int”. Read the error carefully! Ensure the value you’re assigning matches the declared type of the variable.
    • Example:
      // int wrongType = "Java"; // Compiler Error! String to int
      // boolean anotherWrong = 0; // Compiler Error! int to boolean
      
  2. Integer Division Issues:

    • Mistake: Expecting a decimal result when dividing two integers. 10 / 4 will be 2, not 2.5.
    • Troubleshooting: If you need a decimal result, make sure at least one of the operands is a double or float. You can achieve this by declaring the variables as double from the start, or by casting one of them: (double)num1 / num2.
    • Example:
      int totalItems = 10;
      int numPeople = 3;
      double itemsPerPerson = totalItems / numPeople; // This will be 3.0, not 3.33!
      // Correct way:
      double correctItemsPerPerson = (double) totalItems / numPeople; // This will be 3.33...
      
  3. Confusing = (Assignment) with == (Comparison):

    • Mistake: Accidentally typing if (x = 5) instead of if (x == 5). The first one assigns 5 to x and then tries to evaluate the result of the assignment as a boolean (which is usually a compile error in Java for primitives, but can lead to subtle bugs in other contexts). The second one compares x to 5.
    • Troubleshooting: Pay close attention when writing conditional statements. The compiler will often flag if (x = 5) as “incompatible types: int cannot be converted to boolean” because the assignment x = 5 results in an int, not a boolean.
    • Example:
      int myValue = 10;
      // if (myValue = 10) { // Compiler Error: Required type boolean, Provided int
      //     System.out.println("Value is 10");
      // }
      if (myValue == 10) { // Correct comparison
          System.out.println("Value is 10");
      }
      

Summary

Phew! You’ve covered a lot of ground in this chapter. Let’s quickly recap the key takeaways:

  • Variables are named containers in memory used to store data.
  • You must declare a variable with a specific data type and initialize it with a value before using it.
  • Use final to declare constants, values that cannot change after initialization (conventionally ALL_CAPS).
  • Java has primitive data types for basic values (int, double, boolean, char, etc.) and reference data types for objects (String being our first example).
  • Operators allow you to perform actions on variables and values:
    • Arithmetic: +, -, *, /, %
    • Assignment: =, +=, -=, etc.
    • Increment/Decrement: ++, -- (watch out for prefix vs. postfix in expressions!)
    • Comparison: ==, !=, >, <, >=, <= (return boolean values)
    • Logical: &&, ||, ! (combine boolean expressions)
  • Be mindful of integer division and the crucial difference between = (assignment) and == (comparison).

You’re building a strong foundation! With variables, data types, and operators, you can now store information, perform calculations, and prepare to make decisions in your programs.

In the next chapter, we’ll take these building blocks and learn how to make your programs make decisions and repeat actions using control flow statements like if/else and loops. Get ready to add some real intelligence to your Java applications!