Memra

Why modules: strong encapsulation & reliable configuration

The problems the flat classpath caused and how JPMS solves them in Java 9+.

The problem with the classpath

Before Java 9, every .jar on the classpath dumped all its packages into one flat namespace. Any class could access any other class — including sun.* and com.sun.* internals that were never meant to be public API. Removing an internal class was a breaking change in practice, even if it was never documented.

Two resulting problems:

- No strong encapsulation: making a package internal was a convention, not enforced by the JVM. - Unreliable configuration: there was no way to say "I need library X at version 2" — if two jars provided the same class, whichever appeared first on the classpath won. Missing jars were not detected until runtime (ClassNotFoundException).

Java Platform Module System (JPMS)

Introduced in Java 9, JPMS gives each module a name, an explicit list of packages it exports, and an explicit list of modules it requires. The JVM enforces these boundaries at both compile time and runtime.

A module is declared in module-info.java, placed at the source root (same level as your top-level package directory):

module com.acme.app {
    requires java.sql;
    exports com.acme.app.api;
}

Named, automatic, and unnamed modules

| Kind | What it is | module-info.java? | |---|---|---| | Named | A jar with module-info.class | Yes | | Automatic | A regular jar placed on the --module-path (name derived from filename) | No | | Unnamed | Everything on the old --class-path | No |

Named modules get full JPMS enforcement. Automatic modules exist for backward compatibility — they export everything and read all other modules. Unnamed modules can access automatic and named modules' exported packages, but named modules cannot directly require the unnamed module, which prevents accidental coupling in the other direction.

NORMAL ~/memra/learn/java-from-zero/why-modules utf-8 LF