Java Study
Java Study › Course structure
Course structure · CP2-CSAI.3.M.A

Computer Programming 2 — Java, OOP & Data Structures

A syllabus-driven map of the full 30-session course: the language fundamentals, the object-oriented core, generics and collections, JavaFX, exception handling and software-design principles — with the concepts, complexities and code ideas behind each session, and links into the interactive study companion (lessons, quiz mode and the cheatsheet).

Code
CP2-CSAI.3.M.A
Area
Computer Science
Credits
6.0 ECTS
Sessions
30 (live, in-person)
Year / Semester
3rd year · 1st semester
Academic year
2025–26
Category
Compulsory
Language
English
Programme
BCSAI — Computer Science & AI
Professor
Dr. Anas Abbood
Contact
aabbood@faculty.ie.edu
Office hours
Fri 10:00–11:20 / by appt.

Subject description

This course deepens programming skill using Java, focusing on object-oriented design, advanced data structures, and efficient algorithm implementation. It offers a comprehensive progression from core language fundamentals — variables, operators, control flow, methods and arrays — through the full object-oriented model (encapsulation, inheritance, polymorphism, abstraction) and on to generics, collections, JavaFX GUIs, robust exception handling and professional software-engineering practices (SOLID, design patterns, build tooling).

Through a blend of theory and hands-on practice, and via both individual and team-based projects, students build a final application that demonstrates the ability to design and implement maintainable, modular Java software using professional tools (IntelliJ IDEA, Maven/Gradle). The pace is tentative and may adapt to group performance; the structure below mirrors the official syllabus session-by-session.

Object-oriented design Data structures Algorithm efficiency Generics & collections JavaFX Exception handling SOLID & patterns Build & packaging

Learning objectives

By the end of the course, students will be able to:

Understand Java's core concepts

Explain Java's history and ecosystem (JDK / JRE / JVM) and distinguish it from other languages.

Write and run Java programs

Develop, compile and execute applications with modern tools — IntelliJ IDEA, Maven and Gradle.

Apply fundamental techniques

Use variables, operators, control flow (if-else, switch) and loops to write working programs.

Utilise OOP

Design and implement classes using encapsulation, inheritance, polymorphism and abstraction.

Modularise and reuse code

Define and invoke methods, overload functions, and reason about scope and parameter passing.

Handle exceptions effectively

Build robust error handling with try-catch, custom exceptions and best practices.

Build interactive apps with JavaFX

Create GUI applications using JavaFX UI controls, multimedia and event-driven programming.

Practise software-engineering principles

Apply SOLID, design patterns and modular architecture for maintainable software.

Implement advanced data structures

Work with collection-backed structures — lists, sets, maps and hash tables — and reason about scalability.

Test, debug & profile

Apply unit testing, debugging and a performance-aware mindset to optimise algorithms.

Teaching methodology

IE University's approach emphasises active, collaborative and applied learning: live in-person sessions, hands-on activities, peer reviews and instructor feedback. The expected student workload totals 150 hours across three activity types. The use of generative AI is encouraged but must be acknowledged — treat GenAI output as wrong until you can verify it, and remain critical of its effect on your own learning.

Lectures · 60 h
40.0%
Individual studying · 50 h
33.3%
Group work · 40 h
26.7%

GenAI policy (summary)

  • Minimum-effort prompts give low-quality results — refining prompts is real work.
  • Don't take GenAI output at face value; cross-check it. You own any errors or omissions.
  • LLMs help most when you are already expert enough to be critical of the output.
  • Acknowledging AI use does not affect your grade — failing to acknowledge it violates academic-honesty policy.

Prerequisites & how this course connects

As the second programming course in the BCSAI degree (3rd year, 1st semester), CP2 assumes you can already reason about basic algorithms, variables, control flow and simple functions from Computer Programming 1. Here that foundation is rebuilt rigorously in Java and then taken much further: the procedural fundamentals (Modules A) become the substrate for the object-oriented model (Module B), which in turn is the prerequisite for the advanced APIs — generics and collections (Module E) lean directly on the equals/hashCode and type-system ideas from Modules A–B, and the design-patterns and SOLID material only makes sense once polymorphism and interfaces are solid.

Connects forward to: data-structures and algorithms courses (trees, graphs, complexity), software-engineering and design courses (patterns, architecture), and any later AI/ML coursework that uses the JVM ecosystem. The skills here — disciplined class design, testing, build tooling — are the same ones expected in industry internships.

Weekly study-load — what 150 hours actually means

The 6 ECTS / 150-hour total breaks down across 30 live sessions. With roughly 15 teaching weeks, that is about 10 hours of total commitment per week: time in class, plus preparation, individual study and project work. Treat the per-activity figures below as a planning budget — front-load reading before each session and protect weekly time for the projects, which are easy to underestimate.

~4 h/wk
Lectures & live sessions (60 h total)
~3.3 h/wk
Individual studying (50 h total)
~2.7 h/wk
Group / project work (40 h total)
~10 h/wk
Total sustainable load

Assessment

Continuous evaluation combines two exams, individual and group project work, and participation. The weights below sum to 100%.

Final Exam
25%
Intermediate Exam
25%
Group Project
25%
Individual Assignments / Projects
15%
Class Participation & Attendance
10%
25%

Final Exam

Deliverable: comprehensive written/coding exam (Session 30).

Evaluated on: the full programme — language fundamentals, OOP, generics, collections, exceptions and design.

25%

Intermediate Exam

Deliverable: mid-course exam over fundamentals and early OOP.

Evaluated on: correctness, fluency with syntax/control flow, and class design. Prep with quiz mode.

25%

Group Project

Deliverable: team-built Java application, introduced S24 and presented S29.

Evaluated on: design quality, modularity, use of OOP & collections, and teamwork.

15%

Individual Assignments / Projects

Deliverable: individual project (introduced S19) plus in-class exercises.

Evaluated on: working code, idiomatic Java, and adherence to encapsulation/SOLID.

10%

Participation & Attendance

Deliverable: active engagement in live sessions, peer reviews and discussion.

Evaluated on: contribution quality and presence (see attendance rule).

ComponentWeightDeliverable formatWhat earns marks (criteria)
Intermediate Exam25% In-class written + coding exam over Modules A–B (fundamentals & OOP), around the mid-point. Correct syntax and control flow; sound class design (encapsulation, constructors, this); tracing program output; explaining inheritance/polymorphism. Partial credit for correct reasoning.
Final Exam25% Comprehensive written/coding exam (Session 30) over the whole programme. Mastery across all six modules: fundamentals, the four OOP pillars, generics & wildcards, collection choice with complexity, exception design, and applying SOLID/patterns to a small design.
Group Project25% Team-built Java application: source repository, runnable JAR, and a live demo presented in S29. Design quality and modularity (clean class boundaries, SOLID); correct use of OOP, generics & collections; working, robust code (exception handling); a JavaFX or comparable UI where relevant; teamwork and clear division of work.
Individual Assignments / Projects15% Individual project (introduced S19) plus in-class exercises submitted as source files. Working, idiomatic Java; adherence to encapsulation and SOLID; readable naming and structure; meeting the brief and milestones on time.
Participation & Attendance10% Ongoing engagement in live sessions, peer reviews and discussion. Quality (not just quantity) of contribution, constructive peer feedback, and presence — subject to the 80% attendance rule below.

Study tips — how to prepare for each component

  • For both exams: practise writing code by hand and tracing output, not just reading it. Drill the high-leverage traps — integer vs floating division, == vs .equals(), overriding vs overloading, checked vs unchecked exceptions — using quiz mode and the cheatsheet.
  • For the projects: sketch your class diagram before coding; commit small and often; integrate team modules early (don't leave merging to the final week); write a short README explaining your design decisions.
  • For participation: come having done the reading so you can ask and answer real questions; give specific, kind peer feedback in reviews.
  • Spacing beats cramming: use the ~3.3 h/week of individual study to revisit the previous session's key idea and pre-read the next chapter — the syllabus builds cumulatively, so gaps compound.

Passing, attendance & re-sit rules

  • Four chances to pass any course, across two consecutive academic years (ordinary + extraordinary calls).
  • 80% attendance is mandatory; below it you fail both calls this year and must re-enrol next year.
  • Fail the ordinary call (and meet attendance) → re-sit in June/July, on-campus, no date/format changes.
  • The June/July re-sit is a single comprehensive exam: continuous evaluation is ignored, pass mark is 5, and the maximum grade is 8.0 ("notable").
  • Retakers (3rd call, re-enrolled) must confirm criteria with the professor; maximum retake grade is 10.0.
  • Grade appeals require attending the post-exam review session first. Failing >18 ECTS after re-sits means leaving the programme.

Programme — 30 sessions in 6 modules

The material below is tentative per the syllabus; all listed topics will be attempted, with pace adapting to the group. Sessions are grouped into thematic modules. Each session carries its objective, per-topic notes, a key idea, and the matching readings — and, where the interactive companion covers it, a cross-link into the relevant lesson, the quiz, or the cheatsheet.

MOD A

Java foundations & elementary programming

Sessions 1–9

From "what is Java" to fluent procedural programming: the JVM model and toolchain, primitive data, expressions, control flow, loops, methods and arrays — closing with the first quiz that consolidates the fundamentals.

Module learning outcomes
  • Explain the JDK/JRE/JVM model and compile & run a program from the command line and an IDE.
  • Use primitive types, operators, precedence and type conversion correctly.
  • Express logic with if/switch and the three loop forms, choosing the right one.
  • Decompose problems into methods (overloading, scope, parameter passing) and process 1D/2D arrays.
  1. Module A · Course Overview & Introduction to Java

    Introduction to Java

    Objective: understand what Java is, why it runs everywhere, and write a first program.

    • Course objectives, structure & expectations — the course is a guided climb from procedural fundamentals to professional object-oriented design. Knowing the map up front — six modules, two exams, two projects — lets you connect each session to where it leads and budget the 150-hour workload sensibly.
    • Introduction to Java — Java is a class-based, statically typed, object-oriented language whose source compiles not to machine code but to portable bytecode. Static typing means the compiler catches whole classes of errors (type mismatches, missing methods) before the program ever runs, which matters more as programs grow.
    • History & evolution of Java — created at Sun Microsystems by James Gosling and first released in 1995, Java was designed for networked, platform-independent software. It now ships on a roughly six-month release cadence with long-term-support (LTS) versions (8, 11, 17, 21) that production systems target; the language has steadily added generics, lambdas, the module system, records and pattern matching.
    • Java vs other languages — unlike C/C++ which compile to native code, Java runs on a managed runtime (the JVM) with automatic garbage collection, giving "write once, run anywhere" portability at the cost of a startup/JIT warm-up. Unlike dynamically typed Python or JavaScript, Java's types are checked at compile time, trading some brevity for earlier error detection and tooling support.
    • First Java program — every application starts at a public static void main(String[] args) entry point; System.out.println writes a line to standard output. The ceremony (a class wrapping main) is the first hint that in Java, everything lives inside a class.
    Key idea — bytecode & the JVM

    Source → javac → platform-neutral bytecode → run by the JVM. That indirection is what makes Java portable.

    public class Hello {
        public static void main(String[] args) {
            System.out.println("Hello, world!");
        }
    }
    Common pitfallThe public class name must match the file name exactly (HelloHello.java), and Java is case-sensitive — main with the wrong signature compiles but the JVM won't find an entry point.
    Key takeawayJava buys portability and early error detection through a compile-to-bytecode, run-on-the-JVM model — the mental model behind everything that follows.

    Readings: Liang, ch. 1 (Introduction to Computers, Programs, and Java); Loy/Niemeyer, ch. 1. Focus on: the JDK/JRE/JVM relationship and the compile-then-run cycle — you'll rely on this mental model all semester.

    → Companion: Lesson 01 — Introduction to Java

  2. Module A · Java tools & environments

    The Java toolchain & IntelliJ IDEA

    Objective: create, compile and run Java programs with both the JDK tools and a modern IDE.

    • Language Specification, API, JDK, JRE & IDE — the Language Specification is the precise rulebook for syntax and semantics; the API is the vast standard library (java.util, java.io…) you build on; the JDK bundles the compiler and tools; the JRE is the runtime; the IDE ties them together. Knowing which layer a problem lives in saves hours of confused debugging.
    • Creating, compiling & executingjavac Hello.java produces Hello.class (bytecode), and java Hello launches the JVM on it. Doing this once on the command line demystifies what the IDE's green "Run" button actually does.
    • Developing with IntelliJ IDEA — IntelliJ manages projects, run configurations, dependencies and the edit–compile–run loop, and adds code completion, refactoring and a debugger. These productivity tools matter precisely because they let you focus on design rather than mechanics.
    Key idea — toolchain layering

    JDK ⊃ JRE ⊃ JVM. You install the JDK to develop; the JRE (now usually bundled) is enough to run. The IDE wraps these tools with editing, debugging and refactoring.

    Common pitfallA "java: command not found" or version-mismatch error usually means JAVA_HOME/PATH points at the wrong (or no) JDK. Confirm with java -version and javac -version before blaming your code.
    Connects to…The build tools in Session 20 (Maven/Gradle) automate this same compile-and-package cycle for real projects with dependencies.

    Readings: Loy/Niemeyer, ch. 2 (A First Application); Liang §1.8–1.11 (development tools). Focus on: the difference between JDK and JRE, and getting a project to compile and run inside IntelliJ end-to-end.

    → Companion: Lesson 02 — Java tools, packages, classpath

  3. Module A · Elementary Programming in Java

    Variables, input & data types

    Objective: read console input and declare/assign variables with the right types.

    • Reading console input — a Scanner wrapping System.in turns raw keyboard bytes into typed values via methods like nextInt() and nextLine(). This is how interactive programs collect data before objects and files take over later in the course.
    • Variables & constants — a variable names a typed storage slot; declaring it with final makes it a constant that can be assigned exactly once. Constants document intent (final int MAX = 100) and let the compiler stop accidental reassignment.
    • Assignment statements & expressions — in Java = is an operator, so an assignment is itself an expression that yields the assigned value (x = y = 5 works). Recognising this explains idioms like while ((line = reader.readLine()) != null).
    • Naming conventions — camelCase for variables/methods, PascalCase for classes/interfaces, UPPER_SNAKE for constants. These aren't enforced by the compiler but are universal in professional code; following them makes your work readable to graders and teammates.
    • Data types — Java has exactly eight primitives (byte short int long float double char boolean) that hold raw values, versus reference types that point to objects. Knowing each primitive's size and range prevents overflow surprises later.
    Key idea — reading input
    Scanner in = new Scanner(System.in);
    int age = in.nextInt();
    final double PI = 3.14159;
    Common pitfallMixing nextInt() with nextLine() leaves the trailing newline in the buffer, so the next nextLine() returns an empty string. Read and discard the leftover line, or parse whole lines.
    Key takeawayPick the narrowest correct primitive, mark anything that shouldn't change as final, and follow the naming conventions from day one — habits that pay off across every later module.

    Readings: Liang, ch. 2 (Elementary Programming) §2.1–2.5. Focus on: the eight primitive types and their ranges, and the read–compute–print structure of a simple interactive program.

    → Companion: Lesson 03 — Elementary programming I · Cheatsheet: primitive types

  4. Module A · Elementary Programming in Java

    Numeric types, operators & conversions

    Objective: evaluate numeric expressions correctly, respecting precedence and conversions.

    • Numeric types & operators — integer types (int, long) and floating types (float, double) support + - * / %. The crucial distinction is that / means truncating integer division when both operands are integers, but real division as soon as one is floating — a constant source of bugs.
    • Numeric literals — Java allows readable literals: underscores as digit separators (1_000_000), hex (0xFF) and binary (0b1010) forms, and type suffixes (100L for long, 3.14f for float). An un-suffixed decimal literal is a double; an integer literal is an int.
    • Evaluating expressions & precedence — operators bind by precedence (unary, then multiplicative * / %, then additive + -) and associate left-to-right; parentheses override both. When in doubt, parenthesise for clarity rather than memorising the full table.
    • Augmented assignmentx += 3 is shorthand for x = x + 3 and quietly performs a narrowing cast, so byte b = 10; b += 5; compiles where b = b + 5; would not.
    • Increment / decrement++i increments then yields the new value; i++ yields the old value then increments. The difference only matters when the result is used inside a larger expression.
    • Type conversions — widening (intdouble) happens implicitly because no information is lost; narrowing (doubleint) needs an explicit cast (int) and truncates the fraction, so it can silently lose data.
    Key idea — integer vs floating division
    5 / 2      // → 2   (integer division truncates)
    5 / 2.0    // → 2.5 (one double operand promotes both)
    5 % 2      // → 1   (remainder)
    double avg = (a + b) / 2.0;  // force real division
    Common pitfalldouble can't represent every decimal exactly, so 0.1 + 0.2 != 0.3. Never test floating values with ==; compare within a small tolerance, and use BigDecimal for money.
    Connects to…The widening/narrowing rules here are the numeric analogue of upcasting/downcasting between object types in Session 15.

    Readings: Liang, ch. 2 §2.6–2.13 (operators, conversions, common errors). Focus on: when integer division truncates and how mixed-type expressions get promoted — then verify by tracing a few by hand.

    → Companion: Lesson 03/04

  5. Module A · Elementary Programming in Java

    Selections — boolean logic, if & switch

    Objective: branch program flow with boolean expressions and selection statements.

    • boolean types, values & expressionsboolean holds only true/false, and relational operators (< <= == != >= >) produce booleans. Unlike C, Java will not treat an integer as a condition, which eliminates the classic "use a number as truth" bug.
    • if / two-way if-else / nested & multi-wayif chooses one branch, if-else chooses between two, and chained else if handles several mutually exclusive cases. Always brace your blocks even when one line — it prevents bugs when you later add a second statement.
    • Logical operators&& (and), || (or) and ! (not) combine conditions, and &&/|| short-circuit: evaluation stops as soon as the result is known. This lets you safely write if (s != null && s.length() > 0).
    • Conditional (ternary) operatorcond ? a : b is an expression returning one of two values, handy for concise assignments like int max = a > b ? a : b;.
    • switch statements — dispatch on a discrete value (int, char, String, enum). Classic switch falls through until a break; the newer arrow form (case X -> …) avoids fall-through entirely.
    • Common errors & pitfalls= (assignment) vs == (comparison), the dangling-else binding to the nearest if, and comparing floating-point values with ==.
    Key idea — short-circuit evaluation

    a && b never evaluates b if a is false — letting you guard against null/zero before using a value.

    if (account != null && account.getBalance() > 0) { ... }
    String label = (n % 2 == 0) ? "even" : "odd";
    Common pitfallComparing objects (especially String) with == tests reference identity, not contents. Use .equals() for value comparison — a trap revisited in earnest at Session 12/15.

    Readings: Liang, ch. 3 (Selections). Focus on: short-circuit behaviour and the difference between = and ==; these underlie countless exam trick questions.

    → Companion: Lesson 05 — Control flow · Cheatsheet: control flow

  6. Module A · Loops in Java

    Loops & iteration

    Objective: repeat work safely with the three loop forms and pick the right one.

    • while loop — tests the condition before each pass, so it may run zero times. Use it when the number of iterations isn't known in advance (e.g. "read until end of input").
    • do-while loop — tests after the body, guaranteeing at least one execution. Ideal for input-validation menus where you must prompt at least once.
    • for loop — packs initialisation, condition and update into one header, making counted iteration self-documenting. The enhanced for-each form traverses arrays/collections without an index.
    • Nested loops — a loop inside a loop builds 2-D structures (multiplication tables, grids, matrix work). Each extra nesting level over the same n data multiplies the cost.
    • Loop design strategy & which to use — choose counter-controlled loops when the count is known and sentinel/condition-controlled loops otherwise; break exits early and continue skips to the next pass. Guard against off-by-one errors and conditions that never become false.
    Key idea — loop choice & complexity

    A single pass over n items is O(n); a nested loop over the same data is typically O(n²) — the first cost-model intuition for the algorithms ahead.

    for (int i = 0; i < n; i++)          // O(n)
        for (int j = 0; j < n; j++)      // O(n²) overall
            grid[i][j] = i * j;
    Common pitfallOff-by-one errors (<= where you meant <) and forgetting to advance the loop variable are the two most common causes of wrong output and infinite loops. Trace the first and last iteration by hand.
    Connects to…The O(n) vs O(n²) intuition here is the seed of the search/sort complexity discussion in Session 8 and the hash-table O(1) payoff in Session 26.

    Readings: Liang, ch. 4 (Loops). Focus on: choosing the right loop form, and reasoning about how nesting affects running time.

    → Companion: Lesson 05 — Control flow (loops)

  7. Module A · Methods in Java

    Methods & modular code

    Objective: decompose programs into reusable methods and reason about scope.

    • Declaration & invocation — a method has a signature (name + parameter types), a return type and a body; calling it pushes a frame onto the call stack and returns control when it finishes. Methods are the unit of reuse in procedural code.
    • Parameters & return values — Java is strictly pass-by-value: a copy of each argument is handed to the method. For objects the copied value is the reference, so the method can mutate the shared object but cannot make the caller's variable point elsewhere.
    • void vs value-returning methods — a void method exists for its side effects (printing, mutating); a value-returning method computes and hands back a result you can compose into larger expressions.
    • Modularising code — splitting logic into small, single-responsibility methods makes programs readable, testable and reusable. This is the procedural rehearsal for the class-level decomposition in Module B.
    • Overloading methods — several methods may share a name if their parameter lists differ; the compiler picks one based on the argument types at the call site (static dispatch). Return type alone cannot distinguish overloads.
    • Scope of variables — a local variable lives only within the block where it's declared and must be assigned before use; parameters are locals initialised from the arguments.
    Key idea — overloading is compile-time
    int max(int a, int b) { ... }
    double max(double a, double b) { ... }  // overload, chosen by arg types
    // pass-by-value: reassigning a parameter never affects the caller
    Common pitfall"Pass-by-value" confuses many: a method can change an object's fields through the reference, but assigning a new object to the parameter is invisible to the caller. Test this once to internalise it.
    Connects to…Overloading here is contrasted with overriding in Session 14 — same-name methods, but one is resolved at compile time and the other at runtime.

    Readings: Liang, ch. 6 (Methods). Focus on: the pass-by-value semantics and how the call stack grows and unwinds — essential for understanding recursion and debugging.

    → Companion: Lesson on methods

  8. Module A · Arrays in Java

    Arrays — 1D & multidimensional

    Objective: store and process fixed-size sequences, and search/sort them.

    • Array basics — an array is a fixed-length, zero-indexed, contiguous block of same-typed elements; its size is fixed at creation and read via the length field (not a method). Indices run 0..length-1.
    • Processing arrays & foreach — a classic for with an index lets you read and write; the enhanced for-each (for (int x : arr)) is cleaner for read-only traversal but gives no index.
    • Copying arrays — assigning one array variable to another copies only the reference, so both point at the same data. For an independent copy use Arrays.copyOf, clone() or System.arraycopy.
    • Passing arrays to methods — because the reference value is passed, a method can modify the caller's array in place — useful for in-place sorts, dangerous if unintended.
    • Variable-length argument lists — varargs (int... nums) let a method accept any number of arguments, received as an array; only one varargs parameter is allowed and it must come last.
    • Searching & sorting — linear search scans every element (O(n)); binary search halves the range each step (O(log n)) but requires sorted data. Library helpers Arrays.sort and Arrays.binarySearch implement these efficiently.
    • Multidimensional arrays — Java has no true 2-D arrays, only arrays of arrays, which means rows can have different lengths (jagged arrays). Access is grid[row][col].
    Key idea — search complexity

    Linear search is O(n) on any array; binary search is O(log n) but requires the array to be sorted first.

    int[] a = {5, 2, 9, 1};
    Arrays.sort(a);                       // {1, 2, 5, 9}
    int i = Arrays.binarySearch(a, 5);    // → 2  (needs sorted input)
    Common pitfallReading arr[arr.length] throws ArrayIndexOutOfBoundsException — the last valid index is length-1. And calling binarySearch on an unsorted array returns a meaningless result, not an error.
    Connects to…Arrays' fixed size motivates the resizable ArrayList in Session 15 and the whole collections framework in Sessions 25–26.

    Readings: Liang, ch. 7 (Single-Dimensional Arrays) & ch. 8 (Multidimensional Arrays). Focus on: reference vs deep copying of arrays, and the precondition (sorted data) that makes binary search valid.

    → Companion: Lesson 06 — Arrays (1D and 2D)

  9. Module A · Quiz 1 — checkpoint

    Quiz 1 & fundamentals recap

    Objective: consolidate and self-assess the procedural fundamentals before OOP.

    • Quiz on fundamental Java topics — a timed check on the toolchain, types, control flow, loops, methods and arrays. Treat it as a low-stakes rehearsal for exam conditions: practise writing and tracing code by hand, not just recognising it.
    • Summary of fundamentals — a guided recap that knits the procedural pieces together and flags the recurring traps (integer division, == vs .equals(), off-by-one, pass-by-value) before the object-oriented model raises the abstraction level.
    Key idea — checkpoint

    This checkpoint feeds the 25% intermediate exam. Rehearse with the companion's mixed quiz.

    Key takeawayIf anything in Modules A feels shaky, fix it now — every later module assumes fluent control flow, methods and arrays.

    Readings: review Liang chs. 1–8. Focus on: re-deriving the worked examples yourself rather than re-reading; redo any exercise you previously needed help with.

    → Companion: Quiz mode — 12 mixed questions

MOD B

Object-oriented programming core

Sessions 10–18

The heart of the course: defining classes and objects, then the four OOP pillars — encapsulation, inheritance, polymorphism and abstraction — plus the design principles (SOLID, composition vs inheritance) that keep object models maintainable. Closes with a consolidating OOP quiz.

Module learning outcomes
  • Design classes with constructors, instance/static members and the this reference.
  • Apply encapsulation (private fields, accessors, immutability) and distinguish primitive vs reference semantics.
  • Build inheritance hierarchies (super, constructor chaining, overriding) and use dynamic binding.
  • Choose between abstract classes and interfaces, and apply SOLID and composition-over-inheritance.
  1. Module B · Objects and classes — 1

    Defining classes & objects

    Objective: define a class, construct objects, and manage instance vs static members.

    • Defining classes & objects — a class is a blueprint describing state and behaviour; new creates an object (instance) on the heap from that blueprint. The shift from "a program is a list of steps" to "a program is a society of collaborating objects" is the conceptual core of the whole course.
    • Constructors — special methods (no return type, same name as the class) that initialise a new object's fields. Java supplies a no-arg default only until you declare any constructor of your own, after which you must add it back if you still need it.
    • Accessing objects via reference variables — a variable of a class type stores a reference to an object, not the object itself; many references can point at the same object, and null means "points at nothing".
    • Object data & methods — fields hold an object's state, methods define its behaviour, and good design keeps the two together so an object manages its own data.
    • Passing objects to methods — the reference value is copied, so the method shares the same object and any field mutations it makes are visible to the caller.
    • this keyword — inside an instance method this denotes the current object; it disambiguates a field from a same-named parameter (this.x = x).
    • Static variables, constants & methods — declared static, these belong to the class itself and are shared by all instances; use them for counters, factory methods and true constants (static final).
    Key idea — instance vs static
    class Counter {
        static int total = 0;   // shared by all instances
        int id;                 // one per object
        Counter() { id = ++total; }
    }
    Common pitfallCalling a method on a null reference throws NullPointerException — the most common Java runtime error. Initialise references before use and check for null at boundaries.
    Key takeawayKeep data and the methods that operate on it inside the same class; an object should be responsible for its own consistency, which sets up encapsulation in Session 13.

    Readings: Liang, ch. 9 (Objects and Classes). Focus on: how constructors initialise state, and the instance-vs-static distinction — a frequent exam discriminator.

    → Companion: Lesson 10–11 — Classes and objects

  2. Module B · Objects and classes — 2

    Visibility, immutability & reference types

    Objective: control access and understand the deep difference between value and reference variables.

    • Visibility modifiers — four levels control access: private (same class only), package-private (no modifier — same package), protected (package + subclasses) and public (everywhere). The guideline is to keep everything as private as possible and widen only deliberately.
    • Immutable objects & classes — an object with no mutators and all-final fields can never change after construction, which makes it automatically thread-safe, freely shareable and safe to cache. String and the wrapper types are the canonical examples.
    • Scope of variables — fields exist for the object's lifetime, locals only within their block, and parameters only within the method; a local can shadow a field, which is when this. becomes necessary.
    • this keyword — besides referring to the current object, this(...) in a constructor calls another constructor of the same class, letting you funnel initialisation through one place.
    • Primitive vs reference variables — a primitive variable stores the actual value; a reference variable stores an address. This single distinction explains copying, equality and the NullPointerException family of bugs.
    Key idea — copying a reference ≠ copying the object
    int[] a = {1,2}; int[] b = a;  // same array
    b[0] = 9;                       // a[0] is now 9 too
    Common pitfallTwo references to the same mutable object create "spooky action at a distance": changing it through one variable surprises code holding the other. Immutability (or defensive copies) removes the hazard.
    Connects to…The reference-vs-value distinction is exactly why == and .equals() differ (Session 15) and why protected matters for inheritance (Session 14).

    Readings: Liang, ch. 9 §9.9–9.13; Bloch, Effective Java Item 17 (minimise mutability). Focus on: Bloch's argument for immutability and the access-level table — both recur throughout the OOP and design modules.

    → Companion: Lesson 10–11 — visibility, overloading

  3. Module B · Object-Oriented Thinking

    Thinking in objects

    Objective: model a problem domain as collaborating objects with clear relationships.

    • Thinking in objects — good OO design starts from responsibilities and behaviours ("what can this thing do, and what is it accountable for?") rather than from data layout. The aim is objects that encapsulate their own state and expose meaningful operations.
    • Class relationships — distinguish association (uses-a), aggregation/composition (has-a, with composition implying ownership and lifecycle) from inheritance (is-a). Choosing has-a over is-a is the design lever explored fully in Session 17.
    • The String class — strings are immutable objects backed by an interned pool, so literals may be shared. This is why == sometimes appears to work on strings but is unreliable: always compare contents with .equals().
    • Case study — a worked end-to-end domain model (identifying classes, fields, methods and relationships) turns the abstract guidance into a concrete design you can imitate in the projects.
    Key idea — String immutability

    Strings never change in place; "modifying" one creates a new object. Use StringBuilder for heavy concatenation.

    String a = "hi", b = "hi";   // same pooled object
    a == b;          // true here, but DON'T rely on it
    a.equals(b);     // true — the correct way to compare
    Common pitfallBuilding a string inside a loop with += creates a new object every iteration — O(n²) work. Use a StringBuilder and call toString() once at the end.
    Connects to…The has-a vs is-a choice here is formalised as "composition over inheritance" in Session 17, and .equals() gets its full contract in Session 15.

    Readings: Liang, ch. 10 (Object-Oriented Thinking); Bloch Item 51 (favour composition). Focus on: how to decompose a problem into classes and relationships — practise on a domain of your own before the project.

    → Companion: Lesson 12 — Object-oriented thinking

  4. Module B · Encapsulation in Java

    Encapsulation

    Objective: protect invariants by hiding state behind a controlled interface.

    • Getters & setters — accessor methods mediate read/write access to private fields, letting a setter validate input or a getter compute a derived value without changing the class's public contract. They are the seam that makes later refactoring safe.
    • Encapsulation principles — make fields private and expose behaviour through public methods so the object alone enforces its invariants; callers depend on what it does, not how it stores data. This is the practical face of "information hiding".
    • Immutable classes — combine a final class, all-final private fields, no setters and defensive copies of any mutable inputs/outputs to guarantee the object can never be observed in an inconsistent state.
    Key idea — validate at the boundary
    private int age;
    public void setAge(int a) {
        if (a < 0) throw new IllegalArgumentException("age < 0");
        this.age = a;          // invariant: age is never negative
    }
    Common pitfallA getter that returns a reference to a mutable field (e.g. a List or array) leaks your internals — callers can mutate it behind your back. Return an unmodifiable view or a copy.
    Connects to…Encapsulation is the "E" behind clean APIs, and directly enables the Single-Responsibility and Open/Closed principles in Session 17; setters that validate prevent the bad state that Session 21's exceptions would otherwise report.

    Readings: Liang, ch. 9 §9.10; Bloch Items 15–16 (minimise accessibility, prefer accessors). Focus on: why public fields are almost always wrong, and how validating setters protect class invariants.

    → Companion: Lesson 13 — Encapsulation

  5. Module B · Inheritance in Java

    Inheritance

    Objective: reuse and specialise behaviour through subclassing without breaking the base.

    • Superclasses & subclassesextends creates an is-a relationship: a subclass inherits the superclass's accessible members and may add or specialise behaviour. Use it only when the subclass truly is a kind of the superclass.
    • The super keywordsuper(...) invokes a chosen superclass constructor, and super.method() calls the parent's version of an overridden method, letting a subclass extend rather than replace behaviour.
    • Constructor chaining — every subclass constructor implicitly (or explicitly via super(...)) calls a superclass constructor first, so objects are built base-up. If the superclass has no no-arg constructor, you must call one explicitly.
    • Overriding methods — a subclass redefines an inherited method with the same signature; annotate it @Override so the compiler verifies you really are overriding and not accidentally overloading.
    • Overriding vs overloading — overriding is resolved at runtime by the object's actual type (dynamic dispatch); overloading is resolved at compile time by the argument types. Conflating the two is a classic exam trap.
    • Object class & toString() — every class ultimately extends Object, inheriting toString(), equals() and hashCode(); overriding toString() gives readable debug output and is almost always worth doing.
    Key idea — @Override + super()
    class Dog extends Animal {
        Dog(String n) { super(n); }
        @Override public String speak() { return "Woof"; }
    }
    Common pitfallWithout @Override, a typo in the signature silently creates an overload that is never called polymorphically — the program compiles but misbehaves. Always annotate intended overrides.
    Connects to…Overriding is the mechanism that makes the polymorphism of Session 15 work, and Bloch's "design for inheritance or prohibit it" anticipates the composition-vs-inheritance debate of Session 17.

    Readings: Liang, ch. 11 (Inheritance and Polymorphism) §11.1–11.6; Bloch Item 19 (design for inheritance or prohibit it). Focus on: constructor chaining order and the precise difference between overriding and overloading.

    → Companion: Lesson 14 — Inheritance

  6. Module B · Polymorphism in Java

    Polymorphism & dynamic binding

    Objective: write code against base types and let the runtime pick the right implementation.

    • Introduction to polymorphism — a single reference type can hold objects of many subtypes, each responding to the same call in its own way. This lets you write code against a general type and add new variants without touching existing logic.
    • Dynamic binding — for overridden methods the JVM dispatches on the object's actual runtime type, not the declared reference type, so Animal a = new Dog(); a.speak(); runs Dog's version.
    • Casting objects — upcasting a subtype to a supertype is implicit and always safe; downcasting needs an explicit cast and can throw ClassCastException if the object isn't really that type, so guard it with instanceof.
    • Object.equals() — defines logical (value) equality and must obey the reflexive/symmetric/transitive/consistent contract; whenever you override equals you must also override hashCode consistently.
    • The ArrayList class — a resizable, generic list (ArrayList<String>) and your first real collection: it grows automatically, unlike a fixed array, previewing the framework in Module E.
    • The instanceof operator — tests an object's runtime type before a downcast; the pattern form if (o instanceof Dog d) tests and binds in one step.
    Key idea — dynamic dispatch
    Animal a = new Dog();
    a.speak();   // "Woof" — resolved at runtime, not compile time
    if (a instanceof Dog d) d.fetch();   // safe downcast via pattern
    Common pitfallOverriding equals but not hashCode (or vice-versa) breaks HashSet/HashMap: equal objects land in different buckets and "disappear". Always override both together.
    Connects to…The equals/hashCode contract here is precisely what hash-based collections in Session 26 rely on; polymorphism is the foundation of the Strategy and Observer patterns in Session 28.

    Readings: Liang, ch. 11 §11.7–11.14; Bloch Items 10–11 (equals/hashCode). Focus on: why dynamic binding picks the subclass method, and the rules for a correct equals/hashCode pair.

    → Companion: Lesson 15 — Polymorphism & dynamic binding

  7. Module B · Abstract classes and Interfaces

    Abstraction — abstract classes & interfaces

    Objective: define contracts and partial implementations, and choose the right abstraction.

    • Abstract classes — declared abstract, they cannot be instantiated and may mix concrete methods (shared implementation) with abstract ones (left to subclasses). Use them when subclasses share both state and partial behaviour.
    • Why abstract methods — an abstract method declares a contract without a body, forcing every concrete subclass to supply its own implementation; this guarantees that, say, every Shape can compute its area().
    • Case study — a shape/geometry hierarchy (Shape → Circle, Rectangle…) shows abstraction and polymorphism working together: store shapes in one collection and total their areas without knowing the concrete types.
    • Defining & implementing interfaces — an interface is a pure contract (since Java 8 it may also carry default and static methods); a class can implement many interfaces, gaining multiple inheritance of type.
    • Interfaces vs abstract classes — pick an interface for a capability many unrelated classes can have (e.g. Comparable); pick an abstract class when subclasses share state and a common partial implementation. A class extends one class but implements many interfaces.
    • Multiple interfaces & ambiguity — if two interfaces supply clashing default methods, the implementing class must override the method and may delegate with Interface.super.method().
    Key idea — program to an interface
    interface Shape { double area(); }
    class Circle implements Shape {
        double r; public double area() { return Math.PI*r*r; }
    }
    List<Shape> shapes = List.of(new Circle());  // depend on the type, not the class
    Common pitfallReaching for inheritance ("a Circle is an abstract Shape") when a capability interface would be cleaner leads to rigid hierarchies. Prefer the smallest interface that expresses the contract.
    Connects to…"Program to an interface" is the dependency-inversion and interface-segregation thinking of Session 17, and interfaces are how the design patterns of Session 28 stay swappable.

    Readings: Liang, ch. 13 (Abstract Classes and Interfaces); Bloch Items 20–22 (prefer interfaces to abstract classes). Focus on: the decision rule for interface vs abstract class, and why coding against interfaces keeps designs flexible.

    → Companion: Lesson 16 — Interfaces and abstract classes

  8. Module B · Object-Oriented Design Principles

    OO design principles — SOLID & beyond

    Objective: judge and improve a design using established principles, not just taste.

    • SOLID overview — five principles for maintainable OO design: Single-responsibility (one reason to change), Open/closed (extend without modifying), Liskov substitution (subtypes must be usable as their base), Interface segregation (many small interfaces beat one fat one) and Dependency inversion (depend on abstractions, not concretions). They turn "good design" from taste into checkable criteria.
    • Composition vs inheritance — prefer assembling behaviour from has-a parts over deep is-a hierarchies; composition is more flexible, avoids the fragile-base-class problem, and lets you change collaborators at runtime.
    • Common OO design pitfalls — god classes that do everything, hierarchies too deep to reason about, and leaky abstractions whose internals show through the interface. Each violates one or more SOLID principles.
    • Shallow vs deep modules — Ousterhout's lens: a deep module hides a lot of functionality behind a small interface (high benefit, low cost), while a shallow one exposes nearly as much complexity as it hides. Aim for depth.
    Key idea — deep modules

    The best modules expose a narrow interface over a deep implementation — maximising functionality hidden behind minimal surface area.

    Common pitfallSOLID is a guide, not dogma — over-applying it (an interface and factory for every class) produces needless ceremony. Reach for a principle when it removes real pain, not reflexively.
    Connects to…Open/closed and dependency inversion are exactly what the design patterns of Session 28 implement; these principles are also a grading criterion for both projects.
    Key takeawayYou can now critique a design with shared vocabulary — name the principle a piece of code violates and the refactor follows.

    Readings: Bloch, Effective Java (composition Item 18, interface design); SOLID primers; Ousterhout, A Philosophy of Software Design (module depth). Focus on: applying each SOLID letter to your own project design, and recognising the composition-over-inheritance trade-off.

    → Companion: Lessons 12–16 (applied to your designs)

  9. Module B · Quiz on Object-Oriented Programming

    OOP quiz & recap

    Objective: consolidate the full OOP model before moving to advanced APIs.

    • Quiz covering all OOP topics — a consolidating assessment over classes, encapsulation, inheritance, polymorphism, abstraction and design. Expect both code-tracing ("what does this print?") and design-judgement ("which principle does this violate?") questions.
    • Summary of fundamental OOP concepts — ties the four pillars to SOLID: encapsulation underpins single-responsibility, inheritance/polymorphism enable open/closed and Liskov, abstraction enables interface-segregation and dependency-inversion.
    Key idea — checkpoint

    A strong OOP foundation underpins the group/individual projects and both exams.

    Key takeawayBe able to name the pillar or principle at work in any snippet — that fluency is what both exams and project reviews reward.

    Readings: review Liang chs. 9–13. Focus on: overriding-vs-overloading, equals/hashCode, and interface-vs-abstract-class decisions — the highest-yield revision targets.

    → Companion: Quiz mode

MOD C

Projects, build tooling & exception handling

Sessions 19–21

From code to a shippable artifact: the individual project kicks off, build tooling (Maven/Gradle, JARs) turns sources into deliverables, and robust exception handling makes applications resilient.

Module learning outcomes
  • Scope and plan an individual project with clear deliverables and timeline.
  • Build and package a Java application with Maven/Gradle into a runnable JAR.
  • Design robust error handling with checked/unchecked exceptions and custom types.
  1. Module C · Individual Project Workshop

    Individual project kickoff

    Objective: understand the individual project's scope, expectations and timeline.

    • Introduction to the individual project — choose an application meaningful enough to exercise classes, collections and error handling, but scoped to finish solo. The brief is your contract; read it for required features and constraints.
    • Expectations & guidelines — the quality bar is idiomatic, well-encapsulated Java that applies SOLID, with readable naming and a short design rationale. Working code that's well-structured beats more features built sloppily.
    • Timeline & deliverable — milestones (design → core feature → polish → submission) feed the 15% individual mark; submit source plus a brief README describing how to build and run it.
    Key idea — design before code

    Sketch classes and responsibilities first; the OOP module gives you the vocabulary to do so.

    Key takeawayStart small and working, then grow — a running skeleton you extend beats a grand design you never finish.

    Readings: Bloch, Effective Java (general advice on API and class design); the project brief. Focus on: turning the brief into a one-page class sketch before you write any code.

  2. Module C · Compilation and Packaging

    Build tooling & packaging

    Objective: turn source into a versioned, distributable artifact.

    • Building with Maven/Gradle — these tools replace manual javac commands with a declarative build: you state dependencies and the tool resolves, compiles, tests and packages through a defined lifecycle (compiletestpackage). This makes builds reproducible across machines.
    • Creating .jar files — a JAR bundles compiled .class files (and resources) into one archive; adding a manifest entry naming the Main-Class makes it directly runnable with java -jar.
    • Package management with Maven Central — declaring a dependency (group:artifact:version) pulls the library and its transitive dependencies automatically from the central repository, so you never check JARs into source control.
    • Delivering Java projects — a clean, reproducible build plus a runnable artifact and a README is what "delivering" means in practice — and what graders and teammates expect to receive.
    Key idea — a runnable JAR
    mvn package          # → target/app-1.0.jar
    java -jar app-1.0.jar  # runs the Main-Class from the manifest
    Common pitfalljava -jar failing with "no main manifest attribute" means the manifest lacks a Main-Class, and "ClassNotFoundException" at runtime usually means dependencies weren't bundled — use a shade/fat-jar plugin to include them.
    Connects to…This is the automated, dependency-aware version of the manual compile-and-run from Session 2, and it's how you package both the individual (S19) and group (S24) projects for delivery.

    Readings: Loy/Niemeyer (packaging & deployment); Maven/Gradle docs. Focus on: the build lifecycle phases and how a manifest's Main-Class makes a JAR runnable.

  3. Module C · Error Handling in Java

    Exception handling

    Objective: build resilient code that signals and recovers from failures cleanly.

    • Exception-handling overview — exceptions let you separate the normal "happy path" from error handling, so the main logic stays readable while failures propagate up to code able to deal with them.
    • Exception typeschecked exceptions (extend Exception) must be declared or handled and model recoverable conditions; unchecked ones (RuntimeException) signal programming bugs; Error represents JVM-level failures you shouldn't catch.
    • Declaring, throwing & catchingthrow raises an exception, throws declares it on a method, and try/catch/finally handles it; finally always runs, for cleanup.
    • Custom exceptions — defining domain-specific types (e.g. InsufficientFundsException) makes failures self-documenting and lets callers catch precisely what they can handle.
    • Best practices — fail fast, never silently swallow an exception, catch the most specific type, throw exceptions appropriate to the abstraction, and prefer try-with-resources so resources close automatically.
    Key idea — try-with-resources
    try (Scanner s = new Scanner(file)) {
        // s is closed automatically, even on exception
    } catch (FileNotFoundException e) {
        System.err.println("Missing file: " + e.getMessage());
    }
    Common pitfallAn empty catch block (swallowing the exception) hides bugs and produces baffling behaviour later. At minimum log it; usually rethrow or handle it meaningfully.
    Connects to…Validating setters in Session 13 typically throw IllegalArgumentException; robust exception handling is an explicit grading criterion for both projects.

    Readings: Liang, ch. 12 (Exception Handling and Text I/O); Bloch Items 69–77 (use exceptions for exceptional conditions, favour standard exceptions, fail fast). Focus on: the checked-vs-unchecked decision and why try-with-resources beats manual finally cleanup.

    → Companion: Lesson 18 — Exception handling

MOD D

JavaFX & interactive applications

Sessions 22–24

Building graphical, event-driven applications: the JavaFX scene graph and layout panes, UI controls and multimedia, and property binding — wrapped around the launch of the final project.

Module learning outcomes
  • Structure a JavaFX app with stages, scenes, panes and the scene graph.
  • Wire UI controls and multimedia with event handlers and property binding.
  • Scope and plan the final project's idea, timeline and deliverable.
  1. Module D · JavaFX Basics

    JavaFX basics

    Objective: assemble a window from a scene graph of panes and shapes.

    • Introduction to JavaFX — JavaFX models a GUI as a tree: a Stage (window) holds a Scene, which holds a scene graph of nodes (controls, shapes, layout panes). Understanding this containment hierarchy is the key to building any window.
    • JavaFX vs Swing & AWT — JavaFX superseded the older AWT/Swing toolkits with a modern scene graph, CSS styling, property binding and FXML, giving cleaner separation of UI and logic.
    • Panes, groups, UI controls & shapes — layout panes (VBox, HBox, BorderPane, GridPane) arrange child nodes automatically, so you describe structure rather than pixel coordinates.
    • Property binding — JavaFX properties can be bound so the UI updates automatically when the model changes (and vice-versa), eliminating manual "refresh" code and a whole class of sync bugs.
    • Color & Font classes — typed styling primitives for fills, strokes and text, complemented by CSS for larger styling concerns.
    • Image & ImageView — load and display images, with ImageView handling sizing and fitting within the scene graph.
    Key idea — Stage → Scene → node graph
    Button b = new Button("Click");
    b.setOnAction(e -> System.out.println("hi"));   // lambda event handler
    stage.setScene(new Scene(new StackPane(b), 300, 200));
    stage.show();
    Common pitfallJavaFX is single-threaded: never block or update the UI from a background thread directly — long work belongs on a Task/background thread, with UI updates marshalled back via Platform.runLater.
    Connects to…Event handlers are lambdas implementing a functional interface — the same interface-and-polymorphism ideas from Sessions 15–16 applied to the UI.

    Readings: Liang, chs. 14–16 (JavaFX basics, events, UI controls & multimedia). Focus on: the Stage/Scene/node hierarchy and how event handlers wire user actions to your code.

    → Companion: Lesson 20 — JavaFX, compilation, packaging

  2. Module D · JavaFX UI Controls and Multimedia

    JavaFX controls & multimedia

    Objective: build a complete interactive UI with the standard controls and media.

    • Label & Labeled — display-only nodes for text and graphics; Labeled is the shared superclass that buttons and labels both extend (inheritance in the standard library).
    • Button, CheckBox, RadioButton — command and selection controls; radio buttons grouped in a ToggleGroup enforce single-choice selection.
    • TextField, ComboBox — free-text and constrained-choice input, the building blocks of forms.
    • ListView, ScrollBar, Slider — present collections of items and capture ranged/continuous input; ListView is typically backed by an ObservableList so it updates as the data changes.
    • Video & audio — the media API (Media, MediaPlayer, MediaView) plays sound and video inside the scene graph.
    Key idea — event-driven UIs

    Controls fire events; you register handlers (often lambdas). The UI is reactive, not procedural.

    ListView<String> list = new ListView<>(items);   // items: ObservableList
    list.getSelectionModel().selectedItemProperty()
        .addListener((obs, old, sel) -> show(sel));
    Connects to…ObservableList bridges JavaFX to the collections framework of Sessions 25–26; the controls here are what you'll wire into the group project's UI.

    Readings: Liang, ch. 16 (JavaFX UI Controls and Multimedia). Focus on: binding a control to a data model so the UI reflects state changes without manual refresh code.

    → Companion: Lesson 20 — JavaFX

  3. Module D · Final Project Workshop — 1

    Final project kickoff

    Objective: define the final (group) project's idea, scope and timeline.

    • Introduction to the final project idea — pick an application substantial enough to demonstrate OOP design, collections and a UI, yet realistic for a team to finish. Agree the scope and a minimal viable version early.
    • Expectations & guidelines — graded on design quality and modularity (SOLID, deep modules), correct use of OOP/generics/collections, robustness (exception handling), and teamwork; the demo should explain why the design is shaped as it is.
    • Timeline & deliverable — milestones (S24 kickoff → S27 progress check → S29 presentation) feed the 25% group mark; deliver a repository, a runnable build and a short design document.
    Key idea — modular from day one

    Split work along clean module boundaries so the team can build in parallel — apply SOLID and deep modules.

    Common pitfall"We'll integrate at the end" is how teams lose the final week to merge conflicts and interface mismatches. Agree interfaces up front and integrate continuously.

    Readings: Bloch, Effective Java (API and class design); the project brief. Focus on: defining clean module interfaces between team members so work can proceed in parallel.

MOD E

Generics, collections & design patterns

Sessions 25–28

The advanced toolkit: type-safe generics, the collections framework (sets and maps / hash tables), and reusable design patterns — interleaved with final-project work time.

Module learning outcomes
  • Write type-safe generic methods and classes using bounds and wildcards.
  • Choose the right collection (List/Set/Map) and reason about hash-table performance.
  • Recognise and apply creational, structural and behavioural design patterns.
  1. Module E · Generics in Java

    Generics

    Objective: write reusable, type-safe code parameterised over types.

    • Motivations & benefits — generics let a class or method work over a parameterised type while keeping full compile-time type safety, so the compiler catches mistakes and you avoid error-prone casts. List<String> can never accidentally hold an Integer.
    • Generic methods & classes — a type parameter <T> stands in for a type chosen by the caller; the same code then serves Box<String>, Box<Integer> and so on without duplication.
    • Type parameters & wildcards? is an unknown type; ? extends T accepts T or any subtype (read from it), and ? super T accepts T or any supertype (write to it). The PECS rule — Producer Extends, Consumer Super — tells you which to use.
    • Bounded types — constrain a parameter so you can call methods on it, e.g. <T extends Comparable<T>> guarantees every T can be compared, enabling a generic max.
    • Raw types & type erasure — generic type information exists only at compile time; the runtime erases it to raw types. This explains why you can't write new T[] or test x instanceof List<String> — and why mixing in raw types defeats the safety generics provide.
    Key idea — PECS & erasure
    <T extends Comparable<T>> T max(List<? extends T> xs) { ... }
    // "Producer extends, Consumer super"; types are erased at runtime
    Common pitfallFalling back to a raw List (no type argument) silences the compiler's checks and reintroduces the cast bugs generics were meant to prevent. Always parameterise; use List<?> if the element type is genuinely unknown.
    Connects to…Bounded types rest on the Comparable interface from Session 16, and generics are what make the collections of Session 26 type-safe (Map<String,User>).

    Readings: Liang, ch. 19 (Generics); Bloch Items 26–33 (don't use raw types, prefer generic methods, use bounded wildcards). Focus on: the PECS rule for wildcards and why type erasure forbids certain operations.

    → Companion: Lesson 17 — Collections, generics

  2. Module E · Sets and Maps in Java

    Sets & maps (hash tables)

    Objective: pick the right collection and understand its performance characteristics.

    • Sets & HashSets — a Set models a collection with no duplicates; HashSet implements it over a hash table for average O(1) membership tests, while TreeSet keeps elements sorted at O(log n) and LinkedHashSet preserves insertion order.
    • Sets vs lists — use a List when order and duplicates matter and you index by position; use a Set when you only care about membership and uniqueness. Choosing the right one is both a correctness and a performance decision.
    • Maps in Java — a Map associates unique keys with values; HashMap gives average O(1) get/put, TreeMap keeps keys sorted (O(log n)), and LinkedHashMap remembers insertion order. Maps are the workhorse for lookups and counting.
    • Singleton & unmodifiable collections/maps — factory methods like List.of, Set.of, Map.of and Collections.unmodifiableList produce immutable collections, ideal for safe sharing and defensive returns.
    Key idea — hashing buys O(1)
    Map<String,Integer> counts = new HashMap<>();
    for (String w : words)
        counts.merge(w, 1, Integer::sum);   // word-frequency in O(n)
    // average O(1) get/put — IF equals & hashCode are consistent
    Common pitfallUsing a mutable object as a HashMap key (or one with a broken hashCode) makes entries "vanish" after the key changes. Use immutable keys and keep equals/hashCode in sync.
    Connects to…The O(1) payoff here is the destination of the complexity thread begun with loops (S6) and arrays (S8); it works only because of the equals/hashCode contract from Session 15.

    Readings: Liang, chs. 20–21 (Lists, Stacks, Queues; Sets and Maps); Bloch Items 10–11 (equals/hashCode). Focus on: choosing Hash vs Tree vs Linked variants by their ordering and complexity trade-offs.

    → Companion: Lesson 17 — Collections · Cheatsheet: collections

  3. Module E · Final Project Workshop — 2

    Final project progress

    Objective: assess progress and iterate on the final project with feedback.

    • Assess progress of the final project — a checkpoint against the timeline set in S24: what's done, what's at risk, and whether the scope still fits the remaining weeks. Cut features early rather than ship a broken whole.
    • Work on the final project — supervised build time with instructor and peer feedback, the moment to surface integration problems and design questions while there's still time to fix them.
    Key idea — integrate early

    Merge team modules often; surface interface mismatches before the final week.

    Key takeawayBring a running build to this session, not a folder of half-finished files — feedback on something that works is worth far more.

    Readings: bring your project; revisit the SOLID/design material (S17) and collections (S26) as your design needs. Focus on: turning feedback into a prioritised to-do list for the final stretch.

  4. Module E · Design Patterns

    Design patterns

    Objective: recognise recurring design problems and apply proven solutions.

    • Introduction to design patterns — patterns are named, reusable solutions to recurring design problems, distilled by the "Gang of Four". They give teams a shared vocabulary ("let's use a Factory here") and encode the SOLID principles in concrete form.
    • Creational patterns — control object creation: Singleton (one shared instance), Factory (decouple callers from concrete classes), Builder (assemble complex objects step-by-step, Bloch Item 2).
    • Structural patterns — compose objects into larger structures: Adapter (make incompatible interfaces work together), Decorator (add behaviour without subclassing), Composite (treat trees of objects uniformly).
    • Behavioral patterns — manage communication and responsibility: Strategy (swap algorithms behind an interface), Observer (notify dependents of changes — what JavaFX binding does internally), Iterator (traverse a collection without exposing its structure).
    Key idea — Strategy via an interface
    interface SortStrategy { void sort(int[] a); }
    class Sorter {
        private SortStrategy strategy;
        void setStrategy(SortStrategy s) { this.strategy = s; }
        void run(int[] a) { strategy.sort(a); }   // swap algorithms at runtime
    }
    Common pitfallPatterns are a means, not a goal — forcing a pattern where a plain method would do ("patternitis") adds complexity without benefit. Apply one when it solves a problem you actually have.
    Connects to…Strategy and Observer are pure polymorphism (S15) plus interfaces (S16); patterns are the open/closed and dependency-inversion principles of S17 made concrete.

    Readings: Bloch, Effective Java (Builder Item 2, static factories Item 1); GoF pattern primers. Focus on: recognising the problem each pattern solves, so you reach for the right one in the project rather than memorising UML.

MOD F

Final presentation & exam

Sessions 29–30

The course closes with project presentations, feedback and review, then the comprehensive final exam.

Module learning outcomes
  • Present and defend a working Java application to peers and instructor.
  • Demonstrate mastery of the full programme under exam conditions.
  1. Module F · Final Project Presentation

    Final presentations & course review

    Objective: showcase the final application and reflect on the course.

    • Students present final projects — a live demo plus the design rationale: walk through the class structure and the key decisions, not just the running features. Rehearse the demo so it survives the inevitable hiccup.
    • Feedback & evaluation — instructor and peer feedback feed the 25% group mark; engaging seriously with others' projects is also part of the participation grade.
    • Course review — a synthesis that connects the six modules back into one story (fundamentals → OOP → advanced APIs → design) ahead of the final exam.
    Key idea — explain your design

    A great demo explains why the design is structured as it is — tie it back to OOP and SOLID.

    Readings: review all modules. Focus on: a 3-sentence "why we designed it this way" for your project, grounded in OOP pillars and SOLID.

  2. Module F · Final Exam

    Final exam

    Objective: demonstrate comprehensive mastery of the programme.

    • Final exam — a comprehensive written/coding assessment over the whole programme (25% of the grade), mixing code-tracing, short implementation tasks and design-judgement questions. Note that a June/July re-sit, if needed, is a single comprehensive exam where continuous evaluation no longer counts and the maximum grade is capped at 8.0.
    Key idea — comprehensive review

    Cover fundamentals, the four OOP pillars, generics, collections, exceptions and design. The companion's quiz mode and cheatsheet make efficient revision tools.

    Key takeawayRevise actively: re-solve past exercises and trace code by hand. Prioritise the recurring discriminators — integer division, == vs .equals(), overriding vs overloading, checked vs unchecked, and collection/complexity choice.

    Readings: all chapters — Liang chs. 1–21; Bloch & Loy/Niemeyer for depth. Focus on: a spaced review across the whole semester, not a single cram — the material is cumulative.

    → Companion: Quiz mode · Cheatsheet

Key concepts — glossary

A quick reference to the terms that recur across the course. For worked examples, see the matching lessons and the cheatsheet.

JVM
Java Virtual Machine — executes platform-neutral bytecode; the basis of Java's portability.
JDK / JRE
JDK = JRE + dev tools (javac, jar); JRE = JVM + standard library to run apps.
Bytecode
The intermediate .class form produced by javac and run by the JVM.
API / standard library
The packaged classes Java ships with (java.util, java.io…) that you build upon.
Primitive type
One of the eight built-in value types (int, double, boolean, char…); not objects.
Reference type
A variable holding a reference (address) to an object on the heap, not the object itself.
final
Marks a variable assignable once, a method un-overridable, or a class un-extendable.
Type conversion / cast
Widening (implicit, lossless) vs narrowing (explicit (int), may lose data).
Short-circuit
&&/|| stop evaluating once the result is determined — useful for null guards.
NullPointerException
Thrown when a method or field is accessed through a null reference — Java's most common runtime error.
Class
A blueprint defining the state (fields) and behaviour (methods) of objects.
Object / instance
A concrete realisation of a class, created with new.
Constructor
A special method that initialises a new object; can be overloaded and chained.
this
Reference to the current object; disambiguates fields and chains constructors.
static
A member belonging to the class itself, shared by all instances.
Pass-by-value
Java copies each argument; for objects it copies the reference, so the same object is shared.
Heap / stack
Objects live on the heap; local variables and call frames live on the stack.
Encapsulation
Hiding internal state behind a controlled interface to protect invariants.
Invariant
A condition a class guarantees always holds (e.g. age ≥ 0), enforced in constructors/setters.
Getter / setter
Accessor methods mediating read/write access to private fields, allowing validation.
Immutability
An object whose state can't change after construction — simpler and thread-safe.
Inheritance
An is-a relationship where a subclass reuses/specialises a superclass via extends.
super
Refers to the superclass; invokes its constructor or overridden methods.
Overriding
Redefining an inherited method (same signature); dispatched at runtime.
Overloading
Multiple methods, same name, different parameters; resolved at compile time.
Polymorphism
One reference type, many runtime forms, via dynamic dispatch.
Dynamic binding
The JVM selects the method implementation based on the object's actual type.
Constructor chaining
A subclass constructor always calls a superclass constructor (via super(...)) first.
Upcasting / downcasting
Upcast to a supertype is implicit and safe; downcast needs a cast and may throw ClassCastException.
Abstract class
A class that can't be instantiated; may declare abstract methods for subclasses.
Interface
A pure contract of methods a class promises to implement; supports multiple inheritance of type.
Default method
An interface method with a body (since Java 8); enables adding behaviour without breaking implementers.
toString()
The Object method overridden to give an object a readable text representation.
instanceof
Tests an object's runtime type before a safe downcast.
equals / hashCode
Value-equality and hashing contract; must stay consistent for hash collections.
Generics
Type parameters (<T>) giving compile-time type safety and fewer casts.
Wildcard (PECS)
? extends for producers, ? super for consumers.
Type erasure
Generic type info exists at compile time only; the runtime sees raw types.
Bounded type
A constrained type parameter, e.g. <T extends Comparable<T>>, enabling calls on T.
Raw type
A generic used without a type argument (List); legal but defeats type safety — avoid.
Collection
Framework of reusable data structures: List, Set, Queue, Map.
List / Set / Map
Ordered indexed sequence / unique-element collection / key→value association.
HashMap / HashSet
Hash-table-backed structures with average O(1) lookup.
TreeMap / TreeSet
Sorted, balanced-tree-backed structures with O(log n) operations.
Iterator
An object that traverses a collection's elements without exposing its internal structure.
Big-O
Asymptotic cost notation — e.g. O(1), O(log n), O(n), O(n²).
Exception
An object representing an error; checked exceptions must be declared or caught.
Checked vs unchecked
Checked (extends Exception) must be handled/declared; unchecked (RuntimeException) signals bugs.
try-with-resources
Auto-closes resources declared in the try header.
SOLID
Five OO design principles for maintainable, flexible software.
Composition
A has-a relationship; often preferred over inheritance for flexibility.
Deep module
A narrow interface hiding substantial functionality — Ousterhout's mark of good design.
Design pattern
A named, reusable solution to a recurring design problem (Singleton, Strategy…).
JavaFX
The modern Java GUI toolkit: Stage → Scene → scene-graph nodes, with property binding.
Property binding
Linking a UI property to a model value so changes propagate automatically.
Maven / Gradle
Build tools that manage dependencies and package apps into JARs.
JAR / manifest
An archive of compiled classes; a manifest Main-Class makes it runnable with java -jar.
Lambda
A concise anonymous function implementing a single-method (functional) interface, e.g. an event handler.

Bibliography

Recommended texts. The Liang text is the primary spine of the programme.

See also: University Code of Conduct, Attendance Policy and Ethics Code (linked from the official syllabus). Full syllabus: SYLLABUS.pdf.