Learn Java

Lesson 44Phase 5: Errors, files and the standard library

Packages and imports

Organizing classes into folders with names, importing what you need, and the classpath.

By Updated 50 min

  • package
  • import
  • classpath
  • fully qualified name
  • java.util
  • access across packages

Every program in this course so far has fit in one file. A real Java project has hundreds of classes, written by different people, and now and then two of them want the same name. Java keeps them apart by sorting classes into named groups called packages. You have used packages since your first ArrayList, through the import lines at the top of your programs. This lesson explains what those lines do, how to put your own classes into packages, and how Java finds a class while a program runs.

By the end of this lesson
  • Say what a package is, and how its dotted name matches folders on disk.
  • Write a package declaration and the kinds of import line you will meet: one class, a whole package, static members and a whole module.
  • Use a fully qualified name in place of an import, and predict which class a short name means when two classes share it.
  • Compile and run a program spread over several packages, and say what the classpath and a JAR file are.
  • Decide whether a class, field or method can be used from another package: public, protected or package access.
From before
You have written import java.util.ArrayList; since ArrayList, and import java.util.Scanner; for keyboard input since if, else and switch. In encapsulation you met public, private and package access, and inheritance added protected. Both lessons said the differences only show once a program is split into packages. This is where that happens.

Start with the clutter#

Picture a banking application. It has a class for a customer, a class for an account, a class for a transaction, a class that prints reports, a class that talks to the database, and dozens more. Now imagine all of those sitting loose in a single folder, every .java file shoulder to shoulder with no grouping. Finding the one you want means scrolling through a wall of names. Worse, two different parts of the project might both want a class called Reader: one that reads bank records, one that reads a file. With everything in one pile, those two names collide and the language has no way to tell them apart.

Key idea

A package is a named group of related classes. It works like a folder, with one twist: the package name is written into the code itself, so Java always knows which group a class belongs to.

Coming from Python?
Java packages do the job of Python packages and modules, and import java.util.ArrayList; plays the part of from collections import deque. Two differences: a Java import runs no code and only lets you write a shorter name, and the package name must match the folders the file sits in.

Declaring a package#

To put a class into a package, you write one line at the very top of its file, above everything except comments. It names the package the class belongs to.

Customer.java
read along
1package com.bank.model;
2
3public class Customer {
4 private String name;
5 private String email;
6}

That first line, package com.bank.model;, says “this class lives in the package com.bank.model”. Each dot in the name is one step deeper into a folder, so the package com.bank.model matches the folder path com/bank/model, and the file Customer.java sits inside that last folder. When Java needs a class, it turns the dots of its package into folders and looks there. A file in the wrong folder is a file Java cannot find, and the compiler reports package com.bank.model does not exist.

Here is how the bank's classes lay out on disk. The dotted names become nested folders under src, the folder that holds the source code.

project layout
read along
1src/
2 com/
3 bank/
4 app/
5 Main.java (package com.bank.app;)
6 model/
7 Customer.java (package com.bank.model;)
8 Account.java (package com.bank.model;)
9 report/
10 Printer.java (package com.bank.report;)
The package line goes first, and only once
The package declaration must come before any import line and any class. Only comments may sit above it. A file belongs to exactly one package, so it has at most one package line. A file with no package line puts its classes in the unnamed package, also called the default package. Every runnable program in this course lives there, which is fine for programs of one file. A real project gives every class a named package.
Quick check
A file starts with package com.shop.cart; and declares public class Basket. Where does Basket.java belong?

The full name of a class#

Once a class lives in a package, its complete name includes the package. The class above is Customer for short, and its full name is com.bank.model.Customer: the package, a dot, then the class. That long form is called the fully qualified name. It names one class and no other, anywhere in the world, because the package pins down which Customer you mean.

Nobody wants to type com.bank.model.Customer every time, so Java lets you use the short name, Customer, as long as the compiler can tell which class you mean. Inside the same package it can tell on its own. From another package you have to say, and that is what import is for.

Short name
Fully qualified name
Just the class: Customer.
Package plus class: com.bank.model.Customer.
Convenient, what you write most of the time.
Long, but never ambiguous.
Works only when the compiler knows the package (same package, or imported).
Works anywhere, with no import.
You read it everywhere: Scanner in;
You see it in documentation and error messages: java.util.Scanner.
Can clash when two packages have a class with the same name.
Cannot clash: the package makes it unique.

An import line is a convenience, never a requirement. You can always skip it and write the full name in place. This program uses three classes from java.util and imports none of them. It reads two names from the keyboard input box and prints them in alphabetical order:

FullNames.java
1public class Main {
2 public static void main(String[] args) {
3 java.util.Scanner in = new java.util.Scanner(System.in);
4 java.util.ArrayList<String> names = new java.util.ArrayList<>();
5
6 names.add(in.nextLine());
7 names.add(in.nextLine());
8 java.util.Collections.sort(names);
9
10 System.out.println(names);
11 }
12}
Prints
›Grace
›Ada
›[Ada, Grace]

It prints [Ada, Grace]. It also shows why hardly anyone writes Java like this: every class name drags its package along with it.

Bringing a class into scope with import#

An importline tells the compiler: “when I write this short name, I mean the class from that package”. Here is the same program with three imports at the top.

Imports.java
1import java.util.ArrayList;
2import java.util.Collections;
3import java.util.Scanner;
4
5public class Main {
6 public static void main(String[] args) {
7 Scanner in = new Scanner(System.in);
8 ArrayList<String> names = new ArrayList<>();
9
10 names.add(in.nextLine());
11 names.add(in.nextLine());
12 Collections.sort(names);
13
14 System.out.println(names);
15 }
16}
Prints
›Grace
›Ada
›[Ada, Grace]

The output is the same. Read the top of the file as the list of classes it borrows. After import java.util.Scanner;, writing Scanner is enough, because you said which one you meant. An import copies no code into your file and loads nothing while the program runs. It only tells the compiler how to read a short name. The compiled .class file refers to every class by its full name, so the import lines are gone once compiling is done.

The Run button does not check imports
The engine on this page runs a program even when an import line is missing. Real Java does not: leave out import java.util.Scanner; and javac stops with cannot find symbol. Write every import as if javac were checking, because on your own computer it is.

Importing a whole package#

You write one import per class. When a file uses many classes from one package, a star imports them all: import java.util.*; makes every public class in java.util available by its short name. This is called an on-demand import, because the compiler only looks in java.util when it meets a short name it does not otherwise know.

imports
read along
1import java.util.ArrayList; // one class
2import java.util.Scanner; // and another
3
4import java.util.*; // or every public class in java.util
Prefer one class per line
Most teams and most editors prefer one import per class. The list at the top then tells a reader exactly what the file depends on, and it can never pull in a name you did not expect. Your editor adds and removes those lines for you as you type, so being exact costs nothing.

A star brings in classes, never other packages. Package names look nested, as in java.util and java.util.function, but Java treats them as two unrelated packages that happen to share the start of their names. So import java.util.*; does not cover Function, which lives in java.util.function. Here is javac's answer to a file that imports java.util.* and then uses Function:

Terminal
read along
1$ javac Main.java
2Main.java:6: error: cannot find symbol
3 Function<String, Integer> size = String::length;
4 ^
5 symbol: class Function
6 location: class Main
71 error

The fix is one more line: import java.util.function.Function;.

Quick check
A file starts with import java.util.*; and nothing else. Which line still needs an import of its own?

java.lang: the package you never import#

You have used String, System and Math since your very first program, and you never wrote an import for them. They live in a package called java.lang, and Java imports it into every file for you, as if each one began with import java.lang.*;. It holds the classes almost every program needs, so the language spares you the line.

NoImports.java
1public class Main {
2 public static void main(String[] args) {
3 String s = "hello";
4 int max = Math.max(2, 5);
5 System.out.println(s.toUpperCase() + " " + max);
6 }
7}
Prints
›HELLO 5

It prints HELLO 5. Every class in it, String, Math and System, comes from java.lang. Anything outside java.lang must be imported or written out in full. These are the packages you have met so far, and some you will meet soon:

PackageSome of its classesWhere you meet it
java.langString, Math, System, Integer, ObjectEvery program. Imported for you.
java.utilArrayList, HashMap, List, Scanner, CollectionsArrayList and every collection since
java.util.functionFunction, Predicate, SupplierEnums and lambdas
org.junit.jupiter.apiTest, AssertionsTesting with JUnit. A library, not part of Java itself.
java.ioBufferedReader, FileWriter, IOExceptionReading files, later in this phase
java.timeLocalDate, DurationDates and times, later in this phase
The documentation page of every class names its package near the top, so you can always look up what to import.

Static imports#

A normal import brings in a class. A static import brings in the static members of a class, its static methods and constants, so you can use them with no class name in front. You met one in testing with JUnit: import static org.junit.jupiter.api.Assertions.assertEquals; is why a test can say assertEquals(...) where it would otherwise need Assertions.assertEquals(...). Math works the same way.

StaticImports.java
1import static java.lang.Math.PI;
2import static java.lang.Math.max;
3import static java.lang.Math.sqrt;
4
5public class Main {
6 public static void main(String[] args) {
7 double radius = 3.0;
8 System.out.printf("Area: %.2f%n", PI * radius * radius);
9
10 int best = max(72, 91);
11 System.out.println("Best score: " + best);
12
13 System.out.println("Square root of 49: " + sqrt(49));
14 }
15}
Prints
›Area: 28.27
›Best score: 91
›Square root of 49: 7.0

It prints Area: 28.27, Best score: 91 and Square root of 49: 7.0. Each line at the top names one member: PI is a constant, and max and sqrt are methods. import static java.lang.Math.*; would bring in every static member of Math at once. Math itself needs no import, since it is in java.lang. The static imports only save you writing Math. in front of each member.

Use static imports sparingly
A reader who meets max(72, 91) has to scroll to the top of the file to learn where max comes from. Static imports pay off for a few members a file uses again and again, such as assertEquals in a test class, or the collectors in stream code: in Collectors and stream recipes you will see lines like import static java.util.stream.Collectors.groupingBy;.
ExerciseFurniture.java
A furniture shop needs two measurements. Finish tableArea so it returns the area of a round table top, PI times the radius times the radius, and diagonal so it returns the diagonal of a rug: the square root of the width squared plus the length squared. PI is already imported; add a static import for sqrt so you can call it without Math. in front.

When two classes share a short name#

Packages exist so that two classes can share a short name, and now and then two of them meet in one file. Java decides which one a short name means with a few rules:

  • A class declared in your own file, or elsewhere in your own package, beats a class that a star import offers. Java does not warn you.
  • An import that names one class beats a star import.
  • If two star imports both offer the name, javac refuses to guess, and using the short name is an error.
  • A fully qualified name always means exactly one class, whatever the imports say.
Predict the outputDice.java
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 Random die = new Random();
6 List<Integer> rolls = new ArrayList<>();
7 for (int i = 0; i < 3; i++) {
8 rolls.add(die.nextInt(6) + 1);
9 }
10 System.out.println(rolls);
11 }
12}
13
14class Random {
15 int nextInt(int bound) {
16 return 3;
17 }
18}

This program imports java.util.*, which includes Java's own Random class, and it also declares a class called Random. What does it print?

It prints [4, 4, 4] on every run. The class Random at the bottom of the file beats the Random that the star import offers, so dieis the program's own loaded die, and each roll is 3 plus 1. Java gives no warning. With import java.util.Random; at the top instead, javac would refuse the file with Random is already defined in this compilation unit, which at least tells you about the clash.

The third rule shows up with two star imports. java.awt, Java's older toolkit for windows and buttons, has a class called List too: a list box drawn on the screen. Import both packages with stars, and javac cannot tell which List you mean.

Main.java (does not compile)
read along
1import java.awt.*;
2import java.util.*;
3
4public class Main {
5 public static void main(String[] args) {
6 List<String> names = new ArrayList<>();
7 names.add("Ada");
8 System.out.println(names);
9 }
10}
Terminal
read along
1$ javac Main.java
2Main.java:6: error: reference to List is ambiguous
3 List<String> names = new ArrayList<>();
4 ^
5 both interface java.util.List in java.util and class java.awt.List in java.awt match
61 error

Either of two fixes works. Add import java.util.List; below the star imports, and the single-class import wins the short name. Or write the full name, java.util.List<String> names, and leave the short name out of it. With either change the program compiles and prints [Ada].

One import for all of java.base#

Java 25 adds a wider import still. A moduleis a named group of packages that ship together. Modules arrived in Java 9, and the core of Java's library is a module called java.base, which holds java.lang, java.util, java.util.function, java.io, java.time, java.math and dozens more. The line import module java.base; imports every public class of every one of those packages.

ModuleImport.java
1import module java.base;
2
3public class Main {
4 public static void main(String[] args) {
5 List<String> payees = new ArrayList<>(List.of("Rent", "Gym", "Bakery"));
6 Collections.sort(payees);
7
8 Map<String, Integer> visits = new TreeMap<>();
9 visits.put("Bakery", 3);
10
11 LocalDate payday = LocalDate.of(2025, 9, 26);
12 Function<String, Integer> letters = String::length;
13
14 System.out.println(payees + " " + visits);
15 System.out.println(payday.getDayOfWeek() + " " + letters.apply("Bakery"));
16 }
17}
Prints
›[Bakery, Gym, Rent] {Bakery=3}
›FRIDAY 6

One line, and List, Map, LocalDate and Function all work, from four different packages. The wider an import, the more names it can clash on, and a single-class import settles a clash here just as it does for star imports. Most projects still list their classes one by one, so import module suits small programs and experiments best. It also explains something from your first Java program: a compact source file, the kind that starts with void main(), gets import module java.base; automatically, so it can use List or Scanner without a single import line.

The classpath: where Java goes looking#

There is a gap to close. When your program says new Account("Maya"), the running Java machine has to find the compiled Accountcode somewhere on the computer and load it. Java's own classes, such as Scanner, come with the JDK, and Java always knows where they are. For every other class, your own and those of any library you use, Java searches the classpath: the list of places where it looks for compiled classes.

Remember that the Java machine runs bytecode, not source code. javac compiles each .java file into a .class file, and the .class files are what run. When the program needs the class com.bank.model.Account, Java goes through each place on the classpath and looks for com/bank/model/Account.class inside it. It is the same mirror-the-folders rule, used again while the program runs.

Here is the whole trip for a two-file version of the bank. The account lives in one package and the program that uses it in another.

src/com/bank/model/Account.java
read along
1package com.bank.model;
2
3public class Account {
4 private final String owner;
5 private double balance;
6
7 public Account(String owner) {
8 this.owner = owner;
9 }
10
11 public void deposit(double amount) {
12 balance = balance + amount;
13 }
14
15 public String getOwner() {
16 return owner;
17 }
18
19 public double getBalance() {
20 return balance;
21 }
22}
src/com/bank/app/Main.java
read along
1package com.bank.app;
2
3import com.bank.model.Account;
4
5public class Main {
6 public static void main(String[] args) {
7 Account acc = new Account("Maya");
8 acc.deposit(250.0);
9 System.out.println(acc.getOwner() + " has " + acc.getBalance());
10 }
11}

From the folder that holds src, two commands compile the program and run it:

Terminal
read along
1$ javac -d out src/com/bank/model/Account.java src/com/bank/app/Main.java
2$ java -cp out com.bank.app.Main
3Maya has 250.0

-d out tells javac to put the compiled files in a folder called out, and it builds the package folders inside it for you:

out, after javac
read along
1out/
2 com/
3 bank/
4 app/
5 Main.class
6 model/
7 Account.class

-cp out, short for classpath, makes out the one place Java searches. And java takes the class's full name, com.bank.app.Main, never a file name. It turns the dots into folders and loads out/com/bank/app/Main.class. When main first uses Account, Java finds out/com/bank/model/Account.class the same way.

Key idea

The classpath is the list of folders and JAR files Java searches when a running program needs a class that is not part of Java itself. In each one, Java looks for the folders that match the class's package.

Quick check
You run java -cp out com.bank.app.Main. Which file does Java load to start the program?

When Java cannot find a class#

Give java a short name, or leave out the classpath, and it cannot find your program at all:

Terminal
read along
1$ java -cp out Main
2Error: Could not find or load main class Main
3Caused by: java.lang.ClassNotFoundException: Main
4$ java com.bank.app.Main
5Error: Could not find or load main class com.bank.app.Main
6Caused by: java.lang.ClassNotFoundException: com.bank.app.Main

The first command asks for a class called Main in no package, so Java looks for out/Main.class, which does not exist. The second command has no -cp, so Java searches the default classpath: the folder you are standing in. There is no com/bank/app/Main.class directly inside it.

JAR files#

Projects rarely hand around folders of .class files. They pack them into a JAR file (short for Java ARchive): a single zip file holding .class files in their package folders. The jar tool that comes with the JDK makes one. Here the model package goes into a JAR, its loose class files are deleted, and the program runs twice:

Terminal
read along
1$ jar --create --file lib/bank-model.jar -C out com/bank/model
2$ rm -r out/com/bank/model
3$ java -cp out com.bank.app.Main
4Exception in thread "main" java.lang.NoClassDefFoundError: com/bank/model/Account
5 at com.bank.app.Main.main(Main.java:7)
6Caused by: java.lang.ClassNotFoundException: com.bank.model.Account
7 at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
8 at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:502)
9 ... 1 more
10$ java -cp out:lib/bank-model.jar com.bank.app.Main
11Maya has 250.0

Read the first run closely. The program starts, then crashes on line 7, the first line that uses Account. Java loads each class the first time it is needed, and Account is no longer in out. A NoClassDefFoundError means a class that was there when the code was compiled is missing while it runs. (The line numbers inside java.base depend on your Java version.) Put the JAR on the classpath after a colon, and the program works again: Java searches a JAR exactly as if it were a folder. On Windows the entries are separated by a semicolon instead, as in out;lib\bank-model.jar.

Compiled fine, will not run
This is the error behind most “it compiled, so why will it not run?” questions. When a program uses a library, such as the database driver in connecting with JDBC, the library's JAR has to be on the classpath when the program runs, as well as when it compiles.

Reaching across a package boundary#

Packages do more than tidy your files. They draw a boundary that the access modifiers from encapsulation and inheritance respect. In a one-file program every class shares the unnamed package, so the boundary never showed. Split the bank into packages and it does.

A class with no modifier in front of the word class has package access, also called package-private: only classes in the same package can use it. To use a class from another package, it must be public. Fields and methods follow the same rule, and protected opens one more door: a protected member can also be used inside a subclass in another package. Here is an account with one field of each kind, a program that uses it, and a savings account that extends it. Main and SavingsAccount are both in com.bank.app.

src/com/bank/model/Account.java
read along
1package com.bank.model;
2
3public class Account {
4 public String owner;
5 protected double balance;
6 String branch = "Leeds";
7
8 public Account(String owner) {
9 this.owner = owner;
10 }
11}
src/com/bank/app/Main.java
read along
1package com.bank.app;
2
3import com.bank.model.Account;
4
5public class Main {
6 public static void main(String[] args) {
7 Account acc = new Account("Maya");
8 System.out.println(acc.owner);
9 acc.balance = 500.0;
10 acc.branch = "York";
11 }
12}
src/com/bank/app/SavingsAccount.java
read along
1package com.bank.app;
2
3import com.bank.model.Account;
4
5public class SavingsAccount extends Account {
6 public SavingsAccount(String owner) {
7 super(owner);
8 }
9
10 public void addInterest() {
11 balance = balance * 1.02;
12 }
13
14 public void moveBranch() {
15 branch = "York";
16 }
17}
Terminal
read along
1$ javac -d out src/com/bank/model/Account.java src/com/bank/app/Main.java src/com/bank/app/SavingsAccount.java
2src/com/bank/app/Main.java:9: error: balance has protected access in Account
3 acc.balance = 500.0;
4 ^
5src/com/bank/app/Main.java:10: error: branch is not public in Account; cannot be accessed from outside package
6 acc.branch = "York";
7 ^
8src/com/bank/app/SavingsAccount.java:15: error: branch is not public in Account; cannot be accessed from outside package
9 branch = "York";
10 ^
113 errors

Walk the boundary one field at a time. owner is public, so line 8 of Main is fine. balance is protected: Main is neither in com.bank.model nor a subclass, so line 9 fails, while line 11 of SavingsAccount, which uses balance inside a subclass, compiles without complaint. branch has package access, so only classes in com.bank.model may touch it. Both other classes fail on it, and extending Account does not help.

ModifierSame classSame packageSubclass in another packageAny other class
publicYesYesYesYes
protectedYesYesYesNo
none (package access)YesYesNoNo
privateYesNoNoNo
Who can use a field or method with each modifier. A subclass in another package reaches protected members inside its own code. A top-level class is either public or has package access.
A common first error: forgetting public
Beginners often write class Account in one package, then cannot understand why another package will not compile against it. Without public the class has package access, so the other package cannot see it at all, and javac says so: Account is not public in com.bank.model; cannot be accessed from outside package. The fix is one word, public class Account. The same trap catches constructors and methods you meant to share. If another package needs it, it must say public.
Quick check
A class Audit in package com.bank.model, next to Account, runs acc.branch = "York"; on an Account called acc. Does it compile?

Putting the whole picture together#

Here is the full life of a name, from the file that defines it to the program that uses it, in four steps.

  1. 1A class declares its package on the first line: package com.bank.model;. On disk it sits in the matching folder, com/bank/model.
  2. 2That gives the class a fully qualified name, com.bank.model.Account, which no other class in the world shares.
  3. 3A class in another package writes import com.bank.model.Account; so it can use the short name Account. For that to be allowed, Account must be public.
  4. 4When the program runs, Java searches the classpath for com/bank/model/Account.class and loads it. The folders mirror the package name once more.

The same correspondence shows up three times: in the folders that hold the source files, in the fully qualified name, and on the classpath while the program runs. Hold onto it and packages stop being mysterious. They are folders whose names the language keeps track of.

Put the lines in orderBestScore.java
Put this file back in order. The import lines go above the class, and their order among themselves does not matter. The program should print Best: 91.

Tap a line, then tap where it should go. Or use the arrows.

Try it

Answer each one in your head or on paper first, then open the answer.

1
The file src/org/library/loans/Loan.java holds a class called Loan. What is the class's fully qualified name, and what is the first line of the file?
2
You wrote System.out.println(...) and never imported System. Why does it work with no import?
3
What is the fully qualified name of the Scanner class? Write the two ways to create one: with an import, and without.
4
A class Account in package com.bank.model is written as class Account with no modifier. A class in com.bank.app imports it and fails to compile. What single word fixes it, and why?
5
What does import static java.lang.Math.max; let you write, and why does Math itself never need an import?
6
A program compiles, but java -cp out com.bank.app.Main stops with NoClassDefFoundError: com/bank/model/Account. What has gone wrong, in one sentence?

Practice

Work through these on your own. Each one builds on this page.

1
Design the package layout for a small library application with the classes Book, Member, Loan, LoanReport and a Main that runs it. Choose package names, draw the folder tree under src showing which .java file sits where, and write the package line at the top of each file.
2
Take your design from the first problem. For Main, write every import line it needs to use the other four classes by their short names. Then decide, for each class, whether it must be public, and say why.
3
If you have Java on your own computer (see your first Java program), build the two-file bank from the classpath section in a folder of its own. Compile it with javac -d out and run it with java -cp out com.bank.app.Main. Then break it on purpose in three ways, one at a time: remove public from class Account, run it with the short name Main, and delete Account.class from out. Match each message you get to the explanation on this page.
4
Write a program that uses LocalDate, ArrayList and Function. Give it the narrowest imports that work, one class per line, then rewrite the top with import module java.base;. Write two sentences on which version you would rather read in a large project, and why.

Further reading#

Short guides on this topic

Quick answers to what people search for about it, with code to run.

Spotted a mistake, or a part that did not make sense? Report it by email