skip to content

What is the difference between a single-type import and a wildcard (on-demand) import in Java, and when would you prefer each?

level: juniorimportance: must knowfreq 70%

answer

  1. Single = one type; wildcard `*` = all public top-level types of one package
  2. Wildcard does NOT recurse into sub-packages
  3. Imports are compile-time only — zero runtime cost
  4. Single-type wins on clarity + collision-safety
  5. Classic clash: java.util.List vs java.awt.List

basics

~10 s

A single-type import names one class, like import java.util.List;. A wildcard import, like import java.util.*;, lets you use any class from that package. Single imports are clearer and usually preferred.

solid answer

~40 s

A single-type import declares exactly one type by its full name, e.g. `import java.util.List;`, so only `List` becomes usable by its simple name. A wildcard (or on-demand) import, `import java.util.*;`, makes every public top-level type in that package available by simple name, but it does NOT recurse into sub-packages. Single-type imports are usually preferred because they document exactly which types are used and avoid surprises when packages add new types that could clash with names you already use. Wildcards reduce import clutter but can introduce ambiguity. Importantly, a wildcard never imports more than is needed at compile time — there is no runtime cost; imports are purely a compile-time naming convenience. Many style guides (e.g. Google's) ban wildcard imports for clarity.

go deeper

for a junior

States the syntactic difference (List vs *) and that single-type imports are usually preferred for clarity.

for a middle

Explains on-demand semantics, that wildcards don't recurse into sub-packages, and the future-collision risk that motivates explicit imports.

for a senior

Articulates that imports are compile-time-only naming sugar, cites the java.util/java.awt List clash, and ties the choice to team style guides and maintainability.

for a principal

Frames import policy as a codebase-wide convention (lint rules, ambiguity-on-package-growth as a stability/SemVer hazard) and can reason about how it interacts with module systems and refactoring tooling.

## What an import even is In Java, every class lives in a **package** — a namespace like `java.util` or `com.acme.billing`. A class's **fully qualified name (FQN)** is the package plus the class's **simple name**: `java.util.List` has package `java.util` and simple name `List`. You can always refer to a type by its FQN with no import at all: ```java java.util.List<String> names = new java.util.ArrayList<>(); ``` That is verbose. An **import declaration** lets you use the **simple name** (`List`) instead. Imports are purely a **compile-time convenience for names** — they generate no bytecode and have no runtime cost. The compiler uses them only to resolve which type a simple name refers to. ## Single-type import ```java import java.util.List; ``` This makes exactly one type — `java.util.List` — available by its simple name `List` for the rest of the file. It is explicit: a reader can see precisely which types the file depends on. ## Wildcard / on-demand import ```java import java.util.*; ``` The `*` is called an **on-demand** import (the JLS term) or **wildcard** import. It makes **all public top-level types** of the package `java.util` (e.g. `List`, `Map`, `ArrayList`, `Set`) available by simple name. Key facts a beginner must internalize: - It does **NOT** recurse into sub-packages. `import java.util.*;` does **not** import `java.util.concurrent.ConcurrentHashMap` — `java.util.concurrent` is a separate package. - It imports types **on demand**: only the simple names you actually use are resolved; nothing is pulled in at runtime. - It can only see **public** top-level types of that exact package. ## When to prefer each **Prefer single-type imports** in almost all production code because: 1. They document the exact dependency surface of the file. 2. They avoid future breakage: if a wildcard-imported package later adds a type whose simple name collides with another wildcard import, your code can suddenly fail to compile (an ambiguity), even though you didn't change it. 3. IDEs auto-manage them, so the verbosity argument is weak. **Wildcards** are occasionally fine for a package from which you use many types (e.g. `java.util.*` in scratch code), but most style guides (Google Java Style, many corporate standards) forbid them outright. ## A common gotcha If both `java.util.List` and some hypothetical `java.awt.List` are wildcard-imported (`import java.util.*; import java.awt.*;`), the simple name `List` becomes **ambiguous** and the code won't compile — you'd have to add a single-type import to disambiguate. This real example (`java.util.List` vs `java.awt.List`) is the classic motivation for preferring explicit imports.

  • Does `import java.util.*;` import `java.util.regex.Pattern`?
    No. `java.util.regex` is a separate package; on-demand imports never recurse into sub-packages. You'd need `import java.util.regex.*;` or `import java.util.regex.Pattern;`.
  • Is there any runtime difference between wildcard and single imports?
    None. Imports are resolved entirely at compile time and emit no bytecode; the compiled class file is identical regardless of import style.

saying these in an interview costs you the question

  • Thinking `import java.util.*;` also imports `java.util.concurrent`
  • Believing wildcard imports make the JAR larger or slow startup
  • Claiming wildcards import private/package-private types
  • Saying you must import classes in the same package

context