Back to Java
2026-02-238 min read

Modules Namespace (Java)

Learn Modules Namespace (Java) step by step with clear examples and exercises.

Title: Modules and Namespaces in Java - A full guide

Why This Matters

In this tutorial, we delve into the essential concepts of modules and namespaces in Java. Understanding these topics is crucial for writing efficient, maintainable, and scalable code. Whether you're preparing for a job interview, working on a complex project, or debugging real-world issues, mastering modules and namespaces can significantly improve your coding abilities.

Prerequisites

Before we delve into the core concept, ensure you have a solid foundation in Java programming:

  1. Familiarity with basic Java syntax, such as variables, loops, and control structures.
  2. Understanding of object-oriented programming concepts like classes, objects, inheritance, and interfaces.
  3. Comfortable working with the Java Development Kit (JDK) and Integrated Development Environments (IDEs) like Eclipse or IntelliJ IDEA.
  4. Familiarity with the Java Standard Library (JSL) and common third-party libraries used in Java development.
  5. Knowledge of version control systems such as Git, as modules can be easily shared and managed using them.

Core Concept

Modules in Java

Java 9 introduced a new module system to address some of the issues with the previous fragmented classpath system. A module is a named collection of types and resources that are intended to be used together. It provides a way to organize your code into smaller, more manageable units, making it easier to reuse, test, and maintain.

Each Java application or library must belong to at least one module. The root module of an application is called the application module, while libraries have their own separate modules.

Declaring a Module

To declare a module, create a file named module-info.java in the root directory of your project. This file contains a module declaration and any necessary dependencies. Here's an example:

module com.example {
}

In this case, we have created a module called com.example. You can replace com.example with any name you prefer, as long as it follows the Java package naming conventions.

Dependencies

You can declare dependencies for your module using the requires keyword. For example:

module com.example {
requires java.sql; // Requires the JDBC driver for SQL access
requires some-third-party-library; // Requires a third-party library called "some-third-party-library"
}

Exporting Modules

To allow other modules to use your module's public types, you can use the exports keyword in your module declaration:

module com.example {
exports com.example.publicapi; // Exports the com.example.publicapi package for other modules to use
}

Service Provider Interfaces (SPIs)

Service Provider Interfaces (SPIs) allow you to define extension points in your module, enabling other modules to provide implementations of specific services. This can help promote modularity and flexibility in your codebase.

Namespaces in Java

In Java, namespaces are not explicitly defined like in some other languages such as C++ or Python. Instead, Java uses packages to organize related classes and interfaces under a common name. This helps avoid naming conflicts between different parts of your codebase.

Creating a Package

To create a package, create a directory with the same name as the desired package in your project's source directory. For example:

src/
main/
java/
com/
example/
database/
JDBCConnection.java

In this example, we have created a package called com.example.database. The JDBCConnection.java file would be placed inside the database directory.

Importing Packages

To use classes from another package, import them at the beginning of your source file using the import keyword:

import com.example.database.JDBCConnection;

public class Main {
public static void main(String[] args) {
JDBCConnection jdbc = new JDBCConnection();
// Use the JDBCConnection object here
}
}

Common Mistakes

  1. Forgetting to declare a module in your project or not specifying dependencies properly.
  2. Importing packages incorrectly, either by misspelling the package name or using an incorrect import statement.
  3. Naming conflicts between classes in different packages due to similar names. To avoid this, use meaningful and descriptive class names, and consider organizing your code into multiple packages if necessary.
  4. Failing to follow Java naming conventions for packages (lowercase letters separated by dots) and class names (Capitalize the first letter of each word).
  5. Ignoring the importance of modules in large-scale projects, leading to a fragmented classpath and potential issues with dependencies.
  6. Not properly using Service Provider Interfaces (SPIs), resulting in hardcoded implementations or unnecessarily complex code.
  7. Failing to export necessary packages when creating a module, preventing other modules from using them.
  8. Incorrectly managing versions of your modules and their dependencies, leading to compatibility issues.

Worked Example

In this section, we will create a simple Java application that demonstrates the use of modules and namespaces. We'll create two separate modules: com.example.app for our main application and com.example.utils for utility classes.

Creating the com.example.app Module

First, let's create a new directory for our project:

mkdir my-java-project
cd my-java-project

Next, we'll create the com.example.app module by creating a module-info.java file in the root directory:

// src/main/java/module-info.java
module com.example.app {
}

Creating the com.example.utils Module

Now, let's create a new package for our utility classes and add a simple StringUtils class:

mkdir src/main/java/com/example/utils
touch src/main/java/com/example/utils/StringUtils.java

Inside the StringUtils.java file, we'll define a simple method to reverse a string:

// src/main/java/com/example/utils/StringUtils.java
package com.example.utils;

public class StringUtils {
public static String reverse(String input) {
StringBuilder sb = new StringBuilder(input);
return sb.reverse().toString();
}
}

Updating the com.example.app Module

Now, we'll update our com.example.app module to include a dependency on our utility module and export the necessary package:

// src/main/java/module-info.java
module com.example.app {
requires com.example.utils; // Requires the com.example.utils module
exports com.example.app; // Exports the com.example.app package for other modules to use
}

Creating the Main Application Class

Finally, let's create a simple Main class in our main application module that uses our utility class:

touch src/main/java/com/example/app/Main.java

Inside the Main.java file, we'll import our utility class and use it to reverse a string:

// src/main/java/com/example/app/Main.java
package com.example.app;

import com.example.utils.StringUtils;

public class Main {
public static void main(String[] args) {
String input = "Hello, World!";
String reversed = StringUtils.reverse(input);
System.out.println("Reversed: " + reversed);
}
}

Compiling and Running the Application

With our application complete, we can compile and run it using the Java compiler (javac) and Java runtime (java):

javac -cp . src/main/java/com/example/app/Main.java src/main/java/com/example/utils/StringUtils.java
java -cp .:./src/main/java com.example.app.Main

The output should be:

Reversed: !dlrow ,olleH

Common Mistakes

  1. Forgetting to export necessary packages when creating a module, preventing other modules from using them.
  2. Failing to properly manage versions of your modules and their dependencies, leading to compatibility issues.
  3. Not properly organizing your code into separate modules, making it harder to maintain and reuse.
  4. Ignoring the importance of Service Provider Interfaces (SPIs) in promoting modularity and flexibility in your codebase.
  5. Failing to follow Java naming conventions for packages and class names, leading to potential naming conflicts and confusion.
  6. Not properly handling dependencies between modules, resulting in issues with accessing required classes and resources.
  7. Using hardcoded implementations instead of Service Provider Interfaces (SPIs) when defining extension points in your codebase.
  8. Failing to test your modules thoroughly, leading to undetected bugs and potential issues in production.

Practice Questions

  1. Create a new module called com.example.logging that provides a custom logging implementation for your application, allowing other modules to use it through Service Provider Interfaces (SPIs).
  2. Modify the com.example.app module from the worked example to include a new class for managing products, along with an Order class that associates users with their orders and specific products.
  3. Write a Java program that demonstrates using the java.util.concurrent package to implement a thread-safe queue data structure.
  4. Create a new module called com.example.security that provides authentication and authorization services for your application, allowing other modules to use it through Service Provider Interfaces (SPIs).
  5. Write a Java program that demonstrates using the java.nio.file package to read and write files asynchronously.
  6. Create a new module called com.example.testing that provides testing utilities for your application, allowing other modules to use it through Service Provider Interfaces (SPIs).
  7. Write a Java program that demonstrates using the java.time package to work with dates and times in a more intuitive and flexible manner.
  8. Create a new module called com.example.database that provides database access functionality for your application, allowing other modules to use it through Service Provider Interfaces (SPIs).

FAQ

What happens if I don't declare a module for my Java project?

  • If you don't declare a module, your project will still compile and run, but it may not work as expected when using third-party libraries or sharing code with others. It is recommended to always declare modules in your projects.

How do I handle naming conflicts between classes in different packages?

  • To avoid naming conflicts, use meaningful and descriptive class names, and consider organizing your code into multiple packages if necessary. If a conflict still occurs, you can rename one of the conflicting classes or qualify the name with its package.

What is the purpose of Service Provider Interfaces (SPIs) in Java modules?

  • Service Provider Interfaces (SPIs) allow you to define extension points in your module, enabling other modules to provide implementations of specific services. This can help promote modularity and flexibility in your codebase.

How do I manage dependencies between my modules?

  • You can declare dependencies for your module using the requires keyword in the module declaration file (module-info.java). This allows other modules to access the required classes and resources.

What is the role of packages in Java namespaces?

  • In Java, packages serve as a way to organize related classes and interfaces under a common name, helping avoid naming conflicts between different parts of your codebase. Packages also provide a namespace for your classes, making it easier to manage large codebases.
Modules Namespace (Java) | Java | XQA Learn