Packages and Imports — Naming Conventions, import, module-info.java, and JPMS
In this tutorial, you will learn about Packages and Imports. We cover key concepts, practical examples, and best practices to help you master this topic.
Java packages organize classes into namespaces, preventing name collisions and enabling access control. Without packages, every class in every library would share a single namespace — two libraries could not both have a User class. Packages solve this by grouping related classes under a unique namespace.
What You'll Learn
- Package declaration and directory structure
- Import statements: explicit, on-demand, and static imports
- Package-level access control
- The Java Platform Module System (JPMS)
Why It Matters
Package organization affects maintainability, build configuration, and deployment. Modular Java applications require module-info.java. Understanding packages is essential for working with any real-world Java project.
Real-World Use
Spring Boot projects follow a layered package structure (controller, service, repository, model). Libraries like Apache Commons use org.apache.commons.lang3. Every Java project relies on packages.
Package Declaration
Every Java file starts with a package declaration (or uses the unnamed package):
package com.example.myapp;
public class User {
// ...
}
The package name must match the directory structure: com/example/myapp/User.java.
Naming Convention
- Domain reversed:
com.example,org.apache,io.spring - All lowercase: Even acronyms:
com.example.htmlparser - One level per sub-namespace:
com.example.myapp.service
The Import Statement
Import brings types from other packages into scope:
import java.util.List;
import java.util.ArrayList;
On-Demand Import (Wildcard)
import java.util.*; // imports all types in java.util
Wildcard imports do not import nested packages (java.util.* does not include java.util.stream.*). They also do not hurt performance — the compiler resolves specific types.
Name Conflicts
If two packages have a class with the same name, use fully qualified names:
import java.util.Date;
// import java.sql.Date; // conflict — use fully qualified
java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis());
Static Imports
Static imports allow using static members without the class name:
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
import static java.util.Collections.sort;
double area = PI * r * r;
double root = sqrt(25);
sort(list);
Use static imports sparingly — they can harm readability when overused.
Package-Level Access
When a member has no access modifier (package-private), it is accessible from any class in the same package:
package com.example.myapp;
class Helper { // package-private class
static void utility() { // package-private method
System.out.println("Utility");
}
}
package com.example.myapp;
public class Main {
public static void main(String[] args) {
Helper.utility(); // accessible (same package)
}
}
The Java Module System (JPMS, Java 9+)
JPMS adds a new layer of Encapsulation above packages. A module is a group of packages that explicitly declares which packages it exports and which modules it requires.
module-info.java
module com.example.myapp {
requires java.sql; // depends on java.sql module
exports com.example.myapp.api; // publicly accessible packages
exports com.example.myapp.model;
}
Key Directives
requires— declares a dependency on another moduleexports— makes a package accessible to other modulesopens— allows reflective access (for frameworks like Spring/Hibernate)provides ... with ...— service provider interfaceuses— declares a dependency on a service
Benefits
- Strong encapsulation: Internal packages are hidden by default
- Reliable configuration:
requiresprevents missing dependencies at startup - Smaller footprint: The JDK itself is modularized —
java.baseis always available, other modules are loaded on demand
The java.base Module
java.base is always required and does not need an explicit requires. It includes java.lang, java.util, java.io, java.math, and other fundamental packages.
Common Mistakes
- Forgetting the package declaration. Classes in the unnamed package cannot be imported by classes in named packages. Always declare a package.
- Using wildcard imports excessively. While they do not affect performance, they make it harder to see exactly which classes are used.
- Naming packages with uppercase letters. Package names should be all lowercase, even for acronyms.
- Missing
exportsin modules. A package that is not exported is invisible to other modules, even with Reflection (unlessopensis used). - Adding
module-info.javato the default package. Module declarations require a named package.
Practice Questions
1. What is the purpose of a Java package?
To organize classes into namespaces, avoid name collisions, and enable access control.
2. How does the on-demand import (import java.util.*) affect performance?
It does not. The compiler resolves which types are actually used. Wildcard imports are a compile-time convenience with no runtime cost.
3. What is the difference between exports and opens in a module?
exports makes the public types in a package accessible at compile time and runtime. opens allows reflective access (for frameworks like Spring) without making the types compile-time accessible.
4. What module is implicitly required in every module?
java.base. It is always present and does not need an explicit requires directive.
5. Can two classes have the same name if they are in different packages?
Yes. Use fully qualified names to distinguish them, or import one and use the fully qualified name for the other.
Challenge Question:
Create a multi-module project with two packages (without Maven/Gradle, just manual compilation). Create com.example.lib with a Greeter class and com.example.app with a Main class. Use module-info.java to export only the com.example.lib package. Compile and run using javac and java with --module-path.
FAQ
Mini Project
Write a program PackageDemo.java organized in the following structure:
src/
com.example.lib/
Greeter.java (package com.example.lib)
module-info.java
com.example.app/
Main.java (package com.example.app)
module-info.java
Greeterhas apublicmethodgreet(String name)that returns "Hello, " + nameMainimports and usesGreetermodule-info.javaforcom.example.libexports its packagemodule-info.javaforcom.example.apprequirescom.example.lib- Compile with
javaccommands and run withjava --module-path
What's Next
Packages organize classes, but Java also provides special types for specific use cases. Lesson 18 covers enums — type-safe constants with fields, methods, and specialized collections like EnumMap and EnumSet.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro