All 15 Java Platform Module System (JPMS) questions
More in Java Platform Module System (JPMS)
Advertisement
Java › Java Platform Module System (JPMS)

How do the requires and exports directives in a module-info.java file work together to define a module's dependencies and public API surface?

Intermediate

Answer

requires ModuleName declares that your module depends on another named module, making that dependency's exported packages available to your module's own code (and causing a compile/runtime error if the required module isn't present, rather than a classpath-era silent NoClassDefFoundError potentially discovered much later); exports package.name declares that a specific package within YOUR module is accessible to OTHER modules that require yours, while any package NOT explicitly exported remains genuinely inaccessible outside your module (not just conventionally private, but JVM-enforced, rejecting even reflective access attempts by default) -- together these two directives let a module precisely control both what it needs and what it exposes.
// module-info.java for a library module
module com.example.mylibrary {
    requires java.logging;                    // this library itself depends on java.logging

    exports com.example.mylibrary.api;        // public API, visible to consuming modules
    // com.example.mylibrary.internal.impl is NOT exported -- truly hidden implementation detail
}

// A consuming module
module com.example.consumer {
    requires com.example.mylibrary;  // can now use com.example.mylibrary.api.* classes
    // but CANNOT access com.example.mylibrary.internal.impl.* at all -- compile error if attempted
}
Real-world example A library author confidently refactors internal implementation classes in a non-exported package, knowing with certainty (enforced by the JVM itself, not just a naming convention) that no external consumer could possibly have compiled against or be relying on those specific classes, since JPMS genuinely prevents that access rather than merely discouraging it.

Common follow-ups: What happens if module A requires module B, but module B doesn't actually export the specific package module A tries to use?;How does 'requires transitive' differ from a plain 'requires' declaration?