The requires keyword in Java is used within a module definition to specify module dependencies. It indicates that the current module depends on another module to function correctly. This is part of the Java Platform Module System (JPMS), introduced in Java 9, which provides a way to modularize Java applications and libraries.
Table of Contents
- Introduction
requiresKeyword Syntax- Understanding
requires - Examples
- Basic Requires
- Requires Transitive
- Requires Static
- Real-World Use Case
- Conclusion
Introduction
In Java’s module system, the requires keyword is used to declare dependencies between modules. By specifying the required modules, you ensure that the current module has access to the classes and interfaces of the required modules, enabling better modularity and dependency management.
requires Keyword Syntax
The syntax for using the requires keyword in a module-info.java file is as follows:
module moduleName {
requires requiredModuleName;
}
Example:
module com.example.myapp {
requires com.example.utils;
}
Understanding requires
Key Points:
- Module Dependency: The
requireskeyword declares a dependency on another module. - Transitive Dependencies: You can use
requires transitiveto expose the dependencies of a required module to other modules that require your module. - Static Dependencies:
requires staticspecifies that the dependency is only needed at compile time, not at runtime.
Examples
Basic Requires
A simple example demonstrating how to declare a dependency on another module.
Example
// File: src/com.example.myapp/module-info.java
module com.example.myapp {
requires com.example.utils;
}
// File: src/com.example.utils/module-info.java
module com.example.utils {
exports com.example.utils.api;
}
// File: src/com.example.utils/api/Utility.java
package com.example.utils.api;
public class Utility {
public static void printMessage(String message) {
System.out.println(message);
}
}
// File: src/com.example.myapp/Main.java
package com.example.myapp;
import com.example.utils.api.Utility;
public class Main {
public static void main(String[] args) {
Utility.printMessage("Hello from the utility module!");
}
}
Requires Transitive
Using requires transitive to expose transitive dependencies.
Example
// File: src/com.example.core/module-info.java
module com.example.core {
requires transitive com.example.utils;
exports com.example.core.api;
}
// File: src/com.example.extensions/module-info.java
module com.example.extensions {
requires com.example.core;
}
// File: src/com.example.extensions/Extension.java
package com.example.extensions;
import com.example.core.api.CoreService;
import com.example.utils.api.Utility;
public class Extension {
public static void main(String[] args) {
CoreService coreService = new CoreService();
coreService.performService();
Utility.printMessage("Message from the utility module via core module!");
}
}
Requires Static
Using requires static to specify a compile-time dependency.
Example
// File: src/com.example.myapp/module-info.java
module com.example.myapp {
requires static com.example.debug;
}
// File: src/com.example.debug/module-info.java
module com.example.debug {
exports com.example.debug.api;
}
// File: src/com.example.debug/api/DebugUtils.java
package com.example.debug.api;
public class DebugUtils {
public static void debug(String message) {
System.out.println("DEBUG: " + message);
}
}
// File: src/com.example.myapp/Main.java
package com.example.myapp;
import com.example.debug.api.DebugUtils;
public class Main {
public static void main(String[] args) {
DebugUtils.debug("Debug message from myapp module!");
}
}
Real-World Use Case
Modularizing an Enterprise Application
In real-world applications, modularization can help manage dependencies and improve maintainability. For instance, you might have different modules for core functionality, utilities, and optional features.
Example
// Core module definition (src/com.example.core/module-info.java)
module com.example.core {
requires com.example.utils;
exports com.example.core.services;
}
// Utilities module definition (src/com.example.utils/module-info.java)
module com.example.utils {
exports com.example.utils.helpers;
}
// Optional feature module definition (src/com.example.feature/module-info.java)
module com.example.feature {
requires static com.example.debug;
}
// Main application module definition (src/com.example.app/module-info.java)
module com.example.app {
requires com.example.core;
requires com.example.feature;
}
// Core service (src/com.example.core/services/CoreService.java)
package com.example.core.services;
import com.example.utils.helpers.Helper;
public class CoreService {
public void performService() {
Helper helper = new Helper();
helper.assist();
System.out.println("Core service performed");
}
}
// Utility helper (src/com.example.utils/helpers/Helper.java)
package com.example.utils.helpers;
public class Helper {
public void assist() {
System.out.println("Helper is assisting");
}
}
// Main application (src/com.example.app/Main.java)
package com.example.app;
import com.example.core.services.CoreService;
public class Main {
public static void main(String[] args) {
CoreService coreService = new CoreService();
coreService.performService();
}
}
Conclusion
The requires keyword in Java’s module system is a crucial tool for managing dependencies between modules. By specifying required modules, you ensure that your module has access to the necessary classes and interfaces, improving modularity and maintainability. Understanding and using the requires keyword effectively is essential for developing robust and scalable modular Java applications.