3 Module Import Declarations

You can import all packages exported by a module with one statement.

Note:

This is a preview feature. A preview feature is a feature whose design, specification, and implementation are complete, but is not permanent. A preview feature may exist in a different form or not at all in future Java SE releases. To compile and run code that contains preview features, you must specify additional command-line options. See Preview Language and VM Features. For more information about module import declarations, see JEP 476

Consider the following example, which imports four classes:

import java.util.Map;    
import java.util.function.Function;  
import java.util.stream.Collectors;  
import java.util.stream.Stream;    

public class FruitMap {
    public static void main(String[] args) {
        String[] fruits = new String[] { "apple", "berry", "citrus" };
        Map<String, String> m = Stream
            .of(fruits)
            .collect(Collectors.toMap(
                s -> s.toUpperCase().substring(0,1),
                Function.identity()));
        m.forEach((k, v) ->
            System.out.println(k + " " + v));
    }
}

You can replace the four single-type-import declarations in this example with type-import-on-demand declarations. However, you still need three of them:

import java.util.*;    
import java.util.function.*;  
import java.util.stream.*;

Because the module java.base exports the packages java.util, java.util.function and java.util.stream, you can replace these three declarations with one module import declaration:

import module java.base;

A module import declaration has the following form:

import module M;

It imports, on demand, all of the public top-level class and interfaces in the following:

  • The packages exported by the module M to the current module.

  • The packages exported by the modules that are read by the current module due to reading the module M. This enables a program to use the API of a module, which might refer to classes and interfaces from other modules, without having to import all those other modules.

    For example, the module import declaration import module java.sql has the same effect as import java.sql.* plus on-demand imports for the indirect exports of the java.sql module, which include the packages java.logging and java.xml.

Ambiguous Imports

It's possible to import classes with the same simple name from different packages with module import declarations. However, this can lead to compile-time errors. The following example uses both java.awt.List and java.util.List:

import java.awt.Frame;
import java.awt.Label;
import java.awt.List;
import java.awt.event.WindowAdapter;   
import java.awt.event.WindowEvent;    
import java.util.Arrays;

public class FruitApp {    
      
    AWTExample(java.util.List<String> fruits) {  
        Frame f = new Frame();  
        Label l = new Label("Fruits");   
        List lst = new List();
        fruits.forEach(i -> lst.add(i));
        l.setBounds(20, 40, 80, 30);  
        lst.setBounds(20, 70, 80, 80);  
        f.add(l);
        f.add(lst);  
        f.setSize(200,200);  
        f.setTitle("Fruit");   
        f.setLayout(null);   
        f.setVisible(true);  

        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                System.exit(0);
            }
        });      
    }    
      
    public static void main(String args[]) {   
        String[] fruits = new String[] { "apple", "berry", "citrus" };
        FruitApp f = new FruitApp(Arrays.asList(fruits));    
    }  
}

Suppose you replace the single-type-import declarations with these module import declarations:

import module java.desktop;
import module java.base;

You'll get these compile-time errors:

error: reference to Label is ambiguous
        Label l = new Label("Fruits");
        ^
  both interface java.lang.classfile.Label in java.lang.classfile and class
  java.awt.Label in java.awt match
...
error: reference to List is ambiguous
        List lst = new List();
        ^
  both interface java.util.List in java.util and class java.awt.List in java.awt
  match

The simple name Label is ambiguous. It's contained in java.lang.classfile and java.awt, which the modules java.base and java.desktop export, respectively. This issue applies similarly to the simple name List.

To resolve these ambiguities, use single-type-import declarations to specify the canonical names of the simple names used in your code:

import module java.desktop;
import module java.base;
import java.awt.Label;
import java.awt.List;

Implicitly Declared Classes and the java.base Module

Every implicitly declared class (see Implicitly Declared Classes) automatically imports, on demand, all public top-level classes and interfaces in all packages exported by the java.base module. It's as if the module import declaration import module java.base appears at the beginning of every implicitly declared class instead of the type-import-on-demand declaration import java.lang.* at the beginning of every ordinary class. For example, you can simplify the FruitMap example with an implicitly declared class as follows:

void main() {
    String[] fruits = new String[] { "apple", "berry", "citrus" };
    Map<String, String> m = Stream
        .of(fruits)
        .collect(Collectors.toMap(
            s -> s.toUpperCase().substring(0,1),
                Function.identity()));
    m.forEach((k, v) ->
        System.out.println(k + " " + v));
}