Java Tutorial
🔍

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

PackagePurposeKey Classes
java.langCore language — auto-imported alwaysString, Integer, Math, System, Object, Thread
java.utilUtility: collections, date, randomArrayList, HashMap, Arrays, Collections, Scanner
java.ioFile and stream I/OFile, FileReader, BufferedReader, PrintWriter
java.nioNon-blocking I/O (modern file ops)Path, Files, Paths, Channels
java.mathPrecise arithmeticBigDecimal, BigInteger
java.timeDate and time (Java 8+)LocalDate, LocalDateTime, ZonedDateTime
java.netNetworkingURL, HttpURLConnection, Socket
java.util.streamFunctional streams (Java 8+)Stream, Collectors, Optional
java.util.concurrentThread safety and parallelismExecutorService, ConcurrentHashMap, Future
java.sqlDatabase 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
  1. ›Order here stands in for a class that, in a real project, would start with package com.store; and live at com/store/Order.java.
  2. ›Another completely unrelated class could also be named Order and live in a different package, such as com.logistics.Order — the two would never collide because the package name is part of each class's full identity.
  3. ›This is the core reason packages exist: they let two developers, teams, or libraries independently create a class called Order without conflict, because com.store.Order and com.logistics.Order are 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. class

Mistake 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.java

Mistake 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 members

Mistake 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; // GOOD

Interview 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