Phase 1 · BeginnerModule 2~40 min read

Variables, Data Types & Operators

Store and manipulate data with primitives, literals, type conversion, and every operator Java offers.

What you'll learn

Every program is really just data being stored, changed, and combined. In this module you'll learn how Java holds data in variables, the exact types that data can take, and the operators you use to calculate and compare.

By the end you'll be able to:

  • Declare, initialize, and reassign variables — and lock values with final
  • Choose the right primitive type for any value
  • Use literals, underscores in numbers, and var type inference
  • Convert between types safely with widening and narrowing casts
  • Apply arithmetic, comparison, logical, and bitwise operators correctly
  • Predict results using operator precedence, and use the Math class

Note

You'll get the most out of this module by running each example and tweaking the numbers. Watching a value change is the fastest way to build intuition.

Variables & constants

A variable is a named box in memory that holds a value. In Java every variable has a fixed type that never changes — this is what makes Java a statically typed language. You declare a variable by writing its type and name, and initialize it by giving it a value.

Variables.java
int age = 25;          // declare + initialize
double price = 19.99;
char grade = 'A';
boolean isJavaFun = true;

age = 26;              // reassign later
final int MAX = 100;   // constant — cannot change

System.out.println(age);
System.out.println(grade + " costs " + price);

A variable's value can change over time (that's why it's "variable"). When you want a value that must never change, mark it final — that makes it a constant. Constants are written in UPPER_SNAKE_CASE by convention.

Tip

Declare variables as close as possible to where you first use them, and give them names that describe their meaning (totalPrice), not their type (doubleValue).

Primitive data types

Java has 8 primitive types — the built-in building blocks for raw values. They fall into four natural groups:

The 8 primitives

Whole numbers

byteshortintlong

No decimals. int is the everyday default.

Decimal numbers

floatdouble

Fractions. double is the default.

Single character

char

One Unicode character, in single quotes.

True / false

boolean

Only true or false.

Each type reserves a fixed amount of memory, which decides the range of values it can hold:

TypeSizeHoldsExample
byte8-bit-128 to 127byte b = 100;
short16-bit-32,768 to 32,767short s = 20000;
int32-bit~ ±2.1 billion (the default)int i = 42;
long64-bitvery large whole numberslong n = 9000000000L;
float32-bitdecimals (less precise)float f = 3.14f;
double64-bitdecimals (the default)double d = 3.14;
char16-bitone Unicode characterchar c = 'A';
boolean1-bit*true or falseboolean ok = true;
* boolean size is JVM-dependent. int and double are the everyday defaults for numbers.
Primitives.java
byte  small = 100;
short medium = 20_000;
int   count = 2_000_000;
long  huge = 9_000_000_000L;   // note the L

float  ratio = 3.14f;          // note the f
double precise = 3.141592653589793;

char   letter = 'J';
boolean active = false;

System.out.println(count + " / " + huge);
System.out.println(ratio + " / " + precise);

Watch the suffixes

A whole-number literal is an int by default, so a long literal larger than int's range needs an L. A decimal literal is a double by default, so a float needs an f.

Literals, underscores & var

A literal is a fixed value written directly in code — 42, 3.14, 'A', true, "hello". To make large numbers readable you can add underscores as digit separators (the compiler ignores them): 1_000_000.

Since Java 10, you can use var for local variables and let the compiler infer the type from the value on the right. The variable is still strongly typed — you just didn't have to write the type twice.

Inference.java
var message = "Hello";   // inferred as String
var count = 42;          // inferred as int
var pi = 3.14;           // inferred as double

System.out.println(message.getClass().getSimpleName());
System.out.println(count + pi);

Note

var only works when you initialize the variable immediately, and only for local variables (not fields or method parameters). Reach for it when the type is obvious from the value.

Type conversion & casting

Sometimes you need to move a value from one type to another. There are two directions, and Java treats them very differently.

The casting ladder
byte→short→int→long→float→double

Widening →

Small into big is automatic and safe. No data is lost.

← Narrowing

Big into small needs an explicit cast and may lose data.

Widening happens automatically; narrowing requires an explicit cast.

Widening (small type → bigger type) happens automatically because no information can be lost. Narrowing (big type → smaller type) must be requested with an explicit cast (type) — and it can lose data or overflow, so use it deliberately.

Casting.java
int i = 300;
byte b = (byte) i;        // narrowing: 300 doesn't fit in a byte
System.out.println(b);    // -> 44 (overflow wraps around)

double d = 9.99;
int truncated = (int) d;  // decimals are dropped, not rounded
System.out.println(truncated);  // -> 9

System.out.println(Integer.MAX_VALUE + 1);  // overflow

Overflow is silent

When a value exceeds a type's range it wraps around instead of erroring — MAX_VALUE + 1 becomes the most negative number. Pick a type big enough for your data, or use long.

Operators

Operators are the symbols that combine values. Arithmetic operators do the maths — but watch out for one classic trap:

OperatorMeaningExample → result
+Addition5 + 2 → 7
-Subtraction5 - 2 → 3
*Multiplication5 * 2 → 10
/Division5 / 2 → 2 (int!) · 5.0 / 2 → 2.5
%Modulo (remainder)5 % 2 → 1
Arithmetic.java
int a = 17, b = 5;

System.out.println(a + b);          // 22
System.out.println(a - b);          // 12
System.out.println(a * b);          // 85
System.out.println(a / b);          // 3  <- integer division!
System.out.println(a % b);          // 2  <- remainder
System.out.println((double) a / b); // 3.4

Integer division truncates

When both operands are integers, / throws away the remainder — 17 / 5 is 3, not 3.4. Make at least one side a double to get a decimal result.

Comparison operators ask a yes/no question and produce a boolean, while logical operators combine those booleans:

ComparisonMeaningLogicalMeaning
==equal to&&AND (both true)
!=not equal to||OR (either true)
>greater than!NOT (flips it)
>=greater or equal
<less than
<=less or equal
Logic.java
int age = 20;

boolean canVote = age >= 18;
boolean isTeen  = age >= 13 && age <= 19;

System.out.println(canVote);   // true
System.out.println(isTeen);    // false
System.out.println(!canVote);  // false

Short-circuiting

&& and || are lazy: if the left side already decides the answer, the right side isn't even evaluated. This is handy for guards like if (list != null && list.size() > 0).

Java also has bitwise and shift operators that work on the individual bits of integers — useful for flags, low-level code, and performance tricks:

OperatorMeaning
&Bitwise AND
|Bitwise OR
^Bitwise XOR
~Bitwise NOT (invert bits)
<<Left shift (× 2 each step)
>>Signed right shift (÷ 2 each step)
>>>Unsigned right shift

Operator precedence & associativity

When several operators appear together, precedence decides who goes first (just like maths: * before +). Here's the order from highest to lowest, simplified:

LevelOperatorsGroup
1() ++ --Parentheses, postfix
2! ~ (type)Unary, cast
3* / %Multiplicative
4+ -Additive
5< <= > >=Relational
6== !=Equality
7&& then ||Logical AND / OR
8= += -=Assignment
When in doubt, add parentheses — they make intent obvious and cost nothing.

Tip

Don't memorise the whole table. Just remember that * and / beat + and -, comparisons beat logic, and parentheses beat everything.

The Math class

For anything beyond the basic operators, Java's built-in Math class has you covered — powers, roots, rounding, trigonometry, and more. Its methods are static, so you call them straight on Math:

MathDemo.java
System.out.println(Math.max(10, 20));  // 20
System.out.println(Math.min(10, 20));  // 10
System.out.println(Math.abs(-7));      // 7
System.out.println(Math.pow(2, 10));   // 1024.0
System.out.println(Math.sqrt(144));    // 12.0
System.out.println(Math.round(3.6));   // 4

Note

Handy extras: Math.random() gives a random double from 0.0 up to (but not including) 1.0, and Math.PI is π. You'll use these constantly in real programs.

Recap & quick check

Key takeaways

  • A variable is a typed, named box for a value; final makes it a constant that can't change.
  • Java has 8 primitives — int and double are the everyday defaults for numbers.
  • Widening casts are automatic; narrowing casts are explicit and can overflow or lose data.
  • Integer division drops the remainder — cast to double for a decimal result.
  • Precedence decides evaluation order, but parentheses always win — use them for clarity.

Quick check

1. What is the result of the expression 7 / 2 in Java?

2. Which keyword makes a variable a constant that cannot be reassigned?

3. Converting a double to an int with (int) does what to the decimals?

4. What type does 'var total = 3.5;' infer?

5. Which operator gives the remainder of a division?

Great work — you can now store and manipulate data with confidence. Next up: Module 3 — Input, Output & Strings, where your programs start talking to the user and working with text.