Definition
Package and import rules:
- Package declaration:
package com.bank.core;– first line, matches directory structure. - Import:
import java.util.List;– useListinstead ofjava.util.List. - Wildcard:
import java.util.*;– imports all classes in the package. - Auto-import:
java.lang.*(String, System, Object, Math) is always imported. - Static import:
import static java.lang.Math.PI;– usePIdirectly.
Packages are like departments in a bank: com.bank.core (core domain), com.bank.service (business logic), com.bank.api (REST controllers). Imports are like putting shortcuts on your desk so you do not have to walk to the other department every time.
Understanding the Concepts
Package declaration
Every Java source file can have at most one package declaration, and it must be the very first statement in the file (before any import or class declaration). The package name must match the directory structure on disk.
package com.bank.core; // must be the first statement
public class Account {
// class body
}
The file must be stored at com/bank/core/Account.java (matching the package). If the directory structure does not match, the compiler reports an error.
Import types
Java provides four forms of import. Specific imports bring in one class. Wildcard imports bring in all classes from one package. Static imports bring in static members of a class. You can also use a fully qualified name inline without any import.
import java.util.List; // specific class import
import java.util.ArrayList;
import java.util.*; // wildcard: all classes in java.util
import static java.lang.Math.sqrt; // static: use sqrt() without Math.
import static java.lang.Math.*; // all static members of Math
Specific imports are preferred over wildcard imports because they make dependencies explicit and avoid name conflicts.
What java.lang gives you for free
The java.lang package is automatically imported into every Java source file. You never need to write import java.lang.String or import java.lang.System.
// No import needed for any of these:
String name = "Rajesh"; // java.lang.String
System.out.println(name); // java.lang.System
Object obj = new Object(); // java.lang.Object
int max = Integer.MAX_VALUE; // java.lang.Integer
double pi = Math.PI; // java.lang.Math
NullPointerException npe; // java.lang.NullPointerException
Common naming conventions in banking projects
Package names follow the reverse domain convention. In a banking application, packages organize code by responsibility.
com.bank.core → domain models (Account, Transaction, Customer) com.bank.service → business logic (TransferService, InterestService) com.bank.repository → data access (AccountRepository, TransactionRepository) com.bank.api → REST controllers (AccountController, TransferController) com.bank.config → configuration (AppConfig, SecurityConfig) com.bank.util → utility classes (AccountNumberGenerator, CurrencyFormatter) com.bank.exception → custom exceptions (InsufficientFundsException)
How do import conflicts work?
When two packages contain classes with the same name, a wildcard import creates ambiguity. The compiler cannot decide which class you mean. You must use either a specific import or the fully qualified name.
package com.bank.report;
import java.util.Date; // java.util.Date
import java.sql.Date; // COMPILE ERROR: Date is ambiguous
// Fix 1: import one, qualify the other
import java.util.Date;
public class AuditReport {
Date createdDate = new Date(); // java.util.Date
java.sql.Date sqlDate = java.sql.Date.valueOf("2024-01-15"); // fully qualified
}
This conflict is common in banking applications that mix utility dates with JDBC query dates.
What about static imports?
Static imports let you use static methods and constants without the class name prefix. They are useful for test assertions and mathematical operations.
package com.bank.service;
import java.math.BigDecimal;
import static java.math.BigDecimal.ZERO;
import static java.math.RoundingMode.HALF_UP;
public class InterestCalculator {
public BigDecimal calculateMonthlyInterest(BigDecimal balance, BigDecimal annualRate) {
if (balance.compareTo(ZERO) <= 0) { // ZERO from static import
return ZERO;
}
return balance.multiply(annualRate)
.divide(new BigDecimal("1200"), 2, HALF_UP); // HALF_UP from static import
}
}
Use static imports sparingly. Overusing them makes code harder to read because the reader cannot tell where a name comes from.
What should a senior engineer know?
- Wildcard imports do not import sub-packages.
import java.util.*does NOT importjava.util.concurrent.*. Each package must be imported separately. - Module system (Java 9+) adds
module-info.javawithrequiresandexportsdeclarations. Modules control which packages are visible to other modules, adding a layer beyond just public/private access. - Import conflicts with same class name: always prefer specific imports and use fully qualified names for the second class.
- IDE auto-import handles most import management. IntelliJ can be configured to use specific imports or wildcard imports based on a threshold (typically 5 classes from the same package).
- No runtime cost. Imports are a compile-time convenience. Wildcard imports do not load extra classes into memory. The JVM loads classes only when they are first used.
Visual Overview
package com.bank.core;
import java.util.List;
import java.math.BigDecimal;
public class Account {
List<String> txns; ← uses List (from import)
BigDecimal balance; ← uses BigDecimal (from import)
String name; ← uses String (auto-imported from java.lang)
}
Directory: com/bank/core/Account.java
Key Takeaway
Packages organize classes into namespaces matching the directory structure. Imports let you use classes by simple name. java.lang is auto-imported. Static imports let you use static members without the class name.
One sentence to remember: package declares the namespace, import provides shortcuts, java.lang is always available.
---