Packages and folders
On This Lesson 11 topics
Lesson Overview
Until now, most of your classes have lived side by side in one folder. That works for a toy program. It stops working when a project has fifty classes and two of them are both called Account. Java's answer is the package: a named group of related classes that also gives each class a longer, unique full name.
Think of a filing cabinet. The cabinet is the project, each labeled drawer is a package, and each file in a drawer is a class. A drawer label tells you what is inside, and two drawers can each hold a document called "Summary" without any confusion.
Why this matters: every real Java backend project is organized into packages. The package line at the top of a file, and the folder that file sits in, are the first things you see in any codebase you join. Get this wrong and the compiler or the JVM will not find your classes.
This lesson builds on the encapsulation module, where you met the word package in a short preview of access levels. Here we teach it properly. The next lesson shows how code in one package uses classes from another.
Learning Objectives
By the end of this lesson you will be able to:
- Explain what a package is and why Java has them.
- Write a correct
packageline and place it where Java requires it. - Map a package name to a folder path, and a folder path to a package name.
- Apply the naming conventions: lowercase names and a reversed domain prefix.
- Compile and run a program whose classes sit in two packages, from a terminal.
- Recognize the symptoms of a package line that does not match its folder.
- Explain why a real project must not use the default (unnamed) package.
Written Explanation
What a package is
A package is a named group of related classes and interfaces. It does two jobs:
- Organization. Related classes are kept together, like papers in one drawer.
- A separate name space. The Java Language Specification explains that each package has its own namespace, so two packages can each contain a class with the same simple name. Its own example is
java.util.Vectornext to a different class also calledVectorin another package.
A class's fully qualified name is its package name, a dot, and its simple name. For a class Account in package com.example.bank, the full name is com.example.bank.Account. Account alone is the simple name.
The package statement
The first line of a source file (ignoring comments and blank lines) declares which package the class belongs to:
package com.example.bank;
public class Account { }Rules:
- The
packageline comes before anyimportlines and before the class. The JLS says a package declaration, when present, comes first in the compilation unit. - There is at most one
packageline per file, and it ends with a semicolon. - Every class in a file belongs to the package named in that file.
Package name to folder path
Java source layout follows a simple rule: each dot in the package name is a folder separator. The Java Language Specification describes this for file-system based storage: a package jag.scrabble.board is held in the directories jag/scrabble/board/.
| Package line | Folder (under your source root) | Full file path |
|---|---|---|
package com.example.bank; | com/example/bank/ | com/example/bank/Account.java |
package com.example.app; | com/example/app/ | com/example/app/Main.java |
package bank; | bank/ | bank/Account.java |
The folder where the package tree begins is called the source root. A package line always describes the path from the source root, never the full path on your disk. If your project is in C:\work\bank-demo\src, then src is the source root and the file Account.java for package com.example.bank belongs in src\com\example\bank\.
Naming conventions
The Oracle Java tutorial gives these conventions:
- Package names are all lowercase, so they never look like class names.
- Companies start with their reversed internet domain: a programmer at
example.comnames a packagecom.example.something. This keeps two organizations' packages from clashing. - Within one company or project, add a further part after the domain, such as
com.example.bank. - Names beginning with
java.orjavax.belong to the Java platform itself. Do not use them.
If a domain is not a legal Java name (for example it contains a hyphen), the tutorial suggests replacing the hyphen with an underscore, so hyphenated-name.example.org becomes org.example.hyphenated_name.
For the lessons in this module we use the invented domain example.com, so our packages begin with com.example. In your own projects use a domain you control, or a clearly personal name.
The folder tree does not create packages by itself
A folder is not a package until a file inside it says so. Both must agree: the package line and the folder. If they disagree, tools stop finding your classes. That mismatch is the number-one beginner error with packages, and Example 3 shows it.
The default (unnamed) package
If a file has no package line, its classes belong to the unnamed package, usually called the default package. The JLS says the unnamed package is meant for small or temporary programs. It has a serious limit: types in the unnamed package cannot be imported by code that is in a named package. So the moment your project grows, classes in the default package cannot be used from properly organized code.
That is why "one giant default package" is the common mistake listed for this module. You may keep using it for a five-line experiment, but a project you intend to keep should have named packages from its first day.
Compiling and running with packages
You compile from the source root and tell the compiler where to put the .class files with -d. According to Oracle's javac documentation, -d sets the output directory, and the compiler places each class in a sub-folder that matches its package, creating folders as needed.
javac -d out src/com/example/bank/Account.java src/com/example/app/Main.java
java -cp out com.example.app.MainTwo things to notice:
- You run a class by its fully qualified name (
com.example.app.Main), not by its file name.-cp outtells the JVM where the compiled package folders start. - Oracle's documentation also describes
-sourcepath, which tellsjavacwhere to look for other source files it needs. Withjavac -d out -sourcepath src src/com/example/app/Main.javayou name onlyMain, and the compiler findsAccountby itself.
(The commands above use forward slashes, which work in most Windows terminals as well. Exact terminal behavior can vary, so adjust to your shell. An IDE does all of this for you, but its menus and wording differ between products and versions, so follow your IDE's own help for "new package".)
Examples
Example 1: one class in a package (simple)
File src/com/example/bank/Account.java:
package com.example.bank;
public class Account {
private final String owner;
private double balance;
public Account(String owner, double balance) {
this.owner = owner;
this.balance = balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public String describe() {
return owner + ": " + balance;
}
}The class is public so code in other packages may use it (the next lessons explain why that matters). The package line says com.example.bank, and the file sits in com/example/bank/. They agree.
Example 2: two packages, compiled and run (practical)
A second file, src/com/example/app/Main.java, uses the account. The import line is explained in the next lesson. For now read it as "make Account available here".
package com.example.app;
import com.example.bank.Account;
public class Main {
public static void main(String[] args) {
Account a = new Account("Sara", 100);
a.deposit(50);
System.out.println(a.describe());
System.out.println(a.getClass().getName());
}
}The project tree:
src/
com/example/bank/Account.java
com/example/app/Main.javaCompile and run from the folder that contains src:
javac -d out -sourcepath src src/com/example/app/Main.java
java -cp out com.example.app.MainOutput (we compiled and ran this with JDK 21):
Sara: 150.0
com.example.bank.AccountThe second line shows the fully qualified name: getName() returns the package plus the class name. The compiler also built this output tree, one folder per package segment:
out/com/example/app/Main.class
out/com/example/bank/Account.classExample 3: the folder does not match the package line (realistic)
A beginner creates a folder src/bank/ and puts Account.java there, but leaves the line package com.example.bank; unchanged. Main still has import com.example.bank.Account;. Compiling with -sourcepath src:
error: package com.example.bank does not exist
import com.example.bank.Account;
^
error: cannot find symbol
symbol: class Account
location: class MainThe error message talks about the package not existing, which is confusing. The real cause is that the compiler looked for src/com/example/bank/Account.java, as the package name demands, and found nothing. Move the file to src/com/example/bank/ (or change both the package line and the imports to a shorter package, consistently). Your IDE usually shows this as a warning on the package line, and many IDEs offer a quick fix. Do not rely on one specific menu; check what your IDE suggests.
A related symptom happens at run time. Running java -cp out app.Main when the real class is com.example.app.Main fails with:
Error: Could not find or load main class app.Main
Caused by: java.lang.ClassNotFoundException: app.MainRun the class with its full name.
Backend Insight
Backend projects have many classes: entities, services, data access, configuration. Packages are how teams find things and how they divide the work. In Java build tools such as Maven and Gradle, the convention is that sources sit under a src/main/java source root, and your package tree starts beneath it. Stack traces and log lines print fully qualified class names (com.example.bank.Account), so a clear package name tells you at a glance which part of the system a message came from.
Package names also matter beyond your own code. Frameworks, scanning tools and deployment files refer to your classes by full name. Renaming a package later means changing folders, package lines, imports and any configuration that mentions the old name, so choose a sensible name early. A reversed-domain prefix such as com.yourcompany.projectname is nearly universal.
Common Mistakes
Mistake 1: package line and folder disagree
- Incorrect:
package com.example.bank;in a file stored atsrc/bank/Account.java. - Correct: store it at
src/com/example/bank/Account.java.
When you see "package ... does not exist" for a package you wrote yourself, check the folder first.
Mistake 2: leaving everything in the default package
Classes in the unnamed package cannot be imported from named packages. In our test, a class in a named package that wrote import Helper; for a default-package Helper got the error '.' expected, because an import needs a package name. Put your classes in packages from the beginning.
Mistake 3: the package line is not first
Placing import lines above the package line is a compile error. Order: package, then imports, then the class.
Mistake 4: capital letters and spaces in names
package Bank; compiles, but it breaks the convention and confuses readers, who expect capitalized names to be classes. Use lowercase. Also avoid spaces and hyphens, which are not legal in a package name.
Mistake 5: running a class by its file path
Use java -cp out com.example.app.Main, not a path to the file. The JVM wants the class's full name.
Exercises
Try each exercise yourself before opening the solutions.
Level A: Foundation
A1. A class Cart is declared with package com.acme.shop;. Under the source root src, what is the full path of its file?
Show solution A1
A1. src/com/acme/shop/Cart.java.
A2. What is the fully qualified name of class Receipt in package org.nile.sales?
Show solution A2
A2. org.nile.sales.Receipt.
A3. Which of these package names follows the convention, and what is wrong with the others? Com.Acme.Shop, com.acme.shop, shop-app.
Show solution A3
A3. com.acme.shop follows the convention. Com.Acme.Shop uses capital letters, which are for class names. shop-app has a hyphen, which is not legal in a package name (and has no reversed-domain prefix).
Level B: Application
B1. You have src/org/nile/sales/Receipt.java and src/org/nile/app/Main.java, with Main using Receipt. Write the javac and java commands, using -d out, that compile and run it.
Show solution B1
B1. From the folder that contains src:
javac -d out -sourcepath src src/org/nile/app/Main.java
java -cp out org.nile.app.MainListing both source files after javac -d out also works.
B2. A teammate's tree has the file src/sales/Receipt.java whose first line is package org.nile.sales;. Describe the compile error you expect when another class imports org.nile.sales.Receipt, and give two different fixes.
Show solution B2
B2. The compiler looks for the package at org/nile/sales/ under the source root, does not find Receipt.java there, and reports something like package org.nile.sales does not exist plus cannot find symbol for Receipt. Fix 1: move the file to src/org/nile/sales/Receipt.java. Fix 2: change the package line to package sales; and update every import to match (less ideal, because the name lacks the reversed-domain prefix).
B3. Explain in two sentences why a growing project should not stay in the default package.
Show solution B3
B3. Classes in the default package cannot be imported by classes in named packages, so the project cannot be organized into packages later without moving things. It also lacks the clear, unique full names that tools, logs and teammates rely on.
Level C: Challenge
C1. Your company owns the domain fast-pay.io. Propose the base package for a project called ledger, using the tutorial's rule for illegal characters. Then give the path of class Entry in the sub-package model.
Show solution C1
C1. The tutorial suggests turning the hyphen into an underscore, giving the prefix io.fast_pay. The base package is io.fast_pay.ledger, and the class path is io/fast_pay/ledger/model/Entry.java with package io.fast_pay.ledger.model;.
C2. Two libraries both define a class called Invoice. Explain what feature of Java makes this possible, and what a class's full name would look like for each, if one comes from com.alpha.billing and the other from com.beta.billing.
Show solution C2
C2. Each package has its own namespace, so the same simple name may appear in different packages. The full names are com.alpha.billing.Invoice and com.beta.billing.Invoice.
Mini Challenge
Create a small project on your own machine with this tree and make it run:
src/
com/example/shop/Product.java
com/example/app/Main.javaProduct has a name and a price, both private, a constructor, and a public method label() that returns text such as Pen: 2.5. Main creates one product and prints its label and getClass().getName().
Check your work: both files have a package line that matches their folder; you compiled with -d out; and you launched Main using its full name. Then deliberately move Product.java to a wrong folder and read the error you get, as in Example 3. Put it back.
Summary & Next Lesson
Key takeaways
- A package groups related classes and gives each a unique full name such as
com.example.bank.Account. - The
packageline is the first statement in the file, and each dot in the name is one folder level from the source root. - Package names are lowercase and usually start with a reversed domain.
- Compile with
-dto get a matching.classfolder tree, and run a class by its full name. - A package line that disagrees with the folder gives errors like
package ... does not exist. - The default package cannot be imported from named packages, so real projects avoid it.
Next lesson
You can now place classes in packages, but Main in one package needed an import to see Account in another. The next lesson, "Imports and name clashes", explains how imports work and what to do when two classes share a simple name.
Self-check
- What does the
packagelinepackage com.example.bank;tell you about the file's folder? - Where in the file must the
packageline appear? - Why do companies begin package names with a reversed domain?
- What is the fully qualified name of class
Mainin packagecom.example.app, and how do you run it? - Name one problem with leaving a project in the default package.
Show answers
- The file belongs in
com/example/bank/under the source root. - First: before any
importline and before the class declaration (comments and blank lines may precede it). - It makes names unique, so packages from different organizations do not clash.
com.example.app.Main; run it withjava -cp out com.example.app.Main.- Its classes cannot be imported from named packages, and it gives no unique full names, so it does not scale.
References
- Oracle, The Java Language Specification, SE 21, Chapter 7: Packages and Modules. Supports the definition of packages and namespaces, the
packagedeclaration coming first, the unnamed package for small programs and its import restriction, and the mapping of package names to directories. - Oracle, The Java Tutorials: Naming a Package. Supports lowercase names, the reversed-domain convention, the
java.andjavax.reservation and the underscore rule for illegal characters. - Oracle, javac command reference (JDK 21). Supports what
-dand-sourcepathdo. - The compiler and run outputs shown were produced by running the code with JDK 21. The Maven/Gradle
src/main/javaconvention in Backend Insight is general community practice that we did not verify against a source in this lesson.
Practice
Apply this lesson with the module's lab, exercises and quiz.
Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.