JavaThe Module System

The Module System

Java 9 introduced the Java Platform Module System (JPMS), a layer of organization above packages. Where a package groups related classes, a module groups related packages and declares, explicitly, what it needs from the outside world and what it is willing to expose.

Declaring a Module
A module is declared with a single special file named module-info.java placed at the root of the module's source tree. It names the module and lists its dependencies and exports.

module-info.java

Java
module com.example.orders {
    requires java.sql;
    requires com.example.billing;

    exports com.example.orders.api;
}

Directive

Meaning

module com.example.orders

Declares this module's unique name

requires java.sql

This module depends on the java.sql module

requires com.example.billing

This module depends on another application module

exports com.example.orders.api

Makes only this package's public types visible to other modules

requires and exports
requires declares a dependency — without it, code in this module cannot even compile against types from the other module, regardless of whether those types are public. exports declares what this module shares — a package that is not exported is completely invisible outside the module, no matter how many of its classes are marked public.
Why Modules Exist: Stronger Encapsulation
Before modules, public meant public to the entire classpath — any code, in any JAR, could reach into any public class of any other JAR. Packages alone could not stop that. The module system adds a genuinely more granular access-control layer: a package's public classes are only accessible to other modules if that package is explicitly listed in an exports directive. An internal implementation package can be left un-exported, so it stays fully hidden from the outside world even though its classes are technically public.

Aspect

Packages Alone (Classpath)

Modules (JPMS)

Visibility of public classes

Visible to any code on the classpath

Visible only if the containing package is exported

Dependency declaration

Implicit — anything on the classpath is reachable

Explicit — must be listed with requires

Hiding internals

Not possible for public classes

Possible — keep a package un-exported

Modules in the Real World
The JDK itself is fully modularized — running java --list-modules shows dozens of modules like java.base, java.sql, and java.xml, each exporting a specific set of packages. This is also why some reflection-based libraries needed updates when moving to newer Java versions — reflective access to non-exported internals is restricted by default.
Note
Adoption of the module system in application code has been slower than originally expected. Many real-world projects, especially those built with Maven or Gradle before modules existed, still run happily on the classic classpath without ever writing a module-info.java. Understanding modules still matters, though — it explains restrictions you may hit with reflection or the java.sql and other JDK modules, and modern library documentation increasingly references module names.
Tip
You do not need to modularize your own application to benefit from this chapter — knowing what requires and exports mean is enough to make sense of JDK module errors and library documentation when you encounter them.