A variable is a named place for a value. Its type tells the compiler which values fit and which operations make sense. In this Java 21 lesson, think about the data before choosing syntax: a count, a price and a person's name have different requirements even when each arrives as text.
Primitive values and references
Java has eight primitive types. byte, short, int and long hold signed integers of 8, 16, 32 and 64 bits. float and double hold approximate binary floating-point numbers. boolean holds true or false. char holds one UTF-16 code unit, which is not necessarily an entire Unicode character.
Usually start with int for bounded counts and long for larger totals. A long literal can use an L suffix. double suits measurements where approximation is acceptable. Avoid choosing a smaller type merely because today's sample values are small.
Reference types include strings, arrays and objects you define. A reference identifies an object or contains null, meaning no object. Assigning a reference copies that reference, not the object. Two variables can therefore reach the same mutable array. Calling a method through null throws NullPointerException.
Local variables must be assigned before use. Fields and array elements have defaults: numeric zero, false, or null, depending on their type. An empty string is a real object value and is different from null.
Trace a complete calculation
Save as TypesDemo.java, then run javac --release 21 TypesDemo.java and java TypesDemo.
import java.math.BigDecimal;
import java.math.RoundingMode;
public class TypesDemo {
public static void main(String[] args) {
int learners = 7;
int teams = 2;
double average = (double) learners / teams;
long population = 3_000_000_000L;
final int seats = 12;
var label = "Java workshop";
BigDecimal price = new BigDecimal("19.90");
BigDecimal total = price.multiply(BigDecimal.valueOf(3));
BigDecimal share = total.divide(
BigDecimal.valueOf(4), 2, RoundingMode.HALF_UP);
System.out.println(learners / teams);
System.out.println(average);
System.out.println(population > seats);
System.out.println(label + ": " + total.toPlainString());
System.out.println(share.toPlainString());
}
}
Expected output:
3
3.5
true
Java workshop: 59.70
14.93
Integer division discards the fractional part, truncating toward zero. Converting the result afterward is too late: (double) (learners / teams) is 3.0. Cast an operand before division to request floating-point arithmetic. Integer division by zero throws; floating-point arithmetic follows different rules and can produce infinity or NaN.
BigDecimal represents decimal values with an explicit scale. Constructing from a decimal string avoids importing the approximation of a binary double. Division sometimes needs a rounding policy because the exact result has no finite decimal representation. The example's two decimal places and HALF_UP are a deliberate policy, not a universal rule for money.
Inference, constants and conversions
var asks the compiler to infer a local variable's type from its initializer. Here label is still a String; it cannot later hold an integer. It is not a dynamic type, cannot infer a type from null alone, and is not available for fields or ordinary method parameters. Prefer an explicit type when it makes intent easier to see.
final prevents reassignment after initialization. A final reference to an array still permits changing that array's elements. It does not make the referenced object immutable.
Widening an int to long preserves the value. Narrowing a long to int with a cast can discard information. Even widening an integer to a floating-point type can lose precision. Ordinary integer arithmetic can overflow without an exception; use Math.addExact or Math.multiplyExact when exceeding the range must fail. Promote an operand before multiplication if the intermediate result needs a long.
Collections use wrapper types such as Integer rather than primitives. Boxing converts an int to an Integer; unboxing extracts its value. Unboxing a null wrapper throws. Compare wrapper values with equals, not reference identity using ==.
Exercise and solution guidance
Calculate the total cost of four tickets priced at 12.50, then divide equally among three people to two decimal places. Explain why the rounded shares might not sum to the exact total. Also compute 2_000_000_000 + 2_000_000_000 safely as a long.
Build the price from a string, multiply by four, then divide with a named rounding mode. The total is 50.00; three rounded 16.67 shares total 50.01, so an actual payment system needs a remainder allocation rule. For the integer calculation, make an operand a long before adding; assigning an already-overflowed int result to long cannot repair it.
Official references
Previous: Introduction. Next: Control Flow and Methods.

