warming up your workspace

Object-Oriented Java

Learn Java through methods, objects and small working systems. Build growable arrays and hash maps, use generics and exception contracts, practice design patterns, compare an eager custom pipeline with Java Streams, and assemble an in-memory order engine with pricing, events and undo.

11 projects, 275 hands-on levels, run in your browser.

Syllabus

  • Foundations: code from zero in Java: Never written code before? Start here. You will learn the basics of Java, methods, variables, types, decisions, loops, and arrays. By the end you are ready for Project 1.
  • Java Foundations: Practice primitive arithmetic, text, arrays and control flow. Organize calculations into static methods, and learn where integer division, reference sharing and overflow affect results.
  • Classes & Objects: Build classes with constructors, instance state and methods. Protect invariants, copy mutable data where ownership requires it, implement equality and hashing together, and combine objects through composition.
  • Inheritance & Polymorphism: Use extends, super, abstract classes and interfaces to share behavior and express capabilities. Trace dynamic method dispatch separately from field access and static calls, and check runtime types before uncertain casts.
  • Collections from Scratch: Build small growable arrays, linked lists, chained hash maps and unbalanced search trees. Relate each operation to its storage and cost, then use java.util collections and comparators for practical tasks.
  • Generics: Use type parameters to express reusable containers and methods. Add bounds for required capabilities, apply extends and super wildcards, and examine boxing, erasure and runtime type checks.
  • Exceptions & Contracts: Specify failure behavior alongside successful results. Throw and catch appropriate types, preserve useful causes, manage resource cleanup, and compare exceptions with result objects and collected validation errors.
  • Design Patterns I: Creational & Structural: Practice builders, factories, decorators, adapters and composites through concrete object contracts. Each pattern addresses a different problem in creation, optional behavior or collaboration between interfaces.
  • Design Patterns II: Behavioral: Make behavior configurable with strategies, notify listeners with observers, and represent reversible work as commands. Model state transitions, customize template methods and implement iterators with explicit exhaustion rules.
  • Functional Java: Pass behavior through functional interfaces and compose functions. Build an eager list-backed Pipe with mapping, filtering and reduction, then compare it with lazy Java Streams and use callbacks for caching, retry and configurable processing.
  • Capstone: An Order-Processing Engine: Build an in-memory order model, pricing policies, event listeners and reversible operations. Assemble them in Engine3: register products, retain order lines, swap pricing, emit add/undo/checkout events and keep an audit. Finish with a driver that uses supplied products and requests to check out an order.

Key concepts

  • Abstract class: A class declared abstract cannot be instantiated directly. It may contain fields, constructors, concrete methods and abstract methods. A concrete subclass must…
  • Adapter: A class that implements YOUR interface and delegates to a foreign one, translating between mismatched APIs. Translation, not surgery, lets two incompatible lib…
  • Aliasing: Two variables referring to one object: int[] b = a does not copy, both names point at the same array, and a write through one shows through the other. A real c…
  • Amortized cost: The average cost per operation over a sequence, even when individual ones are expensive. Doubling-array growth copies occasionally, but the per-append average…
  • Autoboxing: Automatic conversion between a primitive and its wrapper, such as int and Integer. Unboxing null throws NullPointerException. Wrapper caching means identity ma…
  • AutoCloseable: The interface (one method, close()) that makes an object usable in try-with-resources. Implement it for files, sockets, sessions, anything that must be release…
  • Binary search tree: A binary search tree orders keys so smaller keys are in one subtree and larger keys in the other. Search follows one branch at each step and costs O(height). A…
  • Bounded type parameter: <T extends Comparable<T>> constrains T so generic code may call the bound's methods (compareTo). Bounds trade generality for capability, exactl…
  • Builder: Chained, named setters ending in build(), curing the telescoping-constructor problem and validating the whole configuration once. Lets the product stay immutab…
  • Cast: An explicit type conversion, such as (long) count or (int) 3.9. Widening int to long preserves its value; some other widening conversions, such as long to doub…
  • Checked vs unchecked: Checked exception types must be caught or declared where required by the compiler. RuntimeException and Error subclasses are unchecked. Checked and unchecked a…
  • Collector: A Collector describes how to accumulate stream elements, combine partial accumulations and finish a result. Examples include toList, joining and groupingBy wit…
  • Command: Turning an action into an object you can queue, log, and undo. Add undo() and a history stack, and you have the machinery behind every undo button and task que…
  • Comparable: Implementing Comparable gives a class a natural ordering via compareTo, which returns negative, zero, or positive. Collections.sort and TreeMap use it.
  • Comparator: An external ordering strategy passed to sort: compare two elements by ANY rule, length, then alphabetical, whatever. The library's most-used strategy objec…
  • Composite: Treating a GROUP of objects like a SINGLE one: a Bundle implements the same interface as an Item and sums its children, so bundles nest inside bundles for free…
  • Composition: Building objects FROM other objects (a Car HAS an Engine) and delegating to them. Composition is more flexible than inheritance and is the right default for mo…
  • Constructor: A declaration used during object creation to initialize an instance. Its name matches the class and it has no return type. Constructors are not ordinary method…
  • Custom exception: A domain-specific exception type (InsufficientFundsException with the missing amount) that turns a failure into structured information. Family hierarchies let…
  • Decorator: A wrapper that IS the interface and HOLDS the interface, adding behavior by delegating to the inner object. Stacking wrappers gives combinatorial features with…
  • Default method: An interface method with a body, built on the interface's abstract methods. It lets an interface evolve without breaking every implementor, and provides re…
  • Defensive copy: Copying a mutable object on the way in (constructor) and on the way out (getter) so callers cannot reach in and mutate your private state. Without it, returnin…
  • Delegation: An object forwarding a call to a held collaborator (Car.start() calls engine.start()). The mechanism behind composition, decorators, and adapters.
  • Design pattern: A named, reusable solution to a recurring design problem. Patterns are not architecture for its own sake, each one cures a specific pain you can point at.
  • Downcasting: A cast from a broader reference type to a narrower compatible type, such as (Dog) animal. A wrong non-null runtime type causes ClassCastException; casting null…
  • Dynamic array (ArrayList): A dynamic array stores elements in a backing array with a logical size and spare capacity. Geometric growth makes append amortized O(1); indexed access is O(1)…
  • Dynamic dispatch: The single most important rule: the variable's TYPE decides what you may CALL, but the object's RUNTIME type decides which override RUNS. Fields and st…
  • Encapsulation: Keeping representation details behind an API. Private fields restrict direct access, while constructors and methods decide which changes are allowed. Returning…
  • equals vs ==: For object references, == compares identity (or two null references). equals tests the equivalence defined by the receiver's class; String compares charact…
  • Exception: An object representing an exceptional condition, thrown to transfer control to a matching handler or caller. Exceptions can represent invalid arguments, missin…
  • Facade: A class offering a smaller API over collaborating components. In the final project, Engine3 coordinates catalog lookup, pricing, listeners and reversible line…
  • Factory Method: A factory creates or selects an implementation behind a return type. A simple factory can branch on a requested kind; the Factory Method pattern lets subclasse…
  • Functional interface: An interface with one abstract method contract, after the rules for inherited and Object methods are applied. It may also have default and static methods. Func…
  • Generics: Type parameters (Box , Map<K, V>) that move type errors from runtime to compile time and eliminate casts. One class, every payload type, checked by the c…
  • Hash collision: A collision occurs when distinct keys are assigned to the same hash or bucket. Equality still distinguishes them. Long chains slow our teaching map; the JDK Ha…
  • Hash map: A hash map uses a key's hash to locate a bucket, then equality to distinguish keys. Our implementation chains collisions in linked nodes and grows its buck…
  • Immutable object: An object whose observable state cannot change after construction. Final fields prevent reassignment but do not freeze referenced mutable objects; ownership, d…
  • In-order traversal: Visiting a binary tree left-subtree, node, right-subtree. On a BST this yields the values in sorted order, free sorting from the structure.
  • Inheritance: A class may extend one superclass. It inherits accessible members according to Java's access rules, but not constructors or private members; package access…
  • Instance member: A field or method that belongs to each OBJECT: every instance carries its own copy of instance fields, and instance methods operate on this . The default, and…
  • instanceof: Tests whether an object is (a subtype of) a given type before casting. Modern Java fuses the check and cast into a pattern variable: if (a instanceof Dog d) bi…
  • Integer division: Dividing two ints discards the remainder and truncates toward zero: 7 / 2 is 3, not 3.5. The remainder lives in the % operator. A frequent source of off-by-fra…
  • Integer overflow: Integer arithmetic can exceed its type's range and wrap without throwing. For example, Integer.MAX_VALUE + 1 becomes Integer.MIN_VALUE. Widen an operand be…
  • Interface: A pure capability contract: 'any class that does this'. A class may implement many interfaces (where it can extend only one class), and default methods…
  • Invariant: A condition intended to hold at an object's observable boundaries, such as a nonnegative balance. Constructors establish it and operations preserve it. Val…
  • Iterable: Iterable supplies iterator(), allowing enhanced for loops over its values. A reusable collection typically returns a fresh independent iterator for each traver…
  • Iterator: An Iterator exposes hasNext and next to step through a sequence. Repeated hasNext calls should not consume elements; next throws NoSuchElementException after e…
  • Lambda: An expression that supplies an implementation for a compatible functional interface. Its target type gives parameter and result types: x -> x * 2 can implem…
  • Lazy evaluation: Deferring expensive work until (or unless) it is needed, by passing a Supplier instead of a value. getOrCompute returns the cache without ever calling the supp…
  • Linked list: Nodes pointing at nodes: O(1) prepend, but O(n) to walk to an index. Insert and delete are cheap once you hold the node, the trade-off against the array's…
  • Load factor: The ratio of entries to buckets. A map can compare this ratio with a configured threshold to decide when to grow; 0.75 is the usual JDK HashMap default thresho…
  • Memoization: Caching a function result by its input so later calls can reuse it. This is useful when repeated inputs should produce the same result and cache lifetime is ap…
  • Method overloading: Several methods sharing one name, distinguished by their PARAMETER types. The compiler picks the match at compile time by the static argument types, this is re…
  • Method overriding: A subclass redefining an inherited method with the same signature. @Override asks the compiler to verify the signature matches. Unlike overloading, overriding…
  • Method reference: A shorthand for a lambda that just calls an existing method: String::toUpperCase is s -> s.toUpperCase() . Cleaner than the equivalent lambda when no extra…
  • Node: A small object holding a value and one or more links (next, left, right). Nodes are the building blocks of linked lists and trees; rewiring their links is &#39…
  • null: The null reference does not refer to an object. Dereferencing it usually throws NullPointerException; comparing it with == is allowed. Each API should state wh…
  • Object (the root): Every class extends Object, so any reference fits an Object variable and inherits equals, hashCode, toString, and getClass. The top of the type hierarchy.
  • Observer: Publish/subscribe: a subject broadcasts changes to whoever subscribed, without knowing who they are. The wiring inside every UI toolkit and event bus; listener…
  • Optional: Optional represents either a non-null value or absence. Methods such as map and orElseGet let callers handle absence explicitly. It is a design choice for suit…
  • PECS: Producer Extends, Consumer Super: use ? extends T for a source you read from, ? super T for a sink you write to. The mnemonic that makes wildcard signatures (l…
  • Polymorphism: One reference type, many runtime shapes: an Animal variable can hold a Dog or a Cat, and each answers sound() in its own voice. Dispatch is the mechanism that…
  • Primitive type: One of Java's eight primitive types: byte, short, int, long, float, double, char and boolean. A primitive variable stores a value rather than an object ref…
  • reduce / fold: A fold combines elements with an accumulated result. Our Pipe.reduce performs a left-to-right fold starting from the supplied seed. Java Stream reductions may…
  • Reference type: A class, interface or array type. A variable of a reference type can hold a reference to a compatible object or null. Copying the reference does not copy the o…
  • Rehashing: Rebuilding bucket placement when the bucket array changes size. Existing entries must be assigned using the new bucket count. Growth controls occupancy but can…
  • Singleton: One shared instance, enforced by a private constructor and a static accessor. Useful for genuinely single resources, dangerous as hidden global state.
  • State pattern: One class per mode, each knowing its own transitions and behavior, replacing mode-flag if-chains. The order knows whether it can be cancelled; the StatefulOrde…
  • static: A static field or method belongs to the CLASS, not to any instance: one shared copy, callable without an object. Constants, factories, and utility helpers are…
  • Strategy: Injecting the algorithm as an object so it can be swapped at runtime: pricing rules, comparators, policies as plug-ins. Every Comparator is a strategy.
  • Stream: A declarative pipeline over a sequence: filter, map, reduce, collect, replacing explicit loops. Lazy and composable; intermediate operations build the pipeline…
  • String immutability: A String object's character sequence cannot change. Methods return a result without changing the receiver; an unchanged result may reuse the same object. R…
  • StringBuilder: A mutable character buffer for building strings efficiently: append in place, call toString() once at the end. The idiomatic fix for loop concatenation.
  • super: Use super(...) to invoke a superclass constructor and super.method(...) to invoke an accessible superclass implementation. In the conventional constructors use…
  • Template Method: A final method locks the algorithm's skeleton while abstract steps (and optional hooks) let subclasses fill the gaps. Subclasses customize the parts, never…
  • The equals contract: equals() must be reflexive, symmetric, transitive, consistent, and false for null. Override it for value semantics following the recipe: identity shortcut, ins…
  • The hashCode contract: Equal objects must have equal hash codes; unequal objects may share one. If equals changes a class's equality rule, ensure hashCode follows that same rule.…
  • this: A reference to the current object inside an instance method or constructor. this.field disambiguates a field from a shadowing parameter; this(...) chains to an…
  • toString: Overriding toString() controls how an object prints in logs, debuggers, and string concatenation. A good toString turns 'Object@1a2b' into something hu…
  • TreeMap: A sorted map backed by a balanced binary search tree: keys stay in order, lookups are O(log n), and range queries are efficient. Trades HashMap's O(1) for…
  • try / catch / finally: A try block runs code; matching catch clauses handle thrown exceptions, with more specific handlers before broader ones. A finally block normally runs when con…
  • try-with-resources: try (Resource r = ...) auto-closes anything AutoCloseable when the block exits, normally or by exception, in reverse order of opening. The modern replacement f…
  • Type erasure: Java checks generic type arguments at compile time and erases most of them from executable types, inserting casts where needed. List and List share one runtime…
  • Utility class: A class that is just a bundle of static helpers with no instances (java.lang.Math is one). A private constructor signals that you should call its methods, not…
  • Validation pattern: Validation checks whether inputs satisfy a contract. A result object or list of errors can represent expected invalid user input; exceptions can report failure…
  • Value object: A small immutable object defined by its data, not its identity: two Money objects with the same cents are equal. Proper equals/hashCode/toString make it behave…
  • Varargs: A trailing int... nums parameter lets a method accept any number of arguments; inside, it is simply an array. Convenient, but only one varargs parameter, alway…
  • Wildcard: A wildcard denotes an unknown type argument. From List you can read Number values but cannot add an arbitrary Number; adding null is permitted. List accepts In…