Chapter 2: Java Prerequisites for DSA
2.01Beginner11 topics18 min

Java language essentials

The Java you need for every later lesson: primitive types, variables, operators and precedence, control flow, methods, scope, overloading, static members and access modifiers. Examples target Java 17.

Learning goals

  • Choose the right primitive type and know its range
  • Predict the value of an expression using precedence and integer division
  • Write methods with correct scope, overloads and access control

Prerequisites

Any programming experience
2.01.1

Primitive types

Java has eight primitive types. For algorithms you mostly use int (32-bit), long (64-bit), double, boolean and char. byte and short appear in memory-tight arrays.

Integer types are signed two's complement, so the negative range is one larger than the positive range.

TypeSizeRange / values
byte8 bits-128 to 127
short16 bits-32,768 to 32,767
int32 bits-2,147,483,648 to 2,147,483,647
long64 bits-9.22 × 10¹⁸ to 9.22 × 10¹⁸
float / double32 / 64 bitsIEEE 754 floating point
char16 bits0 to 65,535 (UTF-16 code unit)
booleanJVM-definedtrue or false
Java
1int max = Integer.MAX_VALUE; // 2147483647
2long big = 10_000_000_000L; // L suffix: the literal does not fit in an int
3double d = 3.5;
4char c = 'A'; // numeric value 65
5boolean ok = max > 0;
2.01.2

Variables

A variable has a type, a name and a value. Declare it close to first use, give it the narrowest scope, and mark values that never change with final. Since Java 10 var infers the type of a local variable from its initialiser.

Local variables have no default value and must be assigned before use; the compiler rejects reading them otherwise.

Java
1final int n = 5; // cannot be reassigned
2var list = new ArrayList<Integer>(); // inferred: ArrayList<Integer>
3int total; // declared, not yet assigned
4total = n * 2; // must happen before any read
2.01.3

Operators

Arithmetic (+ - * / %), comparison (== != < <= > >=), logical (&& || !, short-circuit), bitwise (& | ^ ~ << >> >>>), assignment (= += -= …), and the ternary cond ? a : b.

Integer division truncates toward zero, so 7 / 2 is 3 and -7 / 2 is -3. At least one operand must be floating point for a fractional result.

Java
1int a = 7 / 2; // 3
2double b = 7 / 2; // 3.0 (integer division first, then widened)
3double c = 7 / 2.0; // 3.5
4int r = 7 % 3; // 1
5boolean x = n > 0 && 10 / n > 1; // && stops early, so no division by zero when n == 0
2.01.4

Precedence

Higher precedence binds first: unary, then * / %, then + -, then shifts, then relational, then ==, then &, ^, |, then &&, ||, ternary, assignment.

The trap: == binds tighter than &, so x & 1 == 0 means x & (1 == 0) and does not compile for ints. Write (x & 1) == 0. When in doubt, add parentheses.

Java
1int v = 1 + 2 * 3; // 7
2int w = (1 + 2) * 3; // 9
3boolean even = (v & 1) == 0; // parentheses are required
4int s = 1 << 2 + 1; // 8: + binds tighter than <<, so 1 << 3
2.01.5

Conditions

if / else if / else for branching, the ternary for simple choices, and switch for many constants. Java 17 supports arrow-form switch expressions that return a value and do not fall through.

Compare strings and boxed values with equals, never ==, which compares references.

Java
1int day = 3;
2String name = switch (day) {
3 case 1, 7 -> "weekend";
4 case 2, 3, 4, 5, 6 -> "weekday";
5 default -> "invalid";
6};
7boolean same = "ab".equals(new String("ab")); // true; == would be false
2.01.6

Loops

for when the count is known, while when it depends on a condition, do … while when the body must run once, and enhanced for to read every element. Use break to leave a loop and continue to skip to the next iteration.

Choose the form that makes the loop's invariant and exit obvious. The enhanced for cannot modify array elements by index or know the index.

Java
1int[] a = {4, 9, 2};
2for (int i = 0; i < a.length; i++) a[i] *= 2; // index needed to write
3int sum = 0;
4for (int x : a) sum += x; // read-only traversal
5int n = 100, steps = 0;
6while (n > 1) { n /= 2; steps++; } // steps = 6
2.01.7

Methods

A method has a return type, name, parameters and body. Java passes everything by value: primitives are copied, and for objects the reference is copied. A method can mutate an object it receives but cannot make the caller's variable point somewhere else.

Keep methods short and name them for what they return or do.

Java
1static int sumTo(int n) {
2 int s = 0;
3 for (int i = 1; i <= n; i++) s += i;
4 return s;
5}
6
7static void setFirst(int[] a) { a[0] = 99; } // caller sees the change
8static void reassign(int[] a) { a = new int[]{1}; } // caller does not
2.01.8

Scope

A variable is visible only inside the block where it is declared. Loop variables exist for the loop, parameters for the method, fields for the object. A local variable may not shadow another local in an enclosing block.

Declare variables in the smallest scope. It reduces bugs and lets the JIT reason better about them.

Java
1int total = 0;
2for (int i = 0; i < 3; i++) { int sq = i * i; total += sq; }
3// i and sq no longer exist here; reading them is a compile error
2.01.9

Overloading

Several methods may share a name if their parameter lists differ in type or count. The compiler picks the best match at compile time using the declared argument types. The return type alone cannot distinguish overloads.

Beware of autoboxing with overloads: list.remove(int index) and list.remove(Object o) behave differently for a List<Integer>.

Java
1static int max(int a, int b) { return a > b ? a : b; }
2static long max(long a, long b) { return a > b ? a : b; }
3static int max(int[] a) { int m = a[0]; for (int x : a) m = Math.max(m, x); return m; }
4
5List<Integer> list = new ArrayList<>(List.of(10, 20, 30));
6list.remove(1); // removes index 1 -> [10, 30]
7list.remove(Integer.valueOf(10)); // removes the value 10 -> [30]
2.01.10

Static members

A static field or method belongs to the class, not to an instance. Utility methods and constants are static. A static method cannot use this or instance fields.

In contest-style code most helpers are static so main can call them directly. Avoid mutable static state in library code; it complicates testing and threads.

Java
1final class MathUtil {
2 static final int MOD = 1_000_000_007; // constant
3 private MathUtil() {} // no instances
4 static int addMod(int a, int b) { return (int) (((long) a + b) % MOD); }
5}
2.01.11

Access modifiers

private: only the same class. Package-private (no modifier): same package. protected: package plus subclasses. public: everywhere. Make fields private and expose behaviour through methods so internal representation can change.

Top-level classes may be public or package-private. A nested helper class is typically private static.

ModifierSame classSame packageSubclassAnywhere
privateyesnonono
(none)yesyesnono
protectedyesyesyesno
publicyesyesyesyes

Practice ladder

Now try it yourself

Easy

  • Predict 7 / 2, -7 / 2, 7 % 3, -7 % 3 and 7 / 2.0
  • Write a method that returns the larger of three ints

Medium

  • Explain why x & 1 == 0 does not compile and fix it
  • Write a switch expression that maps a month number to its number of days (non-leap year)

Advanced

  • Explain what list.remove(1) does for List<Integer> compared with list.remove(Integer.valueOf(1)), and why

Key takeaways

  • Know int and long ranges; integer division truncates toward zero.
  • Parenthesise mixed bitwise and comparison expressions.
  • Java is pass-by-value; objects are passed as copied references.