Packages in Java
Packages in Java
Every Java program you write lives inside a package — even if you never declare one. When you start writing enterprise-grade code with dozens of classes, or when two developers on the same team both create a class called Order, packages are what prevent the collision and keep everything organised.
A package in Java is a namespace that groups related classes, interfaces, and sub-packages together. The analogy is a folder on your computer — just as you put all your music files in a Music folder and all your documents in a Documents folder, Java puts related classes into packages. java.util holds utility classes. java.io holds input/output classes. Your own com.flipkart.order package holds all order-related classes for a Flipkart-like application.
Why Packages Exist — Three Reasons
Reason 1 — Namespace collision prevention:
Without packages:
Developer A writes: class Order { ... } ← conflict!
Developer B writes: class Order { ... } ← same name, same scope
With packages:
com.flipkart.order.Order ← fully qualified: no conflict
com.amazon.cart.Order ← completely separate
Reason 2 — Access control:
Classes in the same package can access each other's
package-private (default) members.
Classes outside the package cannot.
Reason 3 — Organisation and navigation:
com.myapp
├── model → Order, User, Product (data classes)
├── service → OrderService, PaymentService (logic)
├── repository → OrderRepository (database access)
├── controller → OrderController (API endpoints)
└── util → DateUtil, StringUtil (helpers)
Built-In Java Packages
Java ships with hundreds of packages. These are the ones every Java developer uses:
// File: BuiltInPackagesDemo.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.io.File;
import java.math.BigDecimal;
import java.time.LocalDate;
public class BuiltInPackagesDemo {
public static void main(String[] args) {
// java.util — utility classes: collections, date, random
List<String> cities = new ArrayList<>(Arrays.asList("Mumbai", "Delhi", "Bengaluru"));
Collections.sort(cities);
System.out.println("java.util.List : " + cities);
Map<String, Integer> scores = new HashMap<>();
scores.put("Priya", 95);
scores.put("Rohan", 88);
System.out.println("java.util.Map : " + scores);
Optional<String> opt = Optional.of("Hello");
System.out.println("java.util.Optional: " + opt.get());
// java.io — file and stream operations
File file = new File("example.txt");
System.out.println("java.io.File : exists=" + file.exists());
// java.math — precise arithmetic (for money calculations)
BigDecimal price = new BigDecimal("1299.99");
BigDecimal tax = new BigDecimal("0.18");
BigDecimal total = price.add(price.multiply(tax));
System.out.println("java.math.BigDecimal: Rs." + total);
// java.time — modern date/time API (Java 8+)
LocalDate today = LocalDate.now();
System.out.println("java.time.LocalDate: " + today);
}
}Output:
java.util.List : [Bengaluru, Delhi, Mumbai]
java.util.Map : {Priya=95, Rohan=88}
java.util.Optional: Hello
java.io.File : exists=false
java.math.BigDecimal: Rs.1533.9882
java.time.LocalDate: 2024-01-15
Key Built-In Package Reference
| Package | Purpose | Key Classes |
|---|---|---|
java.lang | Core language — auto-imported always | String, Integer, Math, System, Object, Thread |
java.util | Utility: collections, date, random | ArrayList, HashMap, Arrays, Collections, Scanner |
java.io | File and stream I/O | File, FileReader, BufferedReader, PrintWriter |
java.nio | Non-blocking I/O (modern file ops) | Path, Files, Paths, Channels |
java.math | Precise arithmetic | BigDecimal, BigInteger |
java.time | Date and time (Java 8+) | LocalDate, LocalDateTime, ZonedDateTime |
java.net | Networking | URL, HttpURLConnection, Socket |
java.util.stream | Functional streams (Java 8+) | Stream, Collectors, Optional |
java.util.concurrent | Thread safety and parallelism | ExecutorService, ConcurrentHashMap, Future |
java.sql | Database connectivity (JDBC) | Connection, PreparedStatement, ResultSet |
java.lang is the only package that is automatically imported in every Java file — no import statement needed. That is why you can write String, System.out.println, and Math.max without any import.
Declaring a Package
A package declaration is the first statement in a Java file (before any import or class declaration). It uses the package keyword followed by the package name.
// File: Order.java
// This file must be saved in: src/com/flipkart/order/Order.java
package com.flipkart.order; // ← must be line 1 (before imports)
import java.time.LocalDate; // ← imports come after package declaration
public class Order {
private final String orderId;
private final String customerId;
private final double amount;
private final LocalDate orderDate;
public Order(String orderId, String customerId, double amount) {
this.orderId = orderId;
this.customerId = customerId;
this.amount = amount;
this.orderDate = LocalDate.now();
}
public String getOrderId() { return orderId; }
public String getCustomerId() { return customerId; }
public double getAmount() { return amount; }
public LocalDate getOrderDate(){ return orderDate; }
@Override
public String toString() {
return "Order{id=" + orderId + ", customer=" + customerId
+ ", amount=Rs." + amount + ", date=" + orderDate + "}";
}
}// File: OrderService.java
// Save in: src/com/flipkart/service/OrderService.java
package com.flipkart.service; // different package from Order
import com.flipkart.order.Order; // must import — different package
public class OrderService {
public Order createOrder(String customerId, double amount) {
String orderId = "ORD-" + System.currentTimeMillis();
Order order = new Order(orderId, customerId, amount);
System.out.println("Created: " + order);
return order;
}
public void processOrder(Order order) {
System.out.println("Processing order: " + order.getOrderId()
+ " for Rs." + order.getAmount());
}
}// File: Main.java
// Save in: src/Main.java (default package — no package declaration)
import com.flipkart.order.Order;
import com.flipkart.service.OrderService;
public class Main {
public static void main(String[] args) {
OrderService service = new OrderService();
Order order = service.createOrder("CUST-501", 1299.50);
service.processOrder(order);
}
}Output:
Created: Order{id=ORD-1705312200000, customer=CUST-501, amount=Rs.1299.5, date=2024-01-15}
Processing order: ORD-1705312200000 for Rs.1299.5
Package Naming Conventions
Java package names follow a strict convention to guarantee global uniqueness and reflect the project structure.
Convention: reverse domain name + project + layer + module Examples: Company / Domain → Reversed Domain ───────────────────────────────────────────── flipkart.com → com.flipkart meesho.com → com.meesho razorpay.com → com.razorpay dev.stackflow (personal) → com.devstackflow Full package names: com.flipkart.order.model → Order, Cart, Product (data) com.flipkart.order.service → OrderService, CartService (logic) com.flipkart.order.repository → OrderRepository (DB access) com.flipkart.order.controller → OrderController (HTTP API) com.flipkart.order.exception → OrderNotFoundException, PaymentException com.flipkart.order.util → OrderIdGenerator, AmountFormatter Rules: — All lowercase (no CamelCase, no underscores recommended) — No Java keywords (e.g., not com.flipkart.class) — Reverse domain name as prefix for global uniqueness — Layer name (model, service, util) as last segment
Package and Folder Structure
The package name maps directly to the folder structure on disk. package com.meesho.catalog.service means the file lives in com/meesho/catalog/service/ directory.
Folder structure for a Meesho-like application:
src/
└── main/
└── java/
└── com/
└── meesho/
└── catalog/
├── model/
│ ├── Product.java → package com.meesho.catalog.model
│ ├── Category.java → package com.meesho.catalog.model
│ └── Seller.java → package com.meesho.catalog.model
├── service/
│ ├── ProductService.java → package com.meesho.catalog.service
│ └── CategoryService.java → package com.meesho.catalog.service
├── repository/
│ └── ProductRepository.java→ package com.meesho.catalog.repository
├── controller/
│ └── ProductController.java→ package com.meesho.catalog.controller
├── exception/
│ └── ProductNotFoundException.java
└── util/
└── SlugGenerator.java → package com.meesho.catalog.util
Every Java file in com/meesho/catalog/model/ must start with package com.meesho.catalog.model; — the compiler enforces that the package declaration matches the file's location.
Sub-packages
Sub-packages are simply packages nested inside other packages through deeper folder hierarchies. Java treats each package independently — com.meesho.catalog and com.meesho.catalog.model are two completely separate packages with no parent-child access relationship.
// File: SubPackageDemo.java
package com.devstackflow.demo;
// java.util is a package — java.util.stream is a SUB-package
// They are independent — importing java.util does NOT import java.util.stream
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors; // must import separately
public class SubPackageDemo {
public static void main(String[] args) {
List<String> names = new ArrayList<>(List.of(
"Priya", "Rohan", "Sneha", "Karan", "Ananya"));
// java.util.stream.Collectors — sub-package of java.util
String joined = names.stream()
.filter(n -> n.length() > 4)
.collect(Collectors.joining(", "));
System.out.println("Long names: " + joined);
// Important: sub-package classes are NOT visible from parent package
// Importing 'java.util.*' does NOT import java.util.stream.Stream
// Every package must be explicitly imported
}
}Output:
Long names: Priya, Rohan, Sneha, Karan, Ananya
Default Package — The Package You Should Avoid
A class with no package declaration lives in the default package — an unnamed package. The compiler allows it, but production code should never use it.
// File: DefaultPackageClass.java
// No package declaration — this is in the DEFAULT PACKAGE
public class DefaultPackageClass {
public static void greet() {
System.out.println("I am in the default package.");
}
}Problems with the default package:
1. Cannot be imported by classes in named packages
import DefaultPackageClass; ← compile error from named package
2. No namespace — collision risk with any other default-package class
3. IDEs and build tools (Maven, Gradle) warn about it
4. Spring Boot, JPA, and other frameworks do not scan the default package
Verdict: Only acceptable for quick throwaway demos.
All production code must declare a package.
Basic Example
// Imagine this class lives in: com/store/Order.java (package com.store;)
class Order {
String id;
Order(String id) {
this.id = id;
}
@Override
public String toString() {
return "store.Order#" + id;
}
}
// A completely different class could also be named "Order" and live in:
// com/logistics/Order.java (package com.logistics;) — it would be a
// totally separate class. No clash, because packages are separate namespaces.
public class Main {
public static void main(String[] args) {
Order order = new Order("ORD-100");
System.out.println(order);
}
}Output
store.Order#ORD-100
- ›
Orderhere stands in for a class that, in a real project, would start withpackage com.store;and live atcom/store/Order.java. - ›Another completely unrelated class could also be named
Orderand live in a different package, such ascom.logistics.Order— the two would never collide because the package name is part of each class's full identity. - ›This is the core reason packages exist: they let two developers, teams, or libraries independently create a class called
Orderwithout conflict, becausecom.store.Orderandcom.logistics.Orderare different fully qualified names.
Best Practices
Always declare a package — never leave classes in the default package. Framework tools like Spring, Hibernate, and Lombok require named packages to scan for annotations. The default package cannot be imported by any named-package class, making its classes inaccessible to most of the application.
Follow the reverse-domain naming convention. com.yourcompany.projectname.layer is the universal standard. It prevents collisions across projects, libraries, and organisations. All lowercase — no numbers at the start, no Java keywords.
Match the package name to the folder structure exactly. The compiler requires it. If the file says package com.meesho.service but lives in com/meesho/model/, the compiler reports an error. In Maven and Gradle projects, src/main/java is the source root — everything below maps to the package name.
Group by layer, not by feature — until the project grows large enough. model, service, repository, controller, util, exception is the standard layered structure for small to mid-sized projects. Feature-based packaging (com.app.order, com.app.payment) becomes more natural in large microservice-style monorepos where each feature is nearly its own module.
Common Mistakes
Mistake 1 — Package Declaration Not on Line 1
// WRONG — comments are fine, but no code or blank logic before package
import java.util.List; // compile error — import before package declaration
package com.myapp.service; // must be the FIRST non-comment statement
// CORRECT order:
package com.myapp.service; // 1. package (line 1)
import java.util.List; // 2. imports
public class Service { } // 3. classMistake 2 — Wrong Folder Location
// File says:
package com.myapp.service;
// But file is saved at: src/com/myapp/model/Service.java
// Compiler: "class Service is public, should be declared in Service.java"
// (and cannot find it in the correct package location)
// Fix: move the file to src/com/myapp/service/Service.javaMistake 3 — Assuming Sub-packages Share Visibility
package com.myapp.util;
class Helper { // package-private — visible only within com.myapp.util
static void doSomething() { }
}
// In com.myapp.util.io (a SUB-package):
package com.myapp.util.io;
import com.myapp.util.Helper; // compile error — Helper is package-private
// Sub-packages have NO special access to parent package membersMistake 4 — Using Single-Segment Package Names
// Too generic — risk of collision with other libraries
package order; // BAD
package service; // BAD
package util; // BAD
// Correct — reverse domain prefix guarantees uniqueness
package com.myntra.order; // GOOD
package com.myntra.service; // GOODInterview Questions
Q1. What is a package in Java and why is it used?
A package is a namespace that groups related classes, interfaces, and sub-packages together. It serves three purposes: preventing naming conflicts between classes from different developers or libraries that happen to share the same class name; providing a layer of access control through package-private visibility; and organising code into logical layers and modules that reflect the application's architecture. The package name maps directly to the folder structure on disk — com.flipkart.order means the class lives at com/flipkart/order/ClassName.java.
Q2. What is the default package in Java and why should you avoid it?
The default package is the unnamed package that a class belongs to when no package declaration is present. Classes in the default package cannot be imported by classes in any named package — the import keyword requires a fully qualified name with at least one dot, which the default package cannot provide. Additionally, frameworks like Spring and Hibernate cannot scan the default package for annotations, making the class invisible to dependency injection. The default package is acceptable only for throwaway test programs — all production code must declare a named package.
Q3. What is the difference between a package and a sub-package in Java?
A package and its sub-package are completely independent. java.util and java.util.stream are two separate packages with no shared visibility. Importing java.util.* does NOT import java.util.stream.Collectors — you must import the sub-package explicitly. Sub-package classes have no special access to parent-package members and vice versa. The folder structure creates the appearance of nesting, but the Java compiler treats each package as an entirely separate namespace.
Q4. What is the naming convention for Java packages?
Package names follow the reverse-domain-name convention to ensure global uniqueness. A company at flipkart.com uses com.flipkart as the prefix. The full name then adds the project and the architectural layer: com.flipkart.catalog.service for service classes in the catalog module. All segments are lowercase — no camelCase, no underscores recommended, no Java keywords. A class's fully qualified name is the complete package path plus the class name: com.flipkart.catalog.service.ProductService.
Q5. Where must the package declaration appear in a Java source file?
The package declaration must be the very first statement in the source file — before any import statements and before the class declaration. Only comments and blank lines may appear before it. The compiler enforces this strictly. The only exception is a class with no package declaration, which belongs to the default package. Having two package statements in one file or placing package after an import causes a compile error.
Q6. What is a fully qualified class name and when do you use it?
A fully qualified class name (FQCN) is the complete name of a class including its package: java.util.ArrayList, com.flipkart.order.model.Order. You use it when two classes from different packages have the same simple name in the same file — for example, if you need both java.util.Date and java.sql.Date, one must be referred to by its FQCN because you can only import one of them by simple name. FQCNs are also used in reflection (Class.forName("com.myapp.service.OrderService")) and in configuration files like Spring XML or persistence.xml.
FAQs
Can two classes in different packages have the same simple name?
Yes — that is precisely the problem packages solve. com.flipkart.order.Order and com.amazon.cart.Order are two completely different classes that happen to share the simple name Order. In a file that needs both, one must be imported by simple name and the other referenced by its FQCN. The compiler does not confuse them because the package prefix makes each name globally unique.
Does importing a package import all its classes?
import com.myapp.service.* imports all public classes directly in com.myapp.service — but not classes in its sub-packages, and not package-private classes. For sub-packages you need separate import statements. The wildcard * never imports sub-packages. Most style guides recommend specific imports over wildcards for readability — it is immediately clear which class from the package is actually used.
What happens if you have two classes with the same name imported?
The compiler raises an error if you try to import two classes with the same simple name. The fix is to import one and use the FQCN for the other: import java.util.Date; and then use java.sql.Date everywhere the SQL version is needed. Alternatively, remove both imports and use FQCNs for both.
Is java.lang automatically imported?
Yes. java.lang is the only package that is automatically imported in every Java source file without any explicit import statement. This is why String, System, Math, Integer, Object, Thread, and all other java.lang classes are available without importing. All other packages — including java.util — require explicit imports.
Can a package span multiple JAR files?
Yes. A package name does not have to be confined to one JAR or one directory. Multiple JARs on the classpath can contribute classes to the same package name — this is called a split package. While technically supported, split packages are discouraged in the Java module system (Java 9+) where each package must belong to exactly one module to ensure encapsulation and reliable linkage.
Summary
A package is a namespace that groups related classes and provides the foundation for Java's access control model. The package declaration must be the first statement in a source file. The name maps directly to the folder structure. Sub-packages are independent — java.util and java.util.stream share no visibility. The default package must be avoided in any production code.
The reverse-domain naming convention — com.company.project.layer — is the universal standard. It prevents collisions, communicates code structure, and satisfies all major frameworks that rely on package scanning. The layered organisation — model, service, repository, controller, util, exception — is the default starting point for any new Java project.
For interviews, be ready to explain the three purposes of packages, distinguish between a package and sub-package, explain the default package and its limitations, and describe the naming convention with a real example.
What to Read Next
Learn how to create your own package.