Java Programming Packages Tutorial
Code Organization

Java Packages - Complete Tutorial

Master Java packages: Learn built-in packages, create user-defined packages, import statements, package hierarchy, and best practices for modular programming.

Built-in Packages

java.lang, java.util, etc.

User-defined

Create custom packages

Import Statements

Access package members

Hierarchy

Package structure

1. Introduction to Java Packages

A package in Java is a namespace that organizes classes and interfaces. Think of it as a folder in a file directory used to prevent naming conflicts, control access, and make searching/locating classes easier.

Why Use Packages?
  • Name Conflict Resolution: Prevent class name collisions
  • Access Control: Package-level access protection
  • Code Organization: Group related classes together
  • Reusability: Easily reuse code across projects
  • Data Encapsulation: Hide implementation details
  • Searchability: Easier to locate related classes
Types of Packages
  • Built-in Packages: Provided by Java API (java.lang, java.util, etc.)
  • User-defined Packages: Created by programmers
  • Default Package: No package declaration (not recommended)
  • Sub-packages: Packages inside packages

Package Naming Conventions

Package names should be in lowercase, use reverse domain name convention (com.company.project), and avoid Java keywords. Example: com.example.mypackage

Package Hierarchy Example
com
└── example
    └── myproject
        ├── utils
        │   ├── StringUtils.java
        │   └── MathUtils.java
        ├── models
        │   ├── User.java
        │   └── Product.java
        └── Main.java

2. Java Built-in Packages

Java provides a rich set of built-in packages that contain pre-written classes for common programming tasks. These packages are part of the Java Development Kit (JDK).

Package Name Description Common Classes Auto-imported?
java.lang Fundamental language classes String, System, Math, Object, Thread Yes
java.util Utility classes and collections ArrayList, HashMap, Scanner, Date, Random No
java.io Input/output operations File, InputStream, OutputStream, Reader, Writer No
java.net Networking operations Socket, URL, HttpURLConnection No
java.awt Abstract Window Toolkit (GUI) Button, Frame, Color, Font No
javax.swing Swing GUI components JFrame, JButton, JTextField No
java.sql Database operations Connection, Statement, ResultSet No
java.time Date and time API (Java 8+) LocalDate, LocalTime, DateTimeFormatter No
java.math Mathematical operations BigInteger, BigDecimal No
java.text Text formatting DateFormat, NumberFormat No
BuiltInPackagesExample.java
// java.lang is automatically imported
// No need for: import java.lang.*;

// Import specific class from java.util
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

// Import entire package (not recommended for large packages)
import java.util.*;

// Import static members
import static java.lang.Math.PI;
import static java.lang.Math.pow;
import static java.lang.System.out;

public class BuiltInPackagesExample {
    public static void main(String[] args) {
        // Using java.lang (auto-imported)
        String message = "Hello from java.lang!";
        out.println(message); // Using static import
        
        // Using java.util
        Scanner scanner = new Scanner(System.in);
        ArrayList list = new ArrayList<>();
        HashMap map = new HashMap<>();
        
        // Using java.math
        java.math.BigDecimal bigDecimal = new java.math.BigDecimal("123.456");
        
        // Using static imports
        double radius = 5.0;
        double area = PI * pow(radius, 2);
        out.println("Area of circle: " + area);
        
        // Using multiple packages
        java.util.Date utilDate = new java.util.Date();
        java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
        
        out.println("Util Date: " + utilDate);
        out.println("SQL Date: " + sqlDate);
        
        scanner.close();
    }
}

3. Creating User-defined Packages

You can create your own packages to organize your classes. User-defined packages follow the same principles as built-in packages.

Project Structure
Project Structure:
📁 myproject/
├── 📁 com/
│   └── 📁 example/
│       └── 📁 utils/
│           ├── StringUtils.java
│           └── MathUtils.java
├── 📁 models/
│   ├── User.java
│   └── Product.java
└── Main.java
StringUtils.java
// Define package name
package com.example.utils;

public class StringUtils {
    
    // Public method - accessible from anywhere
    public static String reverse(String str) {
        return new StringBuilder(str).reverse().toString();
    }
    
    // Package-private method - accessible only within same package
    static boolean isPalindrome(String str) {
        String reversed = reverse(str);
        return str.equalsIgnoreCase(reversed);
    }
    
    // Protected method - accessible within package and subclasses
    protected static int countVowels(String str) {
        int count = 0;
        String vowels = "aeiouAEIOU";
        for(char c : str.toCharArray()) {
            if(vowels.indexOf(c) != -1) {
                count++;
            }
        }
        return count;
    }
    
    // Private method - accessible only within this class
    private static String sanitize(String str) {
        return str.trim().toLowerCase();
    }
}
MathUtils.java
package com.example.utils;

public class MathUtils {
    
    public static int add(int a, int b) {
        return a + b;
    }
    
    public static int subtract(int a, int b) {
        return a - b;
    }
    
    public static int multiply(int a, int b) {
        return a * b;
    }
    
    public static double divide(int a, int b) {
        if(b == 0) {
            throw new ArithmeticException("Division by zero!");
        }
        return (double) a / b;
    }
    
    public static int factorial(int n) {
        if(n < 0) throw new IllegalArgumentException("Number must be non-negative");
        if(n == 0 || n == 1) return 1;
        
        int result = 1;
        for(int i = 2; i <= n; i++) {
            result *= i;
        }
        return result;
    }
    
    public static boolean isPrime(int n) {
        if(n <= 1) return false;
        if(n == 2) return true;
        if(n % 2 == 0) return false;
        
        for(int i = 3; i <= Math.sqrt(n); i += 2) {
            if(n % i == 0) return false;
        }
        return true;
    }
}
User.java (in models package)
package models;

public class User {
    // Private fields - encapsulated
    private String username;
    private String email;
    private int age;
    
    // Constructor
    public User(String username, String email, int age) {
        this.username = username;
        this.email = email;
        this.age = age;
    }
    
    // Public getters and setters
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        if(age >= 0) {
            this.age = age;
        } else {
            throw new IllegalArgumentException("Age cannot be negative");
        }
    }
    
    // Public method
    public void displayInfo() {
        System.out.println("Username: " + username);
        System.out.println("Email: " + email);
        System.out.println("Age: " + age);
    }
    
    // Package-private method
    void updateEmail(String newEmail) {
        this.email = newEmail;
    }
}

4. Importing and Using Packages

The import statement is used to bring classes and interfaces from other packages into your current file.

Main.java (Using imported packages)
// Import specific classes
import com.example.utils.StringUtils;
import com.example.utils.MathUtils;
import models.User;

// Import entire package (use with caution)
// import com.example.utils.*;

// Import static members
import static com.example.utils.MathUtils.add;
import static com.example.utils.MathUtils.multiply;

public class Main {
    public static void main(String[] args) {
        System.out.println("=== Using User-defined Packages ===");
        
        // Using StringUtils
        String text = "Hello World";
        String reversed = StringUtils.reverse(text);
        System.out.println("Original: " + text);
        System.out.println("Reversed: " + reversed);
        
        // Using MathUtils
        int sum = MathUtils.add(10, 20);
        int product = MathUtils.multiply(5, 6);
        System.out.println("\n10 + 20 = " + sum);
        System.out.println("5 * 6 = " + product);
        
        // Using static imports
        int staticSum = add(15, 25);
        int staticProduct = multiply(7, 8);
        System.out.println("\nUsing static imports:");
        System.out.println("15 + 25 = " + staticSum);
        System.out.println("7 * 8 = " + staticProduct);
        
        // Check prime numbers
        System.out.println("\n=== Prime Numbers Check ===");
        int[] numbers = {2, 3, 4, 5, 17, 20, 29};
        for(int num : numbers) {
            boolean isPrime = MathUtils.isPrime(num);
            System.out.println(num + " is prime? " + isPrime);
        }
        
        // Factorial calculation
        System.out.println("\n=== Factorials ===");
        for(int i = 1; i <= 5; i++) {
            int factorial = MathUtils.factorial(i);
            System.out.println(i + "! = " + factorial);
        }
        
        // Using User class from models package
        System.out.println("\n=== User Management ===");
        User user1 = new User("john_doe", "john@example.com", 25);
        User user2 = new User("jane_smith", "jane@example.com", 30);
        
        user1.displayInfo();
        System.out.println("---");
        user2.displayInfo();
        
        // Update user information
        user1.setAge(26);
        System.out.println("\nUpdated age for " + user1.getUsername() + ": " + user1.getAge());
        
        // Working with arrays of objects from packages
        System.out.println("\n=== Array of Users ===");
        User[] users = {
            new User("alice", "alice@example.com", 22),
            new User("bob", "bob@example.com", 28),
            new User("charlie", "charlie@example.com", 35)
        };
        
        for(User user : users) {
            user.displayInfo();
            System.out.println("---");
        }
    }
}
Import Type Syntax Description When to Use
Specific Class import package.ClassName; Import single class from package Most common, recommended
Entire Package import package.*; Import all classes from package Avoid for large packages
Static Import import static package.Class.method; Import static members For utility class methods
Fully Qualified package.Class obj = new package.Class(); Use class without import When name conflicts occur

5. Package Access Control

Java provides four access modifiers that control the visibility of classes, methods, and variables. Packages play a crucial role in access control.

Access Modifier Within Class Within Package Subclasses Outside Package Example
private private int count;
default (no modifier) int count; (package-private)
protected protected void method()
public public class MyClass
AccessControlExample.java
package com.example.access;

// Public class - accessible from anywhere
public class AccessControlExample {
    
    // Public field
    public String publicField = "I'm public";
    
    // Protected field
    protected String protectedField = "I'm protected";
    
    // Default (package-private) field
    String defaultField = "I'm package-private";
    
    // Private field
    private String privateField = "I'm private";
    
    // Public method
    public void publicMethod() {
        System.out.println("Public method called");
        privateMethod(); // Can call private method from same class
    }
    
    // Protected method
    protected void protectedMethod() {
        System.out.println("Protected method called");
    }
    
    // Default (package-private) method
    void defaultMethod() {
        System.out.println("Default method called");
    }
    
    // Private method
    private void privateMethod() {
        System.out.println("Private method called");
    }
    
    // Method to demonstrate access
    public void demonstrateAccess() {
        System.out.println("\nAccess from within same class:");
        System.out.println("Public field: " + publicField);
        System.out.println("Protected field: " + protectedField);
        System.out.println("Default field: " + defaultField);
        System.out.println("Private field: " + privateField);
    }
}

// Default (package-private) class - only accessible within same package
class PackagePrivateClass {
    public void sayHello() {
        System.out.println("Hello from package-private class!");
    }
}
AnotherClassInSamePackage.java
package com.example.access;

public class AnotherClassInSamePackage {
    public static void main(String[] args) {
        AccessControlExample example = new AccessControlExample();
        
        System.out.println("Access from same package:");
        
        // Can access public members
        System.out.println("Public field: " + example.publicField);
        example.publicMethod();
        
        // Can access protected members (same package)
        System.out.println("Protected field: " + example.protectedField);
        example.protectedMethod();
        
        // Can access default members (same package)
        System.out.println("Default field: " + example.defaultField);
        example.defaultMethod();
        
        // Cannot access private members
        // System.out.println(example.privateField); // Compilation error
        // example.privateMethod(); // Compilation error
        
        // Can access package-private class
        PackagePrivateClass pkgClass = new PackagePrivateClass();
        pkgClass.sayHello();
    }
}
DifferentPackageClass.java
package com.example.different;

import com.example.access.AccessControlExample;

public class DifferentPackageClass {
    public static void main(String[] args) {
        AccessControlExample example = new AccessControlExample();
        
        System.out.println("Access from different package:");
        
        // Can only access public members
        System.out.println("Public field: " + example.publicField);
        example.publicMethod();
        
        // Cannot access protected, default, or private members
        // System.out.println(example.protectedField); // Compilation error
        // System.out.println(example.defaultField);   // Compilation error
        // System.out.println(example.privateField);   // Compilation error
        
        // Cannot access package-private class from different package
        // PackagePrivateClass pkgClass = new PackagePrivateClass(); // Compilation error
    }
}

// Subclass in different package
class SubClass extends AccessControlExample {
    public void testAccess() {
        System.out.println("Access from subclass in different package:");
        
        // Can access public members
        System.out.println("Public field: " + publicField);
        publicMethod();
        
        // Can access protected members (through inheritance)
        System.out.println("Protected field: " + protectedField);
        protectedMethod();
        
        // Cannot access default or private members
        // System.out.println(defaultField); // Compilation error
        // System.out.println(privateField); // Compilation error
    }
}

6. Sub-packages and Package Hierarchy

Sub-packages are packages inside other packages. They help create a hierarchical structure for better organization.

Sub-package Structure
com
└── example
    ├── mainapp
    │   ├── controllers
    │   │   ├── UserController.java
    │   │   └── ProductController.java
    │   ├── models
    │   │   ├── User.java
    │   │   └── Product.java
    │   └── Main.java
    └── utils
        ├── StringHelper.java
        └── MathHelper.java
Working with Sub-packages
// File: com/example/mainapp/controllers/UserController.java
package com.example.mainapp.controllers;

import com.example.mainapp.models.User;
import com.example.utils.StringHelper;

public class UserController {
    
    public User createUser(String username, String email) {
        // Validate username using StringHelper from utils sub-package
        if(StringHelper.isValidUsername(username)) {
            return new User(username, email);
        } else {
            throw new IllegalArgumentException("Invalid username");
        }
    }
    
    public void displayUserInfo(User user) {
        System.out.println("User: " + user.getUsername());
        System.out.println("Email: " + user.getEmail());
    }
}

// File: com/example/utils/StringHelper.java
package com.example.utils;

public class StringHelper {
    
    public static boolean isValidUsername(String username) {
        if(username == null || username.trim().isEmpty()) {
            return false;
        }
        // Username must be 3-20 characters, alphanumeric
        return username.matches("^[a-zA-Z0-9]{3,20}$");
    }
    
    public static String capitalize(String str) {
        if(str == null || str.isEmpty()) {
            return str;
        }
        return str.substring(0, 1).toUpperCase() + str.substring(1).toLowerCase();
    }
}

// File: com/example/mainapp/Main.java
package com.example.mainapp;

import com.example.mainapp.controllers.UserController;
import com.example.mainapp.models.User;
import com.example.utils.StringHelper;

public class Main {
    public static void main(String[] args) {
        System.out.println("=== Working with Sub-packages ===");
        
        // Create user controller
        UserController controller = new UserController();
        
        try {
            // Create valid user
            User user1 = controller.createUser("john123", "john@example.com");
            controller.displayUserInfo(user1);
            
            // Try to create invalid user
            User user2 = controller.createUser("ab", "invalid@example.com");
        } catch (IllegalArgumentException e) {
            System.out.println("Error: " + e.getMessage());
        }
        
        // Use StringHelper from utils package
        String name = "jane doe";
        String capitalized = StringHelper.capitalize(name);
        System.out.println("\nOriginal: " + name);
        System.out.println("Capitalized: " + capitalized);
        
        // Check username validity
        String[] usernames = {"alice", "bob123", "charlie_doe", "a", "verylongusername123456789"};
        System.out.println("\n=== Username Validation ===");
        for(String username : usernames) {
            boolean valid = StringHelper.isValidUsername(username);
            System.out.println(username + ": " + (valid ? "Valid" : "Invalid"));
        }
    }
}
Important Notes about Sub-packages:
  • import com.example.* does NOT import sub-packages
  • Sub-packages are treated as separate packages
  • Import each sub-package separately: import com.example.utils.*
  • Package hierarchy doesn't imply access privileges
  • Use meaningful sub-package names: controllers, models, views, utils, etc.

7. Practical Package Examples

Example 1: E-commerce System Package Structure

// File: com/estore/models/Product.java
package com.estore.models;

public class Product {
    private String id;
    private String name;
    private double price;
    private int stock;
    
    public Product(String id, String name, double price, int stock) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.stock = stock;
    }
    
    // Getters and setters
    public String getId() { return id; }
    public String getName() { return name; }
    public double getPrice() { return price; }
    public int getStock() { return stock; }
    
    public void setStock(int stock) { this.stock = stock; }
    
    public void displayInfo() {
        System.out.printf("Product: %s | Price: $%.2f | Stock: %d\n", 
                         name, price, stock);
    }
}

// File: com/estore/services/InventoryService.java
package com.estore.services;

import com.estore.models.Product;

public class InventoryService {
    
    public void updateStock(Product product, int quantity) {
        if(product.getStock() + quantity < 0) {
            throw new IllegalArgumentException("Insufficient stock");
        }
        product.setStock(product.getStock() + quantity);
        System.out.println("Updated stock for " + product.getName() + 
                         " to " + product.getStock());
    }
    
    public boolean checkAvailability(Product product, int quantity) {
        return product.getStock() >= quantity;
    }
}

// File: com/estore/utils/PriceCalculator.java
package com.estore.utils;

public class PriceCalculator {
    
    public static double calculateTotal(double price, int quantity) {
        return price * quantity;
    }
    
    public static double applyDiscount(double total, double discountPercent) {
        return total * (1 - discountPercent / 100);
    }
    
    public static double calculateTax(double amount, double taxRate) {
        return amount * taxRate / 100;
    }
}

// File: com/estore/Main.java
package com.estore;

import com.estore.models.Product;
import com.estore.services.InventoryService;
import com.estore.utils.PriceCalculator;

public class Main {
    public static void main(String[] args) {
        System.out.println("=== E-commerce System ===");
        
        // Create products
        Product laptop = new Product("P001", "Laptop", 999.99, 10);
        Product phone = new Product("P002", "Smartphone", 699.99, 25);
        
        // Display products
        laptop.displayInfo();
        phone.displayInfo();
        
        // Use InventoryService
        InventoryService inventory = new InventoryService();
        inventory.updateStock(laptop, -2); // Sell 2 laptops
        inventory.updateStock(phone, 10);  // Restock 10 phones
        
        // Check availability
        boolean available = inventory.checkAvailability(laptop, 5);
        System.out.println("\n5 laptops available? " + available);
        
        // Use PriceCalculator
        double total = PriceCalculator.calculateTotal(laptop.getPrice(), 3);
        double discounted = PriceCalculator.applyDiscount(total, 10);
        double tax = PriceCalculator.calculateTax(discounted, 8);
        double finalPrice = discounted + tax;
        
        System.out.println("\n=== Price Calculation ===");
        System.out.printf("Subtotal (3 laptops): $%.2f\n", total);
        System.out.printf("After 10%% discount: $%.2f\n", discounted);
        System.out.printf("Tax (8%%): $%.2f\n", tax);
        System.out.printf("Final Price: $%.2f\n", finalPrice);
    }
}

8. Package Best Practices

Common Package Mistakes:
  1. Default package usage: Always use explicit packages
  2. Poor naming: Use meaningful, reverse-domain names
  3. Circular dependencies: Avoid package A depending on B and B depending on A
  4. Wildcard imports: Avoid import java.util.* in large projects
  5. Package sprawl: Too many small packages can be confusing
  6. Ignoring access modifiers: Use appropriate access levels
Package Design Best Practices
  • Use reverse domain name convention: com.company.project
  • Keep packages cohesive - related classes together
  • Avoid cyclic dependencies between packages
  • Use sub-packages for logical separation
  • Follow naming conventions (all lowercase)
  • Keep package size manageable (5-30 classes per package)
  • Use package-info.java for documentation
Organization Strategies
  • By feature: com.example.auth, com.example.payment
  • By layer: controllers, models, services, utils
  • By module: user, product, order modules
  • Mixed approach: Combine based on project needs
  • Separate API from implementation
  • Use common package for shared utilities

Package Design Principles

High Cohesion: Related classes should be together
Low Coupling: Minimize dependencies between packages
Reuse-Release Equivalence: What you release is what you reuse
Common Closure: Classes that change together belong together
Stable Abstractions: Stable packages should be abstract

package-info.java Example
/**
 * Provides utility classes for common operations in the application.
 * 
 * 

This package contains helper classes that provide reusable functionality * for string manipulation, mathematical calculations, date formatting, * and other common tasks.

* *

Package Specification

*
    *
  • {@link com.example.utils.StringHelper} - String manipulation utilities
  • *
  • {@link com.example.utils.MathHelper} - Mathematical operations
  • *
  • {@link com.example.utils.DateHelper} - Date and time utilities
  • *
  • {@link com.example.utils.ValidationHelper} - Input validation
  • *
* * @since 1.0 * @author Your Name * @version 1.0 */ package com.example.utils;