In Section 9.4, “Requiring Modules,” on p. 504, you have seen the basic form of the requires statement. In this section, you will see two variants that are occasionally useful.
In some situation, it can be tedious for a user of a given module to declare all required modules. Consider, for example, the javafx.controts module that contains JavaFX user interface elements such as buttons. The javafx.controts requires the javafx.base module, and everyone using javafx.controts will also need javafx.base. (You can’t do much with a user interface control such as a Button if you don’t have packages from the javafx.base module available.) For that reason, the javafx.controts module declares the requirement with the transitive modifier:
requires transitive javafx.base;
Any module that declares a requirement on javafx.controls now automatically requires javafx.base.
One compelling use of the requires transitive statement is an aggregator module—a module with no packages and only transitive requirements. One such module is the java.se module, declared like this:
requires transitive java.compiler;
requires transitive java.datatransfer;
requires transitive java.desktop;
requires transitive java.sql;
requires transitive java.sql.rowset;
requires transitive java.xml;
requires transitive java.xml.crypto;
A programmer who isn’t interested in fine-grained module dependencies can simply require java.se and get all modules of the Java SE platform.
Finally, there is an uncommon requires static variant that declares that a module must be present at compile time but is optional at runtime. There are two use cases:
- To access an annotation that is processed at compile time and declared in a different module.
- To use a class in a different module if it is available, and otherwise do something else, such as:
catch (NoCtassDefFoundError er)
Do something else
Source: Horstmann Cay S. (2019), Core Java. Volume II – Advanced Features, Pearson; 11th edition.