Variables, Data Types & Operators in Java

Series: Java Core for Beginners Lecture: 02 of 12 Topics: Primitive types · Reference types · Variables · Type casting · Operators · Strings


What Is a Variable?

A variable is a named container for storing a value in memory. When you write a program, you constantly need to hold pieces of information — a user’s age, a product price, whether a door is open or closed — and variables are how you do that.

In Java, every variable has three things:

  • A type — what kind of data it holds (a whole number, a decimal, a true/false value, etc.)
  • A name — how you refer to it in your code
  • A value — the actual data stored inside it

Java is a statically typed language. This means you must declare the type of a variable when you create it, and that type cannot change for the lifetime of the variable. This is different from dynamically typed languages like Python or JavaScript, where a variable can hold any type of value at any time.

Static typing has a significant advantage: the compiler catches type mismatches before your program runs. If you declare a variable as an integer and accidentally try to store a name string in it, Java refuses to compile — you learn about the mistake immediately rather than discovering it as a bug in production.


Primitive Data Types

Java has eight primitive data types. These are the most basic building blocks — they hold simple values directly in memory and are not objects. Knowing these eight types and their characteristics is foundational to everything else in Java.

Integer types

These types store whole numbers (no decimal point).

Type Size Range Default value
byte 8 bits −128 to 127 0
short 16 bits −32,768 to 32,767 0
int 32 bits −2,147,483,648 to 2,147,483,647 0
long 64 bits −9.2 × 10¹⁸ to 9.2 × 10¹⁸ 0L

int is your default choice for whole numbers. You reach for long only when a number might exceed roughly 2.1 billion — think timestamps in milliseconds, large financial calculations, or population counts.

int age = 25;
int temperature = -10;
long worldPopulation = 8_100_000_000L;   // L suffix marks a long literal

Notice the underscore in 8_100_000_000L. Java allows underscores inside numeric literals to improve readability. The compiler ignores them — they are purely visual separators, like commas in a written number.

byte and short are rarely used directly in application code. They exist mainly to save memory when working with large arrays or binary data.

Floating-point types

These types store numbers with a decimal component.

Type Size Precision Default value
float 32 bits ~7 significant digits 0.0f
double 64 bits ~15 significant digits 0.0

double is your default choice for decimal numbers. It provides sufficient precision for most applications and is what Java’s math library methods return by default.

double price = 19.99;
double pi = 3.141592653589793;
float discount = 0.15f;   // f suffix marks a float literal

Important: float and double use binary floating-point representation, which cannot represent all decimal fractions exactly. For example, 0.1 + 0.2 in floating-point does not equal exactly 0.3. This is not a Java quirk — it is a property of how IEEE 754 floating-point arithmetic works in virtually every programming language. For financial calculations where exact decimal precision is required, use java.math.BigDecimal instead.

System.out.println(0.1 + 0.2);   // prints 0.30000000000000004

The boolean type

boolean stores one of two values: true or false. It is the foundation of all conditional logic in Java.

boolean isLoggedIn = true;
boolean hasPermission = false;

boolean in Java is not numeric — unlike C, you cannot use 1 or 0 in place of true or false. A boolean is only ever true or false.

The char type

char stores a single Unicode character, enclosed in single quotes.

char grade = 'A';
char symbol = '@';
char newline = '\n';   // escape sequence for a newline character

Under the hood, char is a 16-bit unsigned integer representing a Unicode code point (range 0 to 65,535). This means you can do arithmetic with characters, though it is rarely necessary:

char c = 'A';
System.out.println(c + 1);   // prints 66 (the int value of 'B')

Common escape sequences for char and String

Sequence Meaning
\n Newline
\t Tab
\\ Literal backslash
\" Literal double quote (inside a String)
\' Literal single quote (inside a char)

Primitive types summary

Whole numbers:     byte → short → int → long        (increasing size)
Decimal numbers:   float → double                    (increasing precision)
True/false:        boolean
Single character:  char

When in doubt: use int for whole numbers, double for decimals, boolean for flags, and char when you genuinely need a single character (though String is more common in practice).


Reference Types — A First Look

Beyond the eight primitives, everything else in Java is a reference type. Where a primitive variable holds its value directly, a reference variable holds a pointer — a memory address pointing to where an object lives on the heap.

You will study reference types in depth starting in Lecture 4 (Classes & Objects). For now, there are two you will encounter immediately.

String

String is the most commonly used reference type in Java. It represents a sequence of characters — text. String literals are enclosed in double quotes:

String name = "Alice";
String greeting = "Hello, World!";
String empty = "";

String is a class, not a primitive, but Java gives it special treatment. You can create string literals with double quotes without using the new keyword, and the + operator is overloaded to concatenate strings.

Arrays

An array is a fixed-size, ordered collection of values of the same type:

int[] scores = {95, 87, 72, 100, 88};
String[] days = {"Monday", "Tuesday", "Wednesday"};

You will cover arrays in full in Lecture 7. For now, know that they are reference types and that square brackets [] denote an array type.

null

Reference variables can hold a special value called null, meaning they point to nothing — no object has been assigned yet:

String message = null;   // message points to nothing

Attempting to call a method on a null reference causes a NullPointerException at runtime — one of the most common errors in Java. You will learn strategies to avoid this in Lectures 10 and 12.


Variable Declaration and Initialization

Declaration

Declaring a variable reserves a named slot in memory for a value of a given type:

int score;
double salary;
boolean isActive;

At this point, the variables exist but have no assigned value. Attempting to use an uninitialized local variable before assigning it is a compile-time error in Java:

int count;
System.out.println(count);   // ERROR: variable count might not have been initialized

Initialization

Initializing a variable assigns it its first value:

int score;       // declaration
score = 100;     // initialization

Declaration and initialization together

In practice, you almost always declare and initialize in a single statement:

int score = 100;
double salary = 55000.0;
boolean isActive = true;
char grade = 'B';
String name = "Alice";

The var keyword (Java 10+)

Since Java 10, you can use var instead of an explicit type when the compiler can infer the type from the assigned value. This is called local variable type inference:

var age = 30;           // inferred as int
var name = "Alice";     // inferred as String
var price = 9.99;       // inferred as double

var is purely a convenience — the type is still fixed at compile time. You cannot later assign a value of a different type. Also, var can only be used for local variables (inside methods) — not for fields, method parameters, or return types.

Use var when the type is obvious from context and repeating it would add noise. Avoid it when the type is not immediately clear from reading the right-hand side.

Naming rules and conventions

Java variable names must follow these rules:

  • Must start with a letter, underscore (_), or dollar sign ($) — not a digit
  • Can contain letters, digits, underscores, and dollar signs
  • Cannot be a Java reserved keyword (int, class, return, etc.)
  • Case-sensitive: count and Count are different variables

By convention, use camelCase for variable names and make them descriptive:

// Poor names
int x = 25;
double d = 19.99;

// Good names
int customerAge = 25;
double productPrice = 19.99;

Constants with final

Adding the final keyword to a variable declaration makes it a constant — its value can be assigned once and cannot change afterward:

final double TAX_RATE = 0.08;
final int MAX_ATTEMPTS = 3;

TAX_RATE = 0.09;   // ERROR: cannot assign a value to final variable TAX_RATE

By convention, constants are named in UPPER_SNAKE_CASE. Use final generously — it communicates intent (this value should not change) and can enable compiler optimizations.


Type Casting

Because Java is statically typed, you sometimes need to explicitly convert a value from one type to another. This is called casting.

Widening conversion (implicit)

A widening conversion moves a value to a larger type — no data is lost, so Java does it automatically:

int count = 42;
long bigCount = count;       // int → long: automatic
double d = count;            // int → double: automatic

float f = 3.14f;
double d2 = f;               // float → double: automatic

The widening order for numeric types is:

byte → short → int → long → float → double

Any conversion that follows this left-to-right order is implicit.

Narrowing conversion (explicit cast)

A narrowing conversion moves a value to a smaller type. Data loss is possible, so Java requires you to write an explicit cast — a type name in parentheses:

double price = 9.99;
int truncated = (int) price;    // explicit cast: double → int
System.out.println(truncated);  // prints 9 (decimal part is discarded, NOT rounded)

long bigNumber = 1_000_000_000_000L;
int smallNumber = (int) bigNumber;  // WARNING: data loss — value wraps around
System.out.println(smallNumber);    // prints 727379968 (overflow)

The cast operator (int) tells the compiler: “I know this conversion might lose data — do it anyway.” This is your explicit acknowledgment of the risk.

Casting with char

char can be cast to and from int because it is stored as a numeric Unicode code point:

char letter = 'A';
int code = letter;              // widening: char → int, prints 65
char back = (char) (code + 1); // narrowing: int → char, back = 'B'
System.out.println(back);       // prints B

String conversion

Converting other types to String is done with String.valueOf() or by concatenating with an empty string:

int n = 42;
String s1 = String.valueOf(n);    // "42"
String s2 = "" + n;               // "42" — concatenation converts n to String

// Parsing a String to a numeric type
String input = "123";
int parsed = Integer.parseInt(input);    // 123
double d = Double.parseDouble("3.14");   // 3.14

Operators

An operator is a symbol that tells Java to perform an operation on one or more values (called operands).

Arithmetic operators

Operator Name Example Result
+ Addition 5 + 3 8
- Subtraction 5 - 3 2
* Multiplication 5 * 3 15
/ Division 5 / 2 2
% Modulus (remainder) 5 % 2 1

Integer division truncates. When both operands are integers, / performs integer division and discards the remainder:

int result = 7 / 2;        // 3, not 3.5
double result2 = 7.0 / 2;  // 3.5 — one operand is double, so result is double
double result3 = (double) 7 / 2;  // 3.5 — cast one operand to force double division

The modulus operator returns the remainder after division. It is extremely useful:

int remainder = 10 % 3;    // 1 (10 = 3×3 + 1)

// Common use: check if a number is even
boolean isEven = (number % 2 == 0);

// Common use: wrap around a range (e.g., clock hours)
int hour = (currentHour + 1) % 24;

Assignment operators

Operator Equivalent to Example
= x = 5
+= x = x + n x += 3
-= x = x - n x -= 3
*= x = x * n x *= 2
/= x = x / n x /= 2
%= x = x % n x %= 3
int score = 100;
score += 10;    // score is now 110
score -= 5;     // score is now 105
score *= 2;     // score is now 210

Increment and decrement operators

These add or subtract 1 from a variable:

Operator Name Meaning
++x Pre-increment Increment, then return new value
x++ Post-increment Return current value, then increment
--x Pre-decrement Decrement, then return new value
x-- Post-decrement Return current value, then decrement
int a = 5;
System.out.println(++a);   // prints 6, a is now 6
System.out.println(a++);   // prints 6, a is now 7
System.out.println(a);     // prints 7

The pre/post distinction matters when the expression is used inside another expression. When the ++ appears as a standalone statement, both forms are equivalent:

count++;    // same as ++count when used alone

Relational (comparison) operators

These operators compare two values and return a boolean result.

Operator Meaning Example Result
== Equal to 5 == 5 true
!= Not equal to 5 != 3 true
> Greater than 5 > 3 true
< Less than 5 < 3 false
>= Greater than or equal 5 >= 5 true
<= Less than or equal 4 <= 3 false

Critical warning: == vs =

= is assignment. == is comparison. Mixing them up is one of the most common beginner bugs:

int x = 5;
if (x = 10) { }   // COMPILE ERROR in Java (fortunately)
if (x == 10) { }  // correct: checks whether x equals 10

== compares references for objects, not content. For String and other reference types, == checks whether two variables point to the same object in memory, not whether their contents are equal. Use the .equals() method to compare content:

String a = new String("hello");
String b = new String("hello");

System.out.println(a == b);        // false — different objects in memory
System.out.println(a.equals(b));   // true — same content

Logical operators

Logical operators combine boolean values or expressions.

Operator Name Meaning
&& Logical AND true only if both operands are true
`\ \ ` Logical OR true if at least one operand is true
! Logical NOT Inverts the boolean value
int age = 20;
boolean hasTicket = true;

boolean canEnter = (age >= 18) && hasTicket;   // true
boolean needsHelp = (age < 13) || (age > 65);  // false
boolean isDenied = !canEnter;                   // false

Short-circuit evaluation. && and || are short-circuit operators:

  • In A && B: if A is false, Java does not evaluate B at all — the result is already false
  • In A || B: if A is true, Java does not evaluate B at all — the result is already true

This is not just an optimization — it is a common pattern for safe code:

// Safe: if list is null, the second condition is never evaluated
if (list != null && list.size() > 0) {
    // ...
}

Operator precedence

When multiple operators appear in an expression, Java applies them in a defined order (similar to PEMDAS/BODMAS in arithmetic):

Highest precedence
  1. Unary:          ++, --, !, (cast)
  2. Multiplicative: *, /, %
  3. Additive:       +, -
  4. Relational:     <, >, <=, >=
  5. Equality:       ==, !=
  6. Logical AND:    &&
  7. Logical OR:     ||
  8. Assignment:     =, +=, -=, ...
Lowest precedence

When in doubt, use parentheses to make the intended order explicit:

int result = 2 + 3 * 4;          // 14 (not 20) — multiplication first
int result2 = (2 + 3) * 4;       // 20 — parentheses override precedence
boolean check = a > 0 && b < 10; // reads clearly already

String Basics

String deserves its own section because it is the type you will use in virtually every Java program you write.

Creating strings

String s1 = "Hello";                 // string literal (most common)
String s2 = new String("Hello");     // explicit object creation (rarely needed)

Prefer string literals. Java maintains a string pool — a cache of string literals. When you write "Hello" in two places, Java reuses the same object from the pool rather than creating two separate objects.

String concatenation with +

The + operator concatenates strings. When one operand is a String, Java automatically converts the other operand to a String:

String firstName = "Alice";
int age = 30;
String message = "Name: " + firstName + ", Age: " + age;
System.out.println(message);
// prints: Name: Alice, Age: 30

Watch out for unexpected addition vs concatenation:

System.out.println("Sum: " + 1 + 2);    // prints "Sum: 12" (concatenation left-to-right)
System.out.println("Sum: " + (1 + 2));  // prints "Sum: 3" (parentheses force addition first)

String immutability

String objects in Java are immutable — once created, their content cannot change. Methods that appear to modify a string actually return a new String object:

String original = "hello";
String upper = original.toUpperCase();

System.out.println(original);  // "hello" — unchanged
System.out.println(upper);     // "HELLO" — a new String object

This has a performance implication: building a string by concatenating many pieces inside a loop creates many temporary String objects. For such cases, use StringBuilder (covered in Lecture 7).

Essential String methods

String s = "  Hello, World!  ";

s.length()                    // 18 — number of characters (including spaces)
s.trim()                      // "Hello, World!" — removes leading/trailing whitespace
s.toLowerCase()               // "  hello, world!  "
s.toUpperCase()               // "  HELLO, WORLD!  "
s.contains("World")           // true
s.startsWith("  Hello")       // true
s.endsWith("!  ")             // true
s.replace("World", "Java")    // "  Hello, Java!  "
s.indexOf("o")                // 5 — index of first occurrence (-1 if not found)
s.substring(2, 7)             // "Hello" — characters from index 2 up to (not including) 7
s.charAt(2)                   // 'H' — character at index 2
s.isEmpty()                   // false
s.trim().isEmpty()            // false
"".isEmpty()                  // true

Checking string equality

Always use .equals(), never ==, to compare string content:

String input = "admin";
if (input.equals("admin")) {
    System.out.println("Access granted");
}

// Defensive style: put the known string first to avoid NullPointerException
if ("admin".equals(input)) {
    System.out.println("Access granted");
}

// Case-insensitive comparison
if (input.equalsIgnoreCase("ADMIN")) {
    System.out.println("Access granted");
}

String.format() and text blocks

For more readable string construction, use String.format():

String name = "Alice";
int age = 30;
double gpa = 3.85;

String report = String.format("Student: %s | Age: %d | GPA: %.2f", name, age, gpa);
System.out.println(report);
// prints: Student: Alice | Age: 30 | GPA: 3.85

Common format specifiers: %s (String), %d (integer), %f (floating-point), %.2f (floating-point with 2 decimal places).

Since Java 15, text blocks allow multiline strings without concatenation or escape characters:

String json = """
        {
            "name": "Alice",
            "age": 30
        }
        """;

The leading whitespace is stripped relative to the closing """. Text blocks are extremely useful for embedding SQL, JSON, HTML, or any multiline content in your code.


Summary

This lecture covered the raw materials that every Java program is built from.

  • Java has eight primitive types: byte, short, int, long, float, double, boolean, and char. Default choices are int for whole numbers and double for decimals.
  • Reference types like String hold a memory address pointing to an object, not the value itself. null means no object is assigned.
  • Variables must be declared with a type and initialized before use. The final keyword makes a variable a constant. var allows type inference for local variables (Java 10+).
  • Widening conversions (small → large type) happen automatically. Narrowing conversions (large → small) require an explicit cast and may lose data.
  • Java provides arithmetic, assignment, relational, and logical operators. Short-circuit evaluation applies to && and ||.
  • String is immutable. Use .equals() (not ==) to compare content. String.format() and text blocks provide clean alternatives to concatenation.

Exercises

Exercise 1 — Declare and print Declare one variable of each primitive type, assign meaningful values, and print each one with a label. For example: "Age: 25", "Price: 9.99", "Passed: true".

Exercise 2 — Integer division trap Write a program that calculates the average of three test scores: 85, 90, and 78. First use integer division and print the result. Then fix it to produce the correct decimal result. Explain in a comment why the first version gives the wrong answer.

Exercise 3 — Operator precedence Without running the code, predict the output of each line. Then verify by running them:

System.out.println(10 + 5 * 2);
System.out.println((10 + 5) * 2);
System.out.println(10 / 3);
System.out.println(10 % 3);
System.out.println(10 / 3.0);
System.out.println(true && false || true);
System.out.println(true && (false || true));

Exercise 4 — Type casting Declare a double variable with the value 9.99. Cast it to int and print both values. Then declare a char variable 'Z' and print its numeric value. Finally, add 1 to it and print the resulting character.

Exercise 5 — String manipulation Write a program that:

  • Stores the string " java programming " in a variable
  • Trims the whitespace and converts it to title case (first letter of each word uppercase — hint: you can use substring and toUpperCase together)
  • Checks whether the trimmed string contains the word "java" (case-insensitive)
  • Prints the length of the trimmed string
  • Replaces "java" with "Java" and prints the result

Exercise 6 — Short-circuit evaluation Run the following code and explain in a comment why it does not throw a NullPointerException:

String s = null;
if (s != null && s.length() > 0) {
    System.out.println("Not empty");
} else {
    System.out.println("Null or empty");
}

Up next: Lecture 3 — Control Flow — where you will learn how to make decisions with if/else and switch, repeat actions with loops, and control execution with break and continue.

Leave a Reply

Your email address will not be published. Required fields are marked *