🪞 Reflection, Annotations & Modules · Advanced

Module import declarations in Java

Java 25 import module java.base;.

🧩 The mysteryOne import line gives you List, Map, Path, Files and hundreds more, with no wildcards per package. Java 25 made it official.

Import a whole module

**import module M; imports every public top-level type from all packages that M exports, plus those of modules M requires transitively. Previewed in Java 23 and 24, it became final in Java 25**.

import module java.base;
 
void main() {
    var files = List.of(Path.of("a.txt"));
    System.out.println(files);
}

Compact files get it free

Why can a compact source file (just void main()) use List and Map with no import at all? It **implicitly imports module java.base**. In a normal class you write imports yourself, or import module java.base;.

🔮 Predict it

Too many Lists

java.desktop exports java.awt.List. What happens in this compact source file?

import module java.desktop;
 
void main() {
    List<String> xs = List.of("a");
    System.out.println(xs);
}
  1. Prints [a]
  2. Compile error
  3. Throws ClassCastException
Show the answer

Two imported modules export a type named List: java.util.List (from the implicit java.base) and java.awt.List. The simple name is ambiguous, so javac refuses.

Single-type imports win

A single-type import shadows module imports and on-demand imports. One extra line settles any clash.

import module java.desktop;
import java.util.List; // List = java.util.List

Using java.sql.Date

✗ Ambiguous
import module java.sql;
 
Date d = new Date(0);

java.base brings java.util.Date too: compile error.

✓ Resolved
import module java.sql;
import java.sql.Date;
 
Date d = new Date(0);

The single-type import wins over module imports.

⚠️ The trap

Encapsulation still applies

import module java.base; does not import internal packages like jdk.internal.misc. Module imports respect encapsulation: only exported packages come in.

💼 In the real world

Where it shines

Module imports are great for scripts, demos, teaching and quick tools: one line instead of a dozen. In big codebases, many teams still prefer explicit single-type imports, which document exactly where each type comes from.

Key takeaways

  1. Final in Java 25
  2. Imports only exported packages of the module
  3. Compact source files import java.base automatically
  4. Single-type imports resolve name clashes
🤯 Did you know?

import module java.sql; also gives you java.util.logging types, because java.sql requires java.logging transitively.

Practice questions

This compact source file imports java.sql. What happens?

import module java.sql;
 
void main() {
    Date d = new Date(0);
    System.out.println(d.getTime());
}
  1. 1970-01-01
  2. 0
  3. Compile error
  4. Throws ClassCastException
Check your answer

Compile error. java.sql exports java.sql.Date and the implicit java.base import brings in java.util.Date, so the simple name Date is ambiguous.

You want to keep `import module java.sql;` and use java.sql.Date in the code above. Best fix?

  1. Write `import module java.sql.Date;`
  2. Rename the variable d
  3. Remove java.base from the JDK
  4. Add `import java.sql.Date;`, since a single-type import wins over module imports
Check your answer

Add `import java.sql.Date;`, since a single-type import wins over module imports. Single-type imports shadow on-demand and module imports, so Date now unambiguously means java.sql.Date.

Modules organize Java code. But what about code that isn't Java at all? Next: calling C libraries directly with the FFM API.