Java Tutorial
🔍

Java import Statement

Java import Statement

Every time you use ArrayList, HashMap, or LocalDate in Java without writing the full java.util.ArrayList every single time, the import statement is doing that work for you. Without imports, every reference to any class outside java.lang would require the full package path — java.util.ArrayList<java.util.HashMap<java.lang.String, java.util.List<java.lang.Integer>>> instead of ArrayList<HashMap<String, List<Integer>>>.

The import statement tells the compiler where to find a class by its simple name. It does not load the class into memory or make the program heavier — it is purely a compile-time instruction that resolves a short name to a fully qualified one.

How import Works

Without import — full class name required everywhere:
  java.util.ArrayList<String> list = new java.util.ArrayList<>();
  java.util.Collections.sort(list);

With import — short name works:
  import java.util.ArrayList;
  import java.util.Collections;

  ArrayList<String> list = new ArrayList<>();
  Collections.sort(list);

What the import statement does:
  ─ Tells the compiler: "when you see ArrayList, look in java.util"
  ─ Does NOT copy any code or load any class at compile time
  ─ Does NOT affect bytecode or runtime performance
  ─ Does NOT make the JAR file larger
  ─ Is purely a compile-time name-resolution instruction

1 — Single-Type Import (Specific Import)

A single-type import imports exactly one class. This is the recommended style — it makes every dependency explicit and readable at a glance.

// File: SingleTypeImportDemo.java package com.devstackflow.demo; // Each import names exactly one class import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Collections; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.math.BigDecimal; public class SingleTypeImportDemo { public static void main(String[] args) { // All imported classes available by simple name List<String> cities = new ArrayList<>(); cities.add("Mumbai"); cities.add("Delhi"); cities.add("Bengaluru"); Collections.sort(cities); System.out.println("Cities : " + cities); Map<String, Integer> population = new HashMap<>(); population.put("Mumbai", 20_000_000); population.put("Delhi", 32_000_000); population.put("Bengaluru", 13_000_000); System.out.println("Population : " + population); LocalDate today = LocalDate.now(); DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd-MMM-yyyy"); System.out.println("Today : " + today.format(fmt)); BigDecimal price = new BigDecimal("4999.99"); System.out.println("Price : Rs." + price); } }
Output:
Cities      : [Bengaluru, Delhi, Mumbai]
Population  : {Mumbai=20000000, Delhi=32000000, Bengaluru=13000000}
Today       : 15-Jan-2024
Price       : Rs.4999.99

Specific imports are preferred in professional code because any developer reading the file can immediately see which classes are used — without having to look up what * pulled in.

2 — Wildcard Import

A wildcard import — import package.*; — imports all public classes in a package with one statement. It does not import sub-packages or package-private classes.

// File: WildcardImportDemo.java package com.devstackflow.demo; // Wildcard — imports all public classes in java.util import java.util.*; // Sub-packages are NOT included — must import separately import java.util.stream.*; import java.util.concurrent.*; public class WildcardImportDemo { public static void main(String[] args) { // All java.util classes available List<String> names = new ArrayList<>(List.of("Priya", "Rohan", "Sneha")); Map<String, Integer> scores = new HashMap<>(); scores.put("Priya", 95); scores.put("Rohan", 88); scores.put("Sneha", 92); Optional<String> topScorer = scores.entrySet().stream() .max(Map.Entry.comparingByValue()) .map(Map.Entry::getKey); System.out.println("Names : " + names); System.out.println("Scores : " + scores); System.out.println("Top scorer : " + topScorer.orElse("none")); System.out.println(); // java.util.stream was imported separately — not included in java.util.* Stream<String> upperNames = names.stream() .map(String::toUpperCase); System.out.println("Uppercased : "); upperNames.forEach(n -> System.out.println(" " + n)); System.out.println(); // java.util.concurrent was imported separately ExecutorService executor = Executors.newFixedThreadPool(2); executor.submit(() -> System.out.println("Task from thread pool")); executor.shutdown(); } }
Output:
Names      : [Priya, Rohan, Sneha]
Scores     : {Priya=95, Rohan=88, Sneha=92}
Top scorer : Priya

Uppercased :
  PRIYA
  ROHAN
  SNEHA

Task from thread pool

The wildcard * is convenient for exploration but most style guides — Google Java Style Guide, Oracle Coding Conventions — prefer specific imports. IDEs like IntelliJ IDEA automatically expand wildcards to specific imports on save.

Specific Import vs Wildcard Import — Comparison Table

AspectSpecific Import import java.util.ArrayListWildcard Import import java.util.*
ReadabilityHigh — every dependency visible at topLower — unclear which classes are used
Compile timeNo measurable differenceNo measurable difference
Runtime performanceIdentical — both are compile-time onlyIdentical
Risk of name conflictLow — explicit class chosenHigher — two packages may contribute same name
Sub-packages includedN/ANo — java.util.* does not include java.util.stream.*
IDE behaviourPreferred — auto-organised by IDEIDE warns or auto-expands to specific
Style guidesRecommendedDiscouraged in production code
When appropriateAlways in production codeQuick prototyping, exam code

3 — Static Import

import static imports a specific static member — field or method — from a class so it can be used without the class name prefix.

// File: StaticImportDemo.java package com.devstackflow.demo; // Import specific static members import static java.lang.Math.PI; import static java.lang.Math.sqrt; import static java.lang.Math.pow; import static java.lang.Math.abs; // Import all static members of a class import static java.util.Collections.sort; import static java.util.Collections.reverse; import static java.util.Collections.unmodifiableList; // Import constant from custom class import static com.devstackflow.demo.AppConstants.MAX_RETRIES; import static com.devstackflow.demo.AppConstants.DEFAULT_TIMEOUT; import java.util.ArrayList; import java.util.Arrays; import java.util.List; class AppConstants { public static final int MAX_RETRIES = 3; public static final long DEFAULT_TIMEOUT = 5000L; public static final String APP_NAME = "DevStackFlow"; } public class StaticImportDemo { public static void main(String[] args) { // Math methods without "Math." prefix double radius = 7.0; double area = PI * pow(radius, 2); double perimeter = 2 * PI * radius; double diagonal = sqrt(pow(5, 2) + pow(12, 2)); System.out.printf("Circle radius : %.1f%n", radius); System.out.printf("Circle area : %.2f%n", area); System.out.printf("Circumference : %.2f%n", perimeter); System.out.printf("3-4-5 diagonal : %.2f%n", diagonal); System.out.printf("abs(-42) : %d%n", abs(-42)); System.out.println(); // Collections methods without "Collections." prefix List<String> products = new ArrayList<>( Arrays.asList("Laptop", "Mouse", "Keyboard", "Monitor", "Headphones")); System.out.println("Before sort : " + products); sort(products); System.out.println("After sort : " + products); reverse(products); System.out.println("After reverse : " + products); List<String> immutable = unmodifiableList(products); System.out.println("Immutable list : " + immutable); System.out.println(); // Custom constants without class prefix System.out.println("Max retries : " + MAX_RETRIES); System.out.println("Default timeout : " + DEFAULT_TIMEOUT + "ms"); } }
Output:
Circle radius   : 7.0
Circle area     : 153.94
Circumference   : 43.98
3-4-5 diagonal  : 13.00
abs(-42)        : 42

Before sort     : [Laptop, Mouse, Keyboard, Monitor, Headphones]
After sort      : [Headphones, Keyboard, Laptop, Monitor, Mouse]
After reverse   : [Mouse, Monitor, Laptop, Keyboard, Headphones]
Immutable list  : [Mouse, Monitor, Laptop, Keyboard, Headphones]

Max retries     : 3
Default timeout : 5000ms

Static import is most valuable for: Math methods in mathematical code, Assert methods in unit tests (assertEquals, assertTrue), and constants across the codebase. Avoid it when it makes code less clear — sort(list) is readable, but importing unrelated constants with the same name from multiple classes creates confusion.

4 — java.lang — The Auto-Imported Package

java.lang is the only package automatically imported in every Java file. You never need to write import java.lang.String or import java.lang.System.

// File: AutoImportDemo.java package com.devstackflow.demo; // No imports needed for any java.lang class // All of the following are automatically available: public class AutoImportDemo { public static void main(String[] args) { // java.lang.String — no import needed String message = "Hello, DevStackFlow!"; System.out.println(message.toUpperCase()); // java.lang.System — no import needed System.out.println("Java version: " + System.getProperty("java.version")); // java.lang.Math — no import needed System.out.println("Max of 5,9 : " + Math.max(5, 9)); System.out.println("PI : " + Math.PI); // java.lang.Integer — no import needed int parsed = Integer.parseInt("42"); System.out.println("Parsed : " + parsed); System.out.println("Max int : " + Integer.MAX_VALUE); // java.lang.StringBuilder — no import needed StringBuilder sb = new StringBuilder("Hello"); sb.append(", World"); System.out.println("SB result : " + sb); // java.lang.Thread — no import needed System.out.println("Thread : " + Thread.currentThread().getName()); // java.lang.Object — root of all classes — no import needed Object obj = new Object(); System.out.println("Object hash: " + obj.hashCode()); } }
Output:
HELLO, DEVSTACKFLOW!
Java version: 17.0.9
Max of 5,9 : 9
PI         : 3.141592653589793
Parsed     : 42
Max int    : 2147483647
SB result  : Hello, World
Thread     : main
Object hash: 1173230247

5 — Handling Naming Conflicts

When two packages you need both have a class with the same name, you can only import one by simple name. The other must be used with its fully qualified class name.

// File: NamingConflictDemo.java package com.devstackflow.demo; // Both java.util and java.sql have a class named "Date" import java.util.Date; // import java.sql.Date; ← cannot import both — same simple name import java.sql.Connection; import java.sql.PreparedStatement; public class NamingConflictDemo { public static void main(String[] args) { // java.util.Date — can use simple name because it was imported Date utilDate = new Date(); System.out.println("java.util.Date : " + utilDate); // java.sql.Date — must use FQCN because it conflicts with the import above java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis()); System.out.println("java.sql.Date : " + sqlDate); System.out.println(); // Another common conflict — java.util.List and java.awt.List java.util.List<String> utilList = new java.util.ArrayList<>(); utilList.add("item1"); System.out.println("java.util.List : " + utilList); // java.awt.List — if needed, use: java.awt.List awtList = new java.awt.List(); System.out.println(); // Best approach when conflict is unavoidable: // Import the one you use most, FQCN for the other // OR use FQCNs for both to make the code unambiguous System.out.println("Conflict resolution: import most-used, FQCN for the rest"); } }
Output:
java.util.Date  : Mon Jan 15 10:30:00 IST 2024
java.sql.Date   : 2024-01-15
java.util.List  : [item1]

Conflict resolution: import most-used, FQCN for the rest

6 — Import Ordering and Organisation

The standard import order — enforced by tools like Google Java Style Guide, Checkstyle, and IDE formatters — keeps imports consistent across a team.

// File: ImportOrderDemo.java package com.devstackflow.demo; // ── Block 1: java.* imports ────────────────────────── import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; // ── Block 2: javax.* imports ───────────────────────── import javax.crypto.Cipher; // ── Block 3: Third-party library imports ───────────── // import org.springframework.stereotype.Service; // import com.fasterxml.jackson.databind.ObjectMapper; // ── Block 4: Internal project imports (same project) ─ // import com.devstackflow.model.Student; // import com.devstackflow.service.StudentService; // ── Block 5: Static imports (at the end) ───────────── import static java.lang.Math.PI; import static java.util.Collections.sort; public class ImportOrderDemo { public static void main(String[] args) { // All imports available by simple name List<String> cities = new ArrayList<>(); cities.add("Mumbai"); cities.add("Delhi"); cities.add("Pune"); sort(cities); // static import Map<String, BigDecimal> prices = new HashMap<>(); prices.put("Laptop", new BigDecimal("45999.00")); prices.put("Monitor", new BigDecimal("18500.00")); LocalDate orderDate = LocalDate.now(); LocalDateTime timestamp = LocalDateTime.now(); System.out.println("Cities : " + cities); System.out.println("Prices : " + prices); System.out.println("Order date: " + orderDate); System.out.println("PI : " + PI); } }
Output:
Cities    : [Delhi, Mumbai, Pune]
Prices    : {Laptop=45999.00, Monitor=18500.00}
Order date: 2024-01-15
PI        : 3.141592653589793

Most IDEs format imports automatically. In IntelliJ IDEA: Code → Optimize Imports removes unused imports and organises the rest. In VS Code with the Java extension: imports are managed on save.

Basic Example

import java.util.ArrayList; import java.util.List; import static java.lang.Math.max; public class Main { public static void main(String[] args) { List<String> fruits = new ArrayList<>(); fruits.add("Apple"); fruits.add("Mango"); System.out.println("Fruits: " + fruits); System.out.println("Max of 3 and 7: " + max(3, 7)); } }

Output

Fruits: [Apple, Mango]
Max of 3 and 7: 7
  1. ›import java.util.ArrayList; and import java.util.List; let the code use the short names ArrayList and List instead of writing java.util.ArrayList and java.util.List every time.
  2. ›import static java.lang.Math.max; imports the static method max so it can be called directly as max(3, 7) instead of Math.max(3, 7).
  3. ›Both imports are purely compile-time shortcuts — they resolve short names to their full package paths and have no effect on the compiled bytecode or runtime behaviour.

Best Practices

Use specific imports over wildcards in production code. A specific import on every dependency makes the file self-documenting — any reader instantly knows which external types are used. Wildcards save typing but hide dependencies. Every major style guide — Google, Oracle, Spring — mandates specific imports.

Let the IDE manage imports. Do not type import statements manually. In IntelliJ IDEA, Alt+Enter on a class name adds the import automatically. Ctrl+Alt+O (or Cmd+Alt+O on macOS) removes unused imports and organises the rest. In VS Code, the Java extension does the same on save. Manual import management wastes time and introduces errors.

Reserve static imports for well-understood constants and utility methods. import static java.lang.Math.PI and import static org.junit.jupiter.api.Assertions.assertEquals are idiomatic and universally understood. Avoid statically importing methods whose origin is not obvious — sort(list) is clear from context, but process(data) imported from an obscure utility class makes the code opaque.

Remove unused imports. Unused imports are noise — they suggest dependencies that do not exist. They trigger warnings in tools like Checkstyle, SonarQube, and most IDEs. Most CI pipelines fail on unused import warnings. Keep imports clean — one import per class actually used.

Common Mistakes

Mistake 1 — Wildcard Does Not Cover Sub-packages

import java.util.*; // imports ArrayList, HashMap, Optional, etc. // Does NOT import java.util.stream.Stream // Does NOT import java.util.concurrent.ExecutorService Stream<String> stream = // compile error: cannot find symbol Stream // Fix — import sub-package separately import java.util.stream.Stream; import java.util.concurrent.ExecutorService;

Mistake 2 — Importing a Class That Does Not Need Importing

// java.lang is auto-imported — these are redundant import java.lang.String; // redundant — String is always available import java.lang.System; // redundant — System is always available import java.lang.Math; // redundant — Math is always available import java.lang.Integer; // redundant — Integer is always available // IDEs mark all java.lang imports as "redundant import" // Style checkers like Checkstyle flag them as violations

Mistake 3 — Ambiguous Import When Two Packages Have Same Class Name

import java.util.Date; import java.sql.Date; // compile error: Date is already defined // Fix — import only one, use FQCN for the other import java.util.Date; public class Example { Date utilDate = new Date(); // java.util.Date java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis()); // FQCN }

Mistake 4 — Placing Import Before Package Declaration

import java.util.List; // compile error: import before package declaration package com.devstackflow; // package must be the first non-comment statement // Correct order: package com.devstackflow; import java.util.List; public class Example { }

Interview Questions

Q1. What does the import statement do in Java?

The import statement is a compile-time instruction that tells the compiler how to resolve a short class name to its fully qualified name. Without it, every class outside java.lang must be referenced by its full package path — java.util.ArrayList instead of ArrayList. The import does not load any code, does not affect the compiled bytecode, does not make the program slower, and does not increase JAR size. It purely enables short-name usage in source code.

Q2. What is the difference between a specific import and a wildcard import?

A specific import — import java.util.ArrayList — imports exactly one named class. A wildcard import — import java.util.* — imports all public classes directly in the specified package, but not sub-packages or package-private classes. Both produce identical compiled bytecode — the compiler resolves which classes are actually used regardless of how many the wildcard might cover. The practical difference is readability and conflict risk: specific imports make dependencies explicit and reduce the chance of name collision.

Q3. What is a static import and when should you use it?

import static imports a static member — field or method — from a class, allowing it to be used without the class name prefix. import static java.lang.Math.PI lets you write PI instead of Math.PI. Static imports are most appropriate for Math constants and methods in mathematical code, Assert methods in JUnit tests (assertEquals, assertTrue), and widely-used constants from your own codebase. Avoid them when the imported name's origin is not obvious from context — clarity always beats brevity.

Q4. Which package is automatically imported in every Java file?

java.lang is the only package automatically imported without any explicit import statement. This provides String, System, Math, Integer, Long, Double, Boolean, Character, StringBuilder, StringBuffer, Thread, Object, Exception, RuntimeException, and all other core language classes without any declaration. All other packages — including java.util, java.io, and java.time — require explicit imports.

Q5. What happens when two imported packages both contain a class with the same name?

A naming conflict occurs. If you write import java.util.Date; import java.sql.Date;, the compiler reports an error — two imports resolve to the same simple name Date. The solution is to import only the more frequently used class and reference the other by its FQCN wherever it appears. Alternatively, remove both imports and use FQCNs for both throughout the file, which makes the distinction explicit at every usage point.

Q6. Does a wildcard import from java.util also import java.util.stream?

No. A wildcard import only covers the classes directly in the named package — it does not extend to sub-packages. import java.util.* imports ArrayList, HashMap, Collections, Optional, and every other public class directly in java.util, but it does not import java.util.stream.Stream, java.util.stream.Collectors, java.util.concurrent.ExecutorService, or any other class in a sub-package. Each sub-package requires its own import statement.

FAQs

Does the order of import statements matter?

The compiler does not care about import order — it processes all imports regardless of sequence. However, teams enforce a standard ordering through style guides and tools. The typical convention: java.* imports first, then javax.*, then third-party libraries, then internal project imports, with static imports last. IDEs auto-sort imports according to configured rules. Consistent ordering reduces unnecessary diffs in version control when two developers independently add imports to the same file.

Can you import a class from the default package?

No. Classes in the default (unnamed) package cannot be imported by classes in named packages. The import keyword requires a fully qualified name with at least one dot separator, which the default package cannot provide. This is one of the fundamental reasons why the default package must be avoided in any project where code needs to be reused or imported.

What is an unused import and why does it matter?

An unused import is an import statement for a class that is not referenced anywhere in the file. The compiler ignores it — it produces no error and no effect on the program. However, unused imports are considered code smell. They mislead readers into thinking a dependency exists when it does not, they trigger warnings from Checkstyle, PMD, and SpotBugs, and they cause test failures on CI pipelines configured to treat warnings as errors. IDEs show them in grey and provide one-click removal.

Can two classes in the same package import each other?

Classes in the same package do not need to import each other at all — they are always mutually visible without any import. If Order.java and OrderItem.java are both in com.myapp.order, either can use the other by simple name with no import statement. This is one of the practical benefits of grouping related classes into the same package.

Is there a performance difference between importing ten specific classes and using a wildcard that covers them all?

No measurable difference at runtime. Both approaches result in exactly the same compiled bytecode — the import statement is erased during compilation. The only difference is at compile time, where the compiler must scan for classes matching the wildcard, which is slightly slower for very large packages with hundreds of classes. In practice this is completely negligible. The choice between specific and wildcard imports is purely a readability and maintainability decision.

Summary

The import statement is a compile-time shortcut — it resolves simple class names to their fully qualified package paths so that you can write ArrayList instead of java.util.ArrayList throughout the file. It has zero effect on the compiled bytecode, the JAR size, or runtime performance.

Three forms: specific import for one class, wildcard for all public classes in a package (but never sub-packages), and static import for static members. java.lang is the sole automatically imported package.

The practice every professional Java team follows: specific imports always, wildcards never in production code, static imports only for well-understood utilities, and IDE import management to keep things clean and ordered.

What to Read Next