What do the `requires` and `exports` directives do in a `module-info.java`, and why are they fundamental to the Java module system?
answer
- requires = readability (I depend on you)
- exports = accessibility (this package is visible)
- public is not enough — package must be exported
- exports is per-package, no sub-package wildcard
- both sides must agree to cross the boundary
basics
~20 srequires says your module depends on another module so you can use its code. exports makes one of your packages visible to other modules. Without an export, a package stays internal and other modules cannot use it, even if it is public.
solid answer
~40 sIn JPMS (the Java Platform Module System, added in Java 9), every module declares itself in `module-info.java`. `requires <module>` declares a dependency: it grants your module *readability* of that module, so you can compile and run against the types it exports. `exports <package>` does the reverse: it makes exactly that one package accessible to other modules. The two are complementary — a type is usable across a module boundary only if the owning module `exports` its package AND the consuming module `requires` the owning module. Crucially, `public` is no longer enough: a public class in a non-exported package is invisible outside its module ("strong encapsulation"). Exports are per-package and not transitive — listing a package does not export sub-packages. This pair replaces the flat, everything-visible classpath with explicit, compiler-enforced dependencies.
code
java · 14 lines// module com.acme.core's module-info.java
module com.acme.core {
exports com.acme.core.api; // visible to readers
// com.acme.core.internal is NOT exported -> stays private
}
// module com.acme.app's module-info.java
module com.acme.app {
requires com.acme.core; // can now read core's exports
exports com.acme.app.web;
}
// In com.acme.app: OK -> com.acme.core.api is exported and required
// Using com.acme.core.internal.* -> compile error (not exported)go deeper
Knows requires = a dependency and exports = makes a package visible; can read a simple module-info.
Explains strong encapsulation (public is not enough), per-package exports with no wildcard, and that both sides must agree.
Reasons about API surface design via exports, the implicit java.base, and how the module graph is validated at compile and launch.
Designs module boundaries for a library/platform: minimal exported surface, internal packages, and migration trade-offs from the classpath.
## Background: what a module is Before Java 9, code was organized only into **packages** (namespaces like `com.acme.util`) loaded from a flat **classpath**. Any public class anywhere on the classpath was visible to all other code. There was no way to say "this package is my internal implementation, keep out." The **Java Platform Module System (JPMS)**, introduced in Java 9 (Project Jigsaw), adds a layer *above* packages: a **module** is a named, self-describing group of packages. You declare a module in a special file at the source root called **`module-info.java`**: ```java module com.acme.app { requires com.acme.core; exports com.acme.app.api; } ``` ## `requires` — declaring a dependency (readability) `requires <moduleName>` states that your module **depends on** another module. The technical term is that it grants **readability**: module A *reads* module B. Only if A reads B can A use the public types in the packages B exports. The compiler and the runtime both enforce this — if you use a type from a module you did not `requires`, compilation fails. Every module implicitly `requires java.base` (the core JDK module with `java.lang`, `java.util`, etc.); you never write that line. ## `exports` — exposing a package (accessibility) `exports <packageName>` makes the **public** types in exactly that one package accessible to any module that reads yours. This is the heart of **strong encapsulation**: in the module world, `public` means "public *within the module*"; it crosses the module boundary only if the package is also exported. Key rules: - Exports are **per package**, listed individually. `exports com.acme.api` does NOT export `com.acme.api.internal` — there is no wildcard, sub-packages are separate. - Exporting affects only **public/protected** members (normal access rules still apply within an exported package). - A package that is not exported is an **internal** package: invisible to other modules at compile and run time, even via its public classes. ## How the two combine A type crosses a module boundary only when **both** sides agree: 1. The owning module `exports` the package, and 2. The consuming module `requires` the owning module. Miss either and you get an error. This turns dependencies from an implicit, fragile classpath soup into an explicit, compiler-checked graph — no accidental dependence on someone's internals, and missing dependencies are caught at build time rather than as a runtime `NoClassDefFoundError`. ## Why it matters - **Strong encapsulation:** library authors can keep `*.internal` packages truly private. - **Reliable configuration:** the module graph is validated up front; you cannot launch with a missing module. - **Clear API surface:** the exported packages are precisely the public contract.
- If a class is `public` but its package is not exported, can another module use it?No. In JPMS, crossing a module boundary requires both an export of the package and a requires of the module. A public class in a non-exported package is invisible outside its own module (strong encapsulation).
- Does `exports com.acme.api` also export `com.acme.api.model`?No. Exports are per-package with no wildcard; sub-packages are distinct packages and must be exported individually.
A module is like an office building. requires is getting a keycard to another building. exports is which of your own rooms have public doors. Even a room with a 'public' sign stays locked to outsiders unless the building lists it as open.
saying these in an interview costs you the question
- Thinking `public` alone makes a class usable across modules
- Assuming `exports a.b` cascades to `a.b.c` sub-packages
- Confusing requires (consume) with exports (provide) directions
- Believing you must declare requires java.base