
Explore the evolution of Java from nine to seventeen, focusing on productivity, memory footprint improvements, faster startup, and tools that enhance performance and reliability.
Explore Java releases from nine to seventeen, including the module system, local variable type inference, text blocks, switch expressions, sealed classes, and migration tools, with practical examples and exercises.
Students will get an understanding of the Java release schedule. There are a few changes recently announced, which we will look at in another lecture.
Choose OpenJDK for free, open source Java with GPL v2 plus classpath exception, while Oracle JDK shifts to a paid production license after Java 11.
Understand the meaning of LTS in OpenJDK and the difference between updates and support, including six-month releases and vendor options.
Java 17 announces an lts update and a no-fee license, proposing a two-year lts cadence with six-month releases, granting free use for article JDK 17 and beyond for one year.
1. The java_catching_up zip file contains source code that we will refer to throughout the course.
2. The modules_movieflix.zip and multi_modules.zip contain source code that we will refer to when we discuss modules, this is in the next section when we explore Java 9.
3. The JMH_Demo.zip contains source code that we will look at in Section 5 when we explore Java 12 and the concept of JMH.
Explore JDK nine features including collection factory methods, G1 garbage collector basics, compact strings and indefi string concatenation, the modular system with Jlink and Jshell, and stream API enhancements.
Explore creating unmodifiable collections in Java 8 and Java 9 with List.of, Set.of, and Map.of, and learn when Map.ofEntries applies.
Explore the off method for lists, sets, and maps, including unmodifiable results, no null elements, and duplicate handling with exceptions, plus space-efficient behind-the-scenes implementations.
Explore the difference between Collections.unmodifiableList as an unmodifiable view and List.of as a true unmodifiable list, including backing collection mutability and null handling.
Learn how the G1 garbage collector manages Java heap memory by dividing it into regions, balancing low latency and throughput, with a default pause goal and humongous region handling.
Explore how the G1 collector partitions the heap into eden, survivor, and old regions, evacuating eden via young collections and triggering a concurrent mark cycle at 45%.
Compact strings in JDK nine switch string data from a char array to a byte array and introduce a private byte coder field, enabling on-construction compression.
Explore the indefi string concatenation feature and how Java nine translates plus to StringBuilder appends, the role of invokedynamic in Java nine, and runtime strategies for faster, memory efficient concatenation.
Explore why modularity matters in Java by solving jar hell and classpath chaos, learn how modules encapsulate functionality, define clear dependencies, and prevent cyclic dependencies in Java 9's module system.
Define a module as a named self-describing collection of code and data with exported packages and required dependencies, and learn how a module descriptor controls visibility.
Explore how to build a simple modular application using Java nine modularization, including module-info.java, module path, and a movie recommendation example implemented in Visual Studio Code.
Declare module dependencies with requires to access other modules, such as java.logging, and export packages to enable the movie recommendation controller to log messages at runtime.
Explore automatic modules as a middle ground between unnamed and explicit modules, enabling non-modular jars to run on the module path and migrate to modular Java.
Learn why automatic modules matter when migrating from jar files to modules, enabling explicit dependencies via module path and allowing automatic modules to read all modules and export packages.
Explore named, unnamed, and automatic modules in Java, learn how to run from the module path versus the classpath, and understand how legacy jars become explicit or automatic modules.
Demonstrates a two-module Java modular app with a front end and back end, showing how requires and exports govern access to the back end's service package and encapsulation.
Enable reliable configuration by declaring module dependencies, allowing compile-time and launch-time analysis that fail fast on missing modules, while enforcing strong encapsulation and exporting only selected functionality for scalability.
Understand how Java 9 modularization encapsulates internal APIs, causing access barriers to sun.security.x509, and use the Java Dependency Analysis Tool to surface internal dependencies and replace with standard APIs.
Learn how Jlink, the Java linker, builds a tailored runtime image containing only the modules your application needs, reducing size and improving startup time.
Learn to use jlink to build a custom runtime image for a modular application with a single module, including only the required modules.
Learn to use jlink to build a custom runtime image that includes two modules, managing module path and dependencies from a mods folder and producing a lean, runnable application.
Explore jshell, the read-evaluate-print loop bundled with the JDK since Java 9, for interactive Java snippets. Prototype and get immediate feedback, since jshell is not an IDE.
Explore jshell commands and features for prototyping Java code, including lambda expressions and method references, with saving, opening, editing, listing, and help, and immediate feedback without a class setup.
Explore how private methods in interfaces, introduced in Java 9, reduce duplication by refactoring common logic from default methods, while preserving interface evolution and encapsulation.
Explore how to use the stream API and the takeWhile method to extract stock names with values at most 500 from a sorted list of stock objects.
Learn how the takewhile method in the stream API extracts stock names with values of 500 or less from a sorted list, short-circuiting when a predicate fails, unlike filter.
Explore how dropWhile processes a sorted stock list to remove values 500 or less and return stocks over 500, and compare it with takeWhile and filter.
Explore Java 9 stream iterate overload with a predicate to produce and terminate streams using seed, predicate, and unary operator, and learn takewhile with primitive streams.
Explore the stream API enhancement with ofNullable to safely handle null values. Learn how flatMap and non null filtering build robust results from a hash map.
Learn how Java 9 changes the semantics of deprecation, including removal eligibility, the deprecated annotation and the deprecated Javadoc tag, and how to migrate deprecated APIs before removal.
Explore Java nine deprecations, including boxed primitive constructors, autoboxing via valueOf, deprecation of the defined class method, unsafe class risks, and finalization with cleaner and phantom references.
This lecture includes a downloadable PDF guide that introduces the Flow API, a powerful feature added in Java 9 to support reactive programming.
What you’ll find inside:
- A clear explanation of the Flow API and why it was introduced
- The four core interfaces: Publisher, Subscriber, Subscription, and Processor
- Practical examples using `SubmissionPublisher`
- How the Flow API connects with libraries like RxJava and Project Reactor
- Key takeaways to help you build a strong foundation for modern Java development
Even though you may not use the Flow API directly in day-to-day coding, it provides the foundation for many reactive libraries and frameworks.
Download this PDF and keep it as a handy reference — it will strengthen your understanding of Java’s evolution and help you in both learning and interviews.
Explore local variable type inference and the or else throw method in optional. Learn to create unmodifiable collections and enable application class data sharing to improve startup time on docker.
Explore local variable type inference and how the compiler infers type by left side and right side, with examples like movies, name, and product search criteria.
Local variable type inference in java does not change its static typing; the compiler infers types like string for name, and bytecode remains unchanged with var, so no runtime overhead.
Learn where local variable type inference with var can be used (initializers, for loop indices, try-with-resources) and where it cannot (fields, method parameters, return types, catch blocks).
Explains local variable type inference using var, showing when it improves readability and when it can hinder understanding, with concrete examples on for loops, maps, and literals.
Explore advanced local variable type inference with practical examples, showing how var affects list element types, readability, and variable naming in refactoring, including movie search criteria and vowel lists.
Explore local variable type inference through examples involving maps and lists, and compare explicit types with var to reveal scope and correctness considerations.
Harness local variable type inference with var to simplify a stream-based approach that groups by movie name, finds the most watched movie, and refactors for readability.
Local variable type inference reduces boilerplate and improves readability; use it with local variables, for loop initializers, and try-with-resources, but avoid fields, method parameters, constructor parameters, and return types.
Explore the orElseThrow method in the Optional class, introduced in JDK ten, to return a value or throw NoSuchElementException. See why get can mislead and orElseThrow improves readability over isPresent.
Learn how the copyOf method creates unmodifiable lists, sets, and maps, providing immutability and a read-only view into the original data.
Learn how application class data sharing enables sharing of application and library classes. Build a shared archive from the class list and start instances with it.
Boost startup time and reduce memory usage by sharing application class data across JVMs. Dynamic archives in Java 13 enable this sharing by recording loaded classes into a shared archive.
Investigate how the JVM now recognizes Docker container constraints via cgroup settings to adjust heap and memory usage, with backport fixes to Java 8 update 191.
Explore Java 11 features, including the Http client with Http2 and WebSocket non-blocking semantics, local variable syntax for lambda parameters, and new string methods like repeat, isBlank, strip, and lines.
Explore the Java http client API introduced in JDK 11 and compare it with the legacy HTTP URL connection, highlighting its fluent, asynchronous design with HTTP/2 and reactive streams integration.
Explore the http client api introduced in JDK 11, including http client, http request, http response, and body handlers; learn the builder pattern and synchronous vs asynchronous sending.
Create an HttpClient with a 3-second timeout, send an async GET request, and handle the string response using CompletableFuture, thenApply, exceptionally, and thenAccept, illustrating the reactive streams behind the HttpClient.
Learn local variable type inference for lambda parameters using var, enabling annotations on parameters and aligning with local variable syntax introduced in JDK 10 and extended in JDK 11.
Discover how the string API repeat method in JDK 11 repeats a string n times and returns an empty string for zero, using a byte array and System.arraycopy.
Learn how the isBlank method (JDK 11) detects empty or whitespace strings, and how it contrasts with isEmpty and trim using Unicode aware isWhitespace.
Learn how the strip method handles unicode whitespace in java, using character.isWhitespace, and compare it with strip trailing, strip leading, and the traditional trim behavior.
Demonstrate the difference between trim and strip on a text with whitespace, showing trim returns length 11 while strip returns 5, and illustrate strip trailing and leading variants.
Explore the string API in JDK 11 by comparing lines and split, showing how lines returns a lazy stream of lines and enables faster processing across platforms.
Explore the epsilon garbage collector, a no-op GC that does not reclaim memory. Use it for performance analysis, memory pressure testing, and ultra latency sensitive applications.
Explore the z gc, a scalable, low-latency concurrent garbage collector that runs with application threads, delivers sub-10 ms pauses, and uses colored pointers and load barriers to relocate objects safely.
Understand how JDK 11 removes Java EE modules such as Jax-ws, JAXB, and Corba, and what this means for migrating apps that rely on these APIs.
Analyze why applets and browser plugins faced security risks and were phased out, with Nashorn deprecated in JDK 11. Consider GraalVM JavaScript as the modern alternative on the JVM.
Analyze deprecation of JavaFX and OpenJFX as an open-source project, while Java is no longer bundled in JDK 11+ and modules are fetched via Maven Central with Maven or Gradle.
Demonstrates launching single-file Java programs without compilation, showing in-memory compilation, top-level main class requirements, and how arguments produce personalized output like Hello Chris Ron.
Use the shebang to specify the interpreter and run a single-file Java source as a script, guided by the Java launcher’s source-file mode introduced since Java 11.
Explore the readString and writeString methods in the files class (JDK 11) to read a file into a string and write string content.
Explains how the not method in the predicate interface improves readability by filtering non-blank lines from a file using streams, method references, and optional type casting.
Explore how JDK Flight Recorder profiles the JVM with low overhead, capturing memory, threads, and I/O, start and stop recordings, and analyze the binary recording files with visualization tools.
Explore JDK mission control, an open source tool for monitoring, profiling, and troubleshooting Java applications in production, with JFR flight recordings, real-time VM analysis, and automated diagnostics.
Learn how to use the JDK mission control user interface to connect to a Java program, view live statistics, and diagnose a deadlocked multithread scenario.
Start a flight recording with java -X:StartFlightRecording, dump on exit, or jfr start with the pid, then stop to dump, and view thread dumps and deadlock in Mission Control UI.
Explore jdk 12 features, including compact number formatting, files mismatch, Java micro benchmarking harness, Maven setup, Shenandoah garbage collector, Tin Collector with keying, and preview switch expressions.
Explore compact number formatting in Java using CompactNumberFormat to display numbers in short forms like 1 k, 100 M, or 1 B, with locale awareness and rounding options for UI.
Learn how the teeing collector merges two downstream collectors to process a stream in parallel, using joining and counting to produce a sentence and its total word count.
Explore the Files API mismatch method in JDK 12, which compares two files and returns -1 for identical content, or the first mismatched byte index, or the smaller file size.
Explore preview features in Java with switch expressions from JDK 12. Learn how to enable previews, compile and run, and see how switch expressions improve readability.
Shenandoah, introduced in Java 12, reduces GC pause times by evacuating concurrently. It uses a forwarding pointer, or brooks pointer, to relocate objects without stopping the program.
Explore the string.indent method added in jdk eight, indenting every line by a given number of spaces; see examples with a poem and a json string, including negative values.
Use the string class transform method to drop the first word, uppercase each remaining word’s first letter, and append three dots. Compare two solutions and highlight a fluent, functional approach.
Learn to use the Java Microbenchmark Harness to accurately compare code blocks, account for the JVM warmup, HotSpot compilation, and multithreading.
Create a maven benchmark project with a maven archetype and a My Benchmark class annotated @Benchmark; build with mvn clean verify and run via java -jar target/benchmarks.jar to measure throughput.
Learn Java microbenchmarking with the Java Microbenchmark Harness (JMH) by comparing two ArrayList benchmarks with and without an initial size, and observe how forking, warmups, and measurements affect throughput.
Micro benchmarking is hard; leverage the Java Microbenchmark Harness (JMH) for reliable results, then use profilers for insights in latency-sensitive or library development work.
Explore JDK 13 changes, including reimplemented legacy socket API, dynamic archives for application class data sharing, text blocks, new string methods, and switch expression and Z garbage collector enhancements.
Explore how Java 13 re-implements the legacy socket api with a drop-in socket impl, uses java.util.concurrent logs, and improves compatibility with Project Loom fibers.
Discover dynamic archives and dynamic class data sharing, extending app cds to create and reuse a shared archive written at exit for runs on host with default and custom loaders.
Explore text blocks, a JDK 13 preview feature using three double quotes as opening and closing delimiters to simplify multi-line strings, with plans for permanence in Java 15.
Explore how the stripIndent method in JDK 13 cleans incidental whitespace from multi-line strings, preserving the intended indentation via text blocks and the string lines method.
Apply the translate escapes method to convert escape sequences in external file lines into proper strings, then group non-blank lines by length and present translated results.
Explore string interpolation and how the static format method and the instance formatted method format strings, including text blocks, and how strip indent and translate escapes enhance readability.
Explore switch expressions and their evolution from JDK 12 preview to JDK 14 permanent feature, noting the yield keyword introduced in JDK 13 and switch as an expression.
Explore how the z garbage collector enhancements in Java 13 return uncommitted heap memory to the operating system, shrinking the heap and improving performance.
Explore Java 14 features like switch expressions and helpful null pointer exceptions, and review changes in garbage collection. Learn about records for concise data declarations and pattern matching.
Compare traditional switch statements with Java's modern switch expressions, now a standard feature since Java 14. Learn about arrows, no breaks, default cases, and value assignment.
Explore modern switch expressions in Java, returning values with yield and comparing them to traditional switches, while inspecting variable scope and a budget discount example.
Explore vintage switch statements versus modern switch expressions, featuring arrow labels, comma-separated cases, and yielding values, while noting mixing label styles is not allowed.
Explore helpful null pointer exceptions in JDK 14 that pinpoint the null-causing variable, and learn about overhead and security trade-offs.
Review updates to Java 14 garbage collectors, including G1's NUMA-aware memory allocator and the deprecation of CMS, plus Z GC's cross-platform port with sub-10 ms pauses and multi-terabyte heaps.
Records provide a compact syntax for lean data carrier classes, reducing boilerplate and enabling immutable data with auto generated methods. A compact constructor supports validation.
Explore pattern matching for instanceof in JDK 14, which combines type testing and binding into a step, reducing boilerplate and casting, with a preview status and future switch expression use.
Explore changes in JDK 15 such as text blocks and compile-time processing, review null pointer exceptions improvements, and survey records, local records, sealed classes and interfaces, and garbage collector changes.
Learn how text blocks, permanent since JDK 15, implement multi-line strings, compare them with traditional literals, and identify when to use text blocks for readability.
Learn how text blocks in Java replace verbose string literals for HTML, XML, JSON, and SQL snippets, improving readability and reducing escapes and incidental whitespace.
Explore text blocks in Java and learn two escape sequences: the line terminator to suppress a newline and the explicit space escape sequence to preserve trailing spaces.
Explore how text blocks are compiled: normalize line terminators, strip incidental whitespace, and interpret escapes. Use text blocks to improve readability, and reserve traditional literals for short, single-line strings.
Explore helpful null pointer exceptions that pinpoint the exact null, such as address in customer, with plus show code details, Java 14, and default in Java 15; disable with minus.
Refactor plain data wrappers into records to cut boilerplate and rely on compiler-generated equals, hashCode, toString, and immutable data carriers with accessors for name, latitude, and longitude.
See how a local record, defined inside a method, aggregates a movie and its score to produce the top three via a stream pipeline.
Explore how sealed classes restrict subclassing to permitted types, using a payment example with cash and card payments in Java 15 preview.
Examine how sealed classes constrain extensibility by listing permitted subclasses, with examples like payment, cash payment, and card payment, and contrast sealed, non-sealed, and final modifiers for secure, well-typed hierarchies.
Explore JDK 15 changes, including the GCC garbage collector becoming a permanent feature with max heap up to 16 TB and Shenandoah moving to product status as G1 remains default.
Explore JDK 16 changes, including records, Stream API enhancements like map and flatMap, and new list methods, and pattern matching scope, plus sealing internals, jpackage packaging, and value-based class warnings.
Explore how Java records serve as immutable data carriers, with id, name, and description, public accessors, canonical and compact constructors, and auto-generated equals, hashCode, and toString.
Create a popular items record from a map entry by streaming entrySet, using the canonical constructor with category and percent, optionally override toString, and collect results into a list.
Learn how to use a record as a compound key in a map by combining a customer and location, leveraging immutability and proper equals and hash code for accurate lookups.
Use records to return multiple values in a single pass, demonstrated by min and max gross earning movies via a min-max record, comparator, and downstream collectors.
Explore how records serve as data transfer objects and return multiple values, a min-max movie example, and note their use in stream operations and as compound map keys.
Explains how to use the stream flatMap to extract the cast from Martin Scorsese movies, showing a one-to-many transformation and flattening into a single list, contrasting with map.
Discover map multi, a JDK 16 stream method for one-to-many transformations with a single flattened stream, unlike flatMap, and learn when an imperative approach suits emission of movie cast.
Refactor mapMulti by explicit types or a consumer, using a method reference for getStar. Use toList in JDK 16 to yield an unmodifiable list rather than collect.
Delve into pattern matching for instanceof, the type pattern feature now permanent in Java 16, and refactor code to bind values with a pattern variable while eliminating casting boilerplate.
Explore pattern matching for instanceof, showing how binding variables gain scope within control flow and how a phone number equals method can be refactored into a concise type-pattern check.
Explore how pattern matching evolves beyond instanceof, enabling switch expressions and case labels, deconstruction of records, and array patterns to write clearer, type-safe code.
Design an expression system with sealed types and records, using constant, add, multiply, and negate to implement evaluate logic.
Explore how the JDK's internal elements are strongly encapsulated by default via modules. Shift toward standard APIs like the Java Time API and method handles.
Learn how jpackage packages self-contained Java applications, bundling jars with the runtime to produce installable bundles (MSI, DMG, deb, rpm) for Windows, macOS, and Linux, with no cross-platform deployment.
Demonstrates packaging a maven-based Java application into a self-contained installer using jpackage, including input target, main jar, and app version, and shows how to install and uninstall on Windows.
Discover how Java 16 introduces value-based classes and deprecates public constructors of primitive wrappers in favor of factory methods. Understand the Valhalla motivation and synchronization warnings on value-based instances.
Explore JDK 17, a long-term support release, highlighting strong encapsulation of internal APIs and new classes, interfaces, and enums. Discover pattern matching for switch, yielding concise case labels.
Explain how sealed classes let you control permitted subtypes, enabling secure hierarchies and accurate domain modeling while highlighting compile-time checks on conversions.
Explore how strong encapsulation of JDK internals tightens security and maintainability in JDK 17, moving developers toward standard APIs and away from internal elements, with warnings and exceptions guiding migration.
Explore the removals and deprecations in Java 17, including the legacy security manager deprecated for removal, the applet API deprecated for removal, and the removal of the RMI activation mechanism.
Explore pattern matching for switch as a preview in JDK 16 and beyond, using type patterns, guarded patterns, and null-aware cases to simplify switch expressions and improve readability.
Learn to compile pattern matching for switch with a Java 17 preview via Maven, enabling preview in pom.xml and using javac with release 17 on the command line.
Explore pattern matching for switch in Java 17, applying it to switch statements for enhanced type checking, exhaustive cases, default branches, and guarded patterns.
Java has changed more since Java 9 than at any time in its history. From modules and `var` to records, sealed classes, text blocks, and switch expressions — the language is evolving fast, and keeping up can be a challenge.
This course gives you a step-by-step path from Java 9 through Java 17, making it simple to catch up with all the modern features while building confidence through hands-on exercises.
By the end of this course, you will:
Understand how Java has evolved beyond Java 8
Master new language features like modules, var, records, sealed classes, text blocks, and switch expressions
Explore new garbage collectors, library enhancements, tools, and deprecations
Learn how the new JDK release cycle impacts developers
Gain confidence with practical exercises and solutions
Be better prepared for interviews and real-world projects
Starting from Java 9, we will incrementally move up to Java 17 and explore :
Language Features, Garbage Collectors, Library enhancements, Tools, Removals and Deprecations, and a lot more.
We target a single Java release in every section.
Some of the topics covered -
Text Blocks, Switch Expressions, Records, Pattern Matching for instanceof, Pattern Matching for switch, Sealed Classes
Garbage Collectors - G1, Epsilon, ZGC, Shenandoah
Modularity, jdeps, jlink, jdeprscan
Improved Docker Container Detection
Tool/Toolkit - Jpackage, JShell, JDK Flight Recorder
Factory methods in Collections
Compact Strings
Understand how String concatenation works behind the scenes
Some of the changes in the Stream API
Local Variable Type Inference along with recommendations on usage
Application Class Data Sharing
The new HTTP Client API
Handy String API changes
Writing scripts using the Java programming language
Teeing Collector
JMH (Java Microbenchmark Harness)
Encapsulated JDK internals
Tips on Migration (Examples on JAXB, Hibernate, and Spring Boot)
and more!
Now includes a downloadable PDF guide on the Java Flow API (Java 9+) — a beginner-friendly reference that explains the core reactive programming interfaces with clear examples and key takeaways. This bonus resource strengthens your understanding and helps with interview preparation.
The course will immensely benefit Java developers interested in getting up to speed with the ever-evolving Java language.
There are lots of exercises (along with the solution) that will help you to gain confidence.
The course is not a migration guide but we do cover numerous areas that can have an impact on migration.
What if you have questions?
I offer full support, 7 days a week, answering any questions you have.