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).
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.
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.
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.
Assessment
Continuous evaluation combines two exams, individual and group project work, and participation. The weights below sum to 100%.
Final Exam
Deliverable: comprehensive written/coding exam (Session 30).
Evaluated on: the full programme — language fundamentals, OOP, generics, collections, exceptions and design.
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.
Group Project
Deliverable: team-built Java application, introduced S24 and presented S29.
Evaluated on: design quality, modularity, use of OOP & collections, and teamwork.
Individual Assignments / Projects
Deliverable: individual project (introduced S19) plus in-class exercises.
Evaluated on: working code, idiomatic Java, and adherence to encapsulation/SOLID.
Participation & Attendance
Deliverable: active engagement in live sessions, peer reviews and discussion.
Evaluated on: contribution quality and presence (see attendance rule).
| Component | Weight | Deliverable format | What earns marks (criteria) |
|---|---|---|---|
| Intermediate Exam | 25% | 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 Exam | 25% | 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 Project | 25% | 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 / Projects | 15% | 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 & Attendance | 10% | 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.
Java foundations & elementary programming
Sessions 1–9From "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.
-
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.printlnwrites a line to standard output. The ceremony (a class wrappingmain) is the first hint that in Java, everything lives inside a class.
Key idea — bytecode & the JVMSource →
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 (Hello→Hello.java), and Java is case-sensitive —mainwith 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
-
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 & executing —
javac Hello.javaproducesHello.class(bytecode), andjava Hellolaunches 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 layeringJDK ⊃ 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 meansJAVA_HOME/PATHpoints at the wrong (or no) JDK. Confirm withjava -versionandjavac -versionbefore 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
- Language Specification, API, JDK, JRE & IDE — the Language Specification is the precise rulebook for syntax and semantics; the API is the vast standard library (
-
Variables, input & data types
Objective: read console input and declare/assign variables with the right types.
- Reading console input — a
ScannerwrappingSystem.inturns raw keyboard bytes into typed values via methods likenextInt()andnextLine(). 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
finalmakes 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 = 5works). Recognising this explains idioms likewhile ((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 inputScanner in = new Scanner(System.in); int age = in.nextInt(); final double PI = 3.14159;Common pitfallMixingnextInt()withnextLine()leaves the trailing newline in the buffer, so the nextnextLine()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 asfinal, 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
- Reading console input — a
-
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 (100Lforlong,3.14fforfloat). An un-suffixed decimal literal is adouble; an integer literal is anint. - 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 assignment —
x += 3is shorthand forx = x + 3and quietly performs a narrowing cast, sobyte b = 10; b += 5;compiles whereb = b + 5;would not. - Increment / decrement —
++iincrements 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 (
int→double) happens implicitly because no information is lost; narrowing (double→int) needs an explicit cast(int)and truncates the fraction, so it can silently lose data.
Key idea — integer vs floating division5 / 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 divisionCommon pitfalldoublecan't represent every decimal exactly, so0.1 + 0.2 != 0.3. Never test floating values with==; compare within a small tolerance, and useBigDecimalfor 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
- Numeric types & operators — integer types (
-
Selections — boolean logic, if & switch
Objective: branch program flow with boolean expressions and selection statements.
- boolean types, values & expressions —
booleanholds onlytrue/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-way —
ifchooses one branch,if-elsechooses between two, and chainedelse ifhandles 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 writeif (s != null && s.length() > 0). - Conditional (ternary) operator —
cond ? a : bis an expression returning one of two values, handy for concise assignments likeint max = a > b ? a : b;. - switch statements — dispatch on a discrete value (int, char, String, enum). Classic
switchfalls through until abreak; the newer arrow form (case X -> …) avoids fall-through entirely. - Common errors & pitfalls —
=(assignment) vs==(comparison), the dangling-elsebinding to the nearestif, and comparing floating-point values with==.
Key idea — short-circuit evaluationa && bnever evaluatesbifais 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 (especiallyString) 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
- boolean types, values & expressions —
-
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;
breakexits early andcontinueskips to the next pass. Guard against off-by-one errors and conditions that never become false.
Key idea — loop choice & complexityA 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)
-
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
voidmethod 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-timeint 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 callerCommon 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
-
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
lengthfield (not a method). Indices run0..length-1. - Processing arrays & foreach — a classic
forwith 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()orSystem.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.sortandArrays.binarySearchimplement 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 complexityLinear 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 pitfallReadingarr[arr.length]throwsArrayIndexOutOfBoundsException— the last valid index islength-1. And callingbinarySearchon an unsorted array returns a meaningless result, not an error.Connects to…Arrays' fixed size motivates the resizableArrayListin 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)
- 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
-
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 — checkpointThis 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
Object-oriented programming core
Sessions 10–18The 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
thisreference. - 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.
-
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;
newcreates 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
nullmeans "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
thisdenotes 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 staticclass Counter { static int total = 0; // shared by all instances int id; // one per object Counter() { id = ++total; } }Common pitfallCalling a method on anullreference throwsNullPointerException— the most common Java runtime error. Initialise references before use and check fornullat 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
- Defining classes & objects — a class is a blueprint describing state and behaviour;
-
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) andpublic(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-
finalfields can never change after construction, which makes it automatically thread-safe, freely shareable and safe to cache.Stringand 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
NullPointerExceptionfamily of bugs.
Key idea — copying a reference ≠ copying the objectint[] a = {1,2}; int[] b = a; // same array b[0] = 9; // a[0] is now 9 tooCommon 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 whyprotectedmatters 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
- Visibility modifiers — four levels control access:
-
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 immutabilityStrings never change in place; "modifying" one creates a new object. Use
StringBuilderfor 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 compareCommon pitfallBuilding a string inside a loop with+=creates a new object every iteration — O(n²) work. Use aStringBuilderand calltoString()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
-
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
privateand 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
finalclass, all-finalprivate 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 boundaryprivate 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. aListor 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
-
Inheritance
Objective: reuse and specialise behaviour through subclassing without breaking the base.
- Superclasses & subclasses —
extendscreates 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 keyword —
super(...)invokes a chosen superclass constructor, andsuper.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
@Overrideso 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, inheritingtoString(),equals()andhashCode(); overridingtoString()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
- Superclasses & subclasses —
-
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();runsDog's version. - Casting objects — upcasting a subtype to a supertype is implicit and always safe; downcasting needs an explicit cast and can throw
ClassCastExceptionif the object isn't really that type, so guard it withinstanceof. - Object.equals() — defines logical (value) equality and must obey the reflexive/symmetric/transitive/consistent contract; whenever you override
equalsyou must also overridehashCodeconsistently. - 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 dispatchAnimal a = new Dog(); a.speak(); // "Woof" — resolved at runtime, not compile time if (a instanceof Dog d) d.fetch(); // safe downcast via patternCommon pitfallOverridingequalsbut nothashCode(or vice-versa) breaksHashSet/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
-
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
Shapecan compute itsarea(). - 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
defaultandstaticmethods); a class canimplementmany 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
defaultmethods, the implementing class must override the method and may delegate withInterface.super.method().
Key idea — program to an interfaceinterface 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 classCommon 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
- Abstract classes — declared
-
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 modulesThe 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)
-
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 — checkpointA 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
Projects, build tooling & exception handling
Sessions 19–21From 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.
-
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 codeSketch 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.
-
Build tooling & packaging
Objective: turn source into a versioned, distributable artifact.
- Building with Maven/Gradle — these tools replace manual
javaccommands with a declarative build: you state dependencies and the tool resolves, compiles, tests and packages through a defined lifecycle (compile→test→package). This makes builds reproducible across machines. - Creating .jar files — a JAR bundles compiled
.classfiles (and resources) into one archive; adding a manifest entry naming theMain-Classmakes it directly runnable withjava -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 JARmvn package # → target/app-1.0.jar java -jar app-1.0.jar # runs the Main-Class from the manifestCommon pitfalljava -jarfailing with "no main manifest attribute" means the manifest lacks aMain-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.
- Building with Maven/Gradle — these tools replace manual
-
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 types — checked exceptions (extend
Exception) must be declared or handled and model recoverable conditions; unchecked ones (RuntimeException) signal programming bugs;Errorrepresents JVM-level failures you shouldn't catch. - Declaring, throwing & catching —
throwraises an exception,throwsdeclares it on a method, andtry/catch/finallyhandles it;finallyalways 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-resourcestry (Scanner s = new Scanner(file)) { // s is closed automatically, even on exception } catch (FileNotFoundException e) { System.err.println("Missing file: " + e.getMessage()); }Common pitfallAn emptycatchblock (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 throwIllegalArgumentException; 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
finallycleanup.→ Companion: Lesson 18 — Exception handling
JavaFX & interactive applications
Sessions 22–24Building 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.
-
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 aScene, 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
ImageViewhandling sizing and fitting within the scene graph.
Key idea — Stage → Scene → node graphButton 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 aTask/background thread, with UI updates marshalled back viaPlatform.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
- Introduction to JavaFX — JavaFX models a GUI as a tree: a
-
JavaFX controls & multimedia
Objective: build a complete interactive UI with the standard controls and media.
- Label & Labeled — display-only nodes for text and graphics;
Labeledis 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
ToggleGroupenforce 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;
ListViewis typically backed by anObservableListso 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 UIsControls 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…ObservableListbridges 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
- Label & Labeled — display-only nodes for text and graphics;
-
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 oneSplit 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.
Generics, collections & design patterns
Sessions 25–28The 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.
-
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 anInteger. - Generic methods & classes — a type parameter
<T>stands in for a type chosen by the caller; the same code then servesBox<String>,Box<Integer>and so on without duplication. - Type parameters & wildcards —
?is an unknown type;? extends Taccepts T or any subtype (read from it), and? super Taccepts 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 genericmax. - 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 testx 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 runtimeCommon pitfallFalling back to a rawList(no type argument) silences the compiler's checks and reintroduces the cast bugs generics were meant to prevent. Always parameterise; useList<?>if the element type is genuinely unknown.Connects to…Bounded types rest on theComparableinterface 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
- 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.
-
Sets & maps (hash tables)
Objective: pick the right collection and understand its performance characteristics.
- Sets & HashSets — a
Setmodels a collection with no duplicates;HashSetimplements it over a hash table for average O(1) membership tests, whileTreeSetkeeps elements sorted at O(log n) andLinkedHashSetpreserves insertion order. - Sets vs lists — use a
Listwhen order and duplicates matter and you index by position; use aSetwhen you only care about membership and uniqueness. Choosing the right one is both a correctness and a performance decision. - Maps in Java — a
Mapassociates unique keys with values;HashMapgives average O(1)get/put,TreeMapkeeps keys sorted (O(log n)), andLinkedHashMapremembers insertion order. Maps are the workhorse for lookups and counting. - Singleton & unmodifiable collections/maps — factory methods like
List.of,Set.of,Map.ofandCollections.unmodifiableListproduce 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 consistentCommon pitfallUsing a mutable object as aHashMapkey (or one with a brokenhashCode) makes entries "vanish" after the key changes. Use immutable keys and keepequals/hashCodein 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
- Sets & HashSets — a
-
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 earlyMerge 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.
-
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 interfaceinterface 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.
Final presentation & exam
Sessions 29–30The 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.
-
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 designA 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.
-
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 reviewCover 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
.classform produced byjavacand 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
nullreference — 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
Objectmethod 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)
? extendsfor producers,? superfor 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
tryheader. - 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-Classmakes it runnable withjava -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.
-
Y. Daniel Liang (2024). Introduction to Java Programming and Data Structures, 13th ed. Pearson. ISBN 0138123536.
Primary text — seamlessly integrates programming, data structures and algorithms; aligned to recent Java. The chapter spine for nearly every session.
Sessions 1–30 (core reference)
-
Josh Bloch (2017). Effective Java, 3rd ed. Addison-Wesley Professional. ISBN 0134686042.
The definitive Java best-practices guide — items on immutability, equals/hashCode, generics, exceptions and API design.
Sessions 11–28 (OOP, generics, collections, exceptions, design)
-
Marc Loy, Patrick Niemeyer, Daniel Leuck (2023). Learning Java, 6th ed. O'Reilly. ISBN 9781098145538.
An accessible introduction to real-world Java programming — useful for the toolchain, JavaFX and packaging context.
Sessions 1–2, 20, 22–23 (setup, tooling, JavaFX, packaging)
See also: University Code of Conduct, Attendance Policy and Ethics Code (linked from the official syllabus). Full syllabus: SYLLABUS.pdf.