Java 25 Module Import Declarations with Examples
Introduction
A typical Java file starts with a long list of imports -
OUTPUT of the above code
Explanation of the code
Ambiguous names
Importing whole modules makes it more likely that two packages contain a type with the same simple name. The classic example is
OUTPUT on compiling the above code
The solution is a single-type import, which always takes precedence over module and on-demand imports -
OUTPUT of the above code
The rule of precedence is: single-type imports (
Module imports and compact source files
Compact source filesClick to read tutorial: Java 25 Compact Source Files and Instance main Methods import
java.util.List, java.util.Map, java.util.stream.Collectors, java.nio.file.Files, java.time.LocalDate - often managed by the IDE and rarely read. On-demand imports like import java.util.*; help, but only for one package at a time. Since Java 9, related packages are grouped into modulesClick to read: modules, so it is natural to import a module as a whole. After previews in Java 23 and 24, Java 25Click to read tutorial: Overview of New Features in Java 25 (JEP 511) finalized module import declarations: import module java.base; imports every public type of every package that the module exports. This tutorial explains them with examples - how they work, resolving ambiguous names, and when to use them.
Importing a whole module
One module import instead of many package imports
//ModuleImportDemo.java
import module java.base; // java.util, java.util.stream, java.time, java.nio.file and 50+ more packages
public class ModuleImportDemo {
public static void main(String[] args) throws IOException {
List<String> names = List.of("Tom", "Harry", "Sam");
Map<Integer, List<String>> byLength = names.stream().collect(Collectors.groupingBy(String::length));
System.out.println("Grouped by length: " + byLength);
LocalDate release = LocalDate.of(2025, Month.SEPTEMBER, 16);
System.out.println("Java 25 was released on a " + release.getDayOfWeek());
Path file = Files.createTempFile("demo", ".txt");
Files.writeString(file, String.join(",", names));
System.out.println("File contains: " + Files.readString(file));
Files.delete(file);
}
}
Grouped by length: {3=[Tom, Sam], 5=[Harry]}
Java 25 was released on a TUESDAY
File contains: Tom,Harry,Sam
import module java.base;madeListandMap(java.util),Collectors(java.util.stream),LocalDateandMonth(java.time),PathandFiles(java.nio.file) andIOException(java.io) all available with one line.- A module import is equivalent to an on-demand import (
import p.*;) of every package the module exports - including, throughrequires transitive, the packages of modules it depends on transitively. Importingjava.sql, for example, also importsjava.xml's packages. - The importing code does not itself need to be in a module - a class on the class path, as here, can import modules too.
List, which exists both as java.util.List and java.awt.List in the java.desktop module -
Two module imports with the same type name
//Ambiguous.java
import module java.base;
import module java.desktop;
public class Ambiguous {
List<String> names = new ArrayList<>();
}
Ambiguous.java:6: error: reference to List is ambiguous List<String> names = new ArrayList<>(); ^ both class java.awt.List in java.awt and interface java.util.List in java.util match 1 error
Resolving the ambiguity with a single-type import
//Resolved.java
import module java.base;
import module java.desktop;
import java.util.List; // shadows java.awt.List
public class Resolved {
public static void main(String[] args) {
List<String> names = new ArrayList<>(List.of("Tom", "Harry"));
Dimension size = new Dimension(800, 600); // from java.desktop's java.awt
System.out.println(names + " in a window of " + size.width + "x" + size.height);
}
}
[Tom, Harry] in a window of 800x600
import java.util.List;) shadow on-demand imports (import java.util.*;), which shadow module imports. So a module import can never silently change the meaning of a name that is imported more specifically.
java.base automatically, as if they began with import module java.base;. This is what lets a beginner use List, Map or LocalDate in a small program without learning about imports first. Your own modules can be imported the same way, by name, if they are on the module path: import module com.javabrahman.greetings;.
When to use module imports
- Good fits: scripts, prototypes, tests, teaching examples and compact source files, where convenience matters more than knowing exactly where each type comes from - and code which uses an API spread over many packages of one module.
- Single-type imports remain clearer in large production codebases, where the import list documents a file's dependencies, and IDEs manage it anyway.
- Whichever style you choose, keep it consistent within a project.
import module line. We replaced a list of package imports with import module java.base;, saw the compile error when two imported modules contain a List, and resolved it with a single-type import, which always takes precedence. Lastly, we looked at module imports in compact source files, and when to use them. Next, read about flexible constructor bodiesClick to read tutorial: Java 25 Flexible Constructor Bodies with Examples.Continue Reading Java 22 to 25 Tutorials
Overview of New Features in Java 25Click to read tutorial: Overview of New Features in Java 25 Java 25 Compact Source Files and Instance main MethodsClick to read tutorial: Java 25 Compact Source Files and Instance main Methods Java 25 Flexible Constructor Bodies with ExamplesClick to read tutorial: Java 25 Flexible Constructor Bodies with Examples Java 25 Scoped Values Tutorial with ExamplesClick to read tutorial: Java 25 Scoped Values Tutorial with Examples Java 25 Compact Object Headers ExplainedClick to read tutorial: Java 25 Compact Object Headers Explained Java 25 Key Derivation Function (KDF) API TutorialClick to read tutorial: Java 25 Key Derivation Function (KDF) API Tutorial Overview of New Features in Java 22Click to read tutorial: Overview of New Features in Java 22 Overview of New Features in Java 23Click to read tutorial: Overview of New Features in Java 23 Overview of New Features in Java 24Click to read tutorial: Overview of New Features in Java 24
Overview of New Features in Java 25Click to read tutorial: Overview of New Features in Java 25 Java 25 Compact Source Files and Instance main MethodsClick to read tutorial: Java 25 Compact Source Files and Instance main Methods Java 25 Flexible Constructor Bodies with ExamplesClick to read tutorial: Java 25 Flexible Constructor Bodies with Examples Java 25 Scoped Values Tutorial with ExamplesClick to read tutorial: Java 25 Scoped Values Tutorial with Examples Java 25 Compact Object Headers ExplainedClick to read tutorial: Java 25 Compact Object Headers Explained Java 25 Key Derivation Function (KDF) API TutorialClick to read tutorial: Java 25 Key Derivation Function (KDF) API Tutorial Overview of New Features in Java 22Click to read tutorial: Overview of New Features in Java 22 Overview of New Features in Java 23Click to read tutorial: Overview of New Features in Java 23 Overview of New Features in Java 24Click to read tutorial: Overview of New Features in Java 24