Static Import in Java: Syntax, Rules and When to Use It

Static import in Java explained with single and on-demand forms, name clash and shadowing rules, JUnit examples, best practices and Java 25 compact files.

How Java resolves a static import name: members of the current class first, then single-static imports, then static-import-on-demand, with ambiguity errors at the point of use

A static import in Java is an import static declaration that lets a source file use the static fields and methods of another class by their simple names, such as max(3, 7) instead of Math.max(3, 7). A regular import saves us from writing the package name of a class, and a static import also saves us from writing the class name in front of its static members.

We use static imports mostly for test assertions such as assertEquals(), for stream helpers such as Collectors.toList() and Comparator.comparing(), and for constants that a class reads many times.

The following example imports one method and one constant from Math.

import static java.lang.Math.max;
import static java.lang.Math.PI;
int larger = max(3, 7);                 // 7
double circle = PI * 2;                 // 6.283185307179586

Notice that both names are written without Math. in front. We cover the two forms of the declaration, the rules the compiler applies when names clash, the places where static imports make code easier to read, and how they relate to the module imports and compact source files of Java 25.

1. Single-Static Import and Static-Import-on-Demand

A static import declaration comes in two forms, and both go after the package declaration and before the first type, next to the regular imports.

  • A single-static-import declaration names one member, such as import static java.util.Map.entry;. It imports every static member with that name, so all overloads of a method come along.
  • A static-import-on-demand declaration ends with an asterisk, such as import static java.util.stream.Collectors.*;. It makes every accessible static member of the class available.
import static java.util.Map.entry;
import static java.util.stream.Collectors.*;
import static java.util.Comparator.comparing;
Map.Entry<String, Integer> apples = entry("apple", 5);              // apple=5
String joined = Stream.of("red", "blue").collect(joining(", "));     // "red, blue"
Map<Integer, Long> byLength = Stream.of("fig", "kiwi", "pear").collect(groupingBy(String::length, counting()));   // {3=1, 4=2}
List<String> sorted = Stream.of("kiwi", "fig", "banana").sorted(comparing(String::length)).toList();   // [fig, kiwi, banana]

A static import works for static fields, static methods, enum constants and static nested types. It does not work for instance members, because there is no object to call them on.

// does not compile: cannot find symbol, length() is an instance method
import static java.lang.String.length;

The declaration does not load or run anything. The compiler only uses it to resolve names, and the class file contains the same Math.max call as code written with the class name.

2. How the Compiler Resolves Static Import Names

Name clashes are where static imports get tricky, because two classes often have static members with the same name, such as MAX_VALUE in every numeric wrapper or max() in Math, Integer and Collections. The compiler applies three rules, which come from the shadowing rules of the language.

How Java resolves a static import name: members of the current class first, then single-static imports, then static-import-on-demand, with ambiguity errors at the point of use
The most specific declaration wins, and a clash is reported where the name is used, not at the import

2.1. A Single-Static Import Shadows an On-Demand Import

If a name is imported both by a single-static import and by a static-import-on-demand declaration, the single-static import wins. In the following imports, Integer.* brings in Integer.MAX_VALUE, but the single import of Long.MAX_VALUE hides it.

import static java.lang.Integer.*;
import static java.lang.Long.MAX_VALUE;
long limit = MAX_VALUE;                 // 9223372036854775807, from Long
int smallest = MIN_VALUE;               // -2147483648, from Integer

2.2. Two Imports of the Same Name Are an Error Only Where Used

Importing two static members with the same simple name from two classes compiles. The compiler reports an error only when the code uses the name and both members fit the call. Two on-demand imports of Math and Integer both offer max(int, int), so the call is ambiguous.

// does not compile: reference to max is ambiguous
import static java.lang.Math.*;
import static java.lang.Integer.*;

int larger = max(3, 7);

For methods, normal overload resolution runs first. If only one of the imported methods accepts the arguments, the call compiles and uses that method. For fields, any use of a name that two imports provide is ambiguous, so we import one of them or write the class name. Two single-static imports of types with the same name, such as two static nested classes called Entry, fail at the import itself.

2.3. A Member of the Current Class Shadows the Import

A static method or field declared in the class itself, or inherited by it, hides an imported member with the same name. The member hides all overloads of the import, so the import of String.format becomes useless in the following class, even for calls that only String.format could serve.

import static java.lang.String.format;
static String format(Object value) {
  return "[" + value + "]";
}
String label = format(5);               // "[5]", the class's own method
// does not compile: method format cannot be applied to given types
String text = format("%d items", 3);

When an imported name does not resolve the way we expect, we check the current class and its superclasses for a member with the same name first.

3. Where Static Imports Make Code Easier to Read

Since Java 5, Oracle has recommended using static import very sparingly, and the advice still holds. A static import helps when a few members are used so often that the class name becomes noise, and when the member names say clearly where they come from.

Test classes are the most common case. A JUnit test for a scoring service calls assertEquals() and assertThrows() dozens of times, and nobody reading a test wonders where assertEquals() comes from.

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@Test
void largerScoreWins() {
  assertEquals(7, max(3, 7));
  assertThrows(NumberFormatException.class, () -> Integer.parseInt("seven"));
}

The same reasoning applies to fluent APIs such as Stream collectors, Comparator factories and AssertJ’s assertThat(). Static imports hurt readability in other cases.

  • On-demand imports of several classes hide where a method comes from and can turn into ambiguity errors when a library adds a method in a later version.
  • Generic names such as of(), copyOf() or valueOf() lose their meaning without the class name, so List.of(…) reads better than of(…).
  • Importing System.out saves seven characters and makes every out.println() look like a local variable.
  • Implementing an interface only to inherit its constants, the “constant interface” pattern, is the misuse that static imports were designed to replace.

4. Static Import in Java vs a Regular Import

Both declarations only affect name resolution at compile time, but they import different kinds of names.

importimport static
ImportsClasses and interfacesStatic fields, static methods, enum constants and static nested types
Exampleimport java.util.List;import static java.util.List.of;
Usage in codeList.of(1, 2)of(1, 2)
On-demand formimport java.util.*; (package)import static java.util.List.*; (class)
Added inJava 1.0Java 5

Java 25 adds a third kind, the module import declaration import module java.base;, which imports every public type of the packages that a module exports. It imports types only, so it combines with static imports instead of replacing them.

5. Static Imports in Java 25 Compact Source Files

Since Java 25, a compact source file can contain a bare void main() method without a class. Such a file imports the java.base module for us, so List needs no import, but it does not import any static members. We call IO.println() with its class name, and add static imports as in any other file.

$ cat Scores.java
import static java.util.Collections.frequency;

void main() {
    List<String> votes = List.of("red", "blue", "red");
    IO.println(frequency(votes, "red"));
}

$ java Scores.java
2

A bare println(“hi”) call in the same file fails with “cannot find symbol”, because IO is a class in java.lang and its methods are not statically imported.

6. Static Import FAQs

A static import changes only how names are written, so the questions about it are about performance, style and the limits of the feature rather than syntax.

6.1. Does a Static Import Make Code Faster?

No. The compiler replaces every imported name with the full class reference, so the bytecode is identical to code that writes Math.max(). A static import also does not initialize the class or load it earlier.

6.2. Is Static Import a Bad Practice?

No, but overuse is. Static imports of a few well-known members, such as test assertions, collectors and constants used many times, make code shorter and still clear. Many on-demand static imports or generic names such as of() make code harder to read, so most style guides and IDEs warn about them.

6.3. Can We Static Import an Enum Constant?

Yes. Enum constants are static fields, so import static java.time.DayOfWeek.MONDAY; lets us write MONDAY instead of DayOfWeek.MONDAY. Inside a switch on an enum, the case labels need no import at all.

6.4. Can We Use import static With Our Own Classes?

Yes, as long as the class is in a named package and the member is accessible from the importing file. Classes in the unnamed (default) package cannot be imported at all, with or without static.

6.5. Which Java Version Added Static Imports?

Java 5 added static imports, together with generics, enums and autoboxing. Java 25 added module import declarations, which import types only.

7. Conclusion

A static import lets us write the static members of another class without the class name. The single form imports one name with all its overloads, and the on-demand form imports every static member of a class.

When names clash, a member of the current class wins over any import, and a single-static import wins over an on-demand one. Two imports of the same name are an error only at the point of use. We keep static imports for test assertions, collectors and frequently used constants, and write the class name everywhere else. The Java tutorial groups the other language basics by topic.

8. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.