So here is the same application developed as modules. Let us turn the API.jar into a modular jar by adding a module declaration.
The module called API exports the package P to everyone. That is the main API and exports the helper package P.Helper to its friend modules Impl1 and Impl2.
Java supports modular programming through libraries and packages
Java supports modular programming through its system of packages, libraries, and more recently, the Java Platform Module System (JPMS) introduced in Java 9. Hereâs how Java facilitates modular programming through these features:
Packages:
A package in Java is a way to group related classes and interfaces. It acts as a container for code, allowing developers to organize their classes into a modular structure.
By using packages, you can prevent naming conflicts and control the access to certain classes by making them package-private, thus promoting encapsulation.
Example:
package com.example.mylibrary;
public class MyClass {
// Class code here
}
Here, `com.example.mylibrary` is a package that organizes `MyClass`. Other classes in the same package can access it, and it can be made public or package-private.
Libraries (JAR files):
A Java Archive (JAR) file is a collection of compiled Java classes bundled into a single file. You can think of it as a way to distribute modular code that others can reuse in their projects.
Libraries allow the reuse of common functionality across multiple projects, enhancing modularity by isolating code into manageable pieces.
Usage: You can create a JAR file from your project or import external libraries (like third-party libraries) by including them in your classpath.
bash
javac -d . MyClass.java
jar cf mylibrary.jar com/example/mylibrary/MyClass.class
Java Platform Module System (JPMS):
Starting from Java 9, Java introduced the Module System, which elevates modular programming to a higher level by formally defining modules.
A module is a collection of packages and resources, along with a `module-info.java` file that declares:
What packages the module exports.
What other modules it requires.
What services it provides or consumes.
This system helps to:
Improve modularity by making explicit what parts of the code are exposed and what parts are internal.
Resolve versioning and dependency conflicts (also known as "JAR hell").
Example:
// module-info.java
module com.example.mylibrary {
exports com.example.mylibrary; // Only export the package that needs to be public
requires java.logging; // Require another module
}
Advantages of JPMS:
Strong encapsulation: Only explicitly exported packages are accessible to other modules.
Clear dependencies: Modules explicitly declare what other modules they depend on.
Reliable configuration: Helps in detecting dependency issues at compile-time or run-time.
Visibility and Encapsulation:
Packages and modules allow Java to enforce visibility rules. In a modular program, internal classes and functionality can be hidden (by making classes package-private or non-exported from a module), ensuring that other parts of the application cannot access implementation details.
Public APIs are well-defined through package exports or module declarations.
Conclusion Javaâs support for modular programming is centered around:
Packages to organize and encapsulate related classes.
JAR files to package and reuse modular libraries.
The Java Module System to explicitly define module boundaries, dependencies, and public interfaces (post-Java 9).
Together, these features provide a strong framework for building modular, reusable, and maintainable applications.
Qualified Exports
The second export directive of P.exports is called a qualified exports.
Any module in the world can require the API module and access the package P, but only the friend Modules can access the package P.Helper. I am not showing the module declarations for the friend modules, but they will obviously require the API module in order to access the P.Foo interface that they implement.
The friend modules will not export anything and they can organize their concealed packages as they wish.
Now the P.Helper package isn't overloaded with implementation classes multiple jars.
The naming of packages is much clearer throughout all three jars and more implementations can be added smoothly.
In effect, Modules make packages as cheap as classes and then control the reuse of packages very precisely.
Summary of Part I: Programming in the Large
A module is a set of packages designed for reuse.
Modules offer strong encapsulation and reliable dependencies and
the Module-aware tooling (the command-line tool in IDEs) will be a big parts of modular developments.