Creating Custom Packages in Java
Create your own Java packages — directory layout, package declaration, and how to compile and use them.
Reading other people's packages is one thing. Creating your own takes three small steps: pick a name, lay out the directory, and put the right package declaration at the top of each file. The compiler and JVM agree on a strict convention, and once you've done it twice it becomes muscle memory. If you're new to the idea of packages, start with the Java packages overview first; this chapter focuses on rolling your own.
The three rules
Anything you write inside a package has to obey exactly three rules:
- The first non-comment statement of the file is the
packagedeclaration. No other statement may precede it. - The file path mirrors the package name.
com.example.util.Stringsmust live atcom/example/util/Strings.javaunder some source root. - The file is named after its public top-level class.
Strings.javaforpublic class Strings.
That's all there is. Everything else is convention.
Choosing a package name
The compiler only enforces the three rules above, but a handful of naming conventions keep your packages collision-free and idiomatic:
- All lowercase.
com.w3docs.greet, nevercom.W3Docs.Greet. Uppercase letters in package names work but break the convention every other Java developer expects, and they cause problems on case-insensitive file systems. - Reverse your domain name. If you own
w3docs.com, your packages start withcom.w3docs. This guarantees global uniqueness so yourGreeternever clashes with someone else'sGreeteron the classpath. - No Java keywords. A package segment can't be a reserved word. If your domain were
int.example.com, you couldn't writecom.example.int— you'd escape it, e.g.com.example.int_. - No leading digits in a segment.
com.3m.tapeis illegal because3misn't a valid identifier; a common fix iscom._3m.tape.
If you don't declare a package at all, your classes land in the default package — fine for a throwaway snippet, but classes there can't be imported by packaged code, so avoid it in real projects.
A minimal example
Suppose you want a tiny utility package called com.w3docs.greet. Here's the layout:
project/
└── src/
└── com/
└── w3docs/
└── greet/
├── Greeter.java
├── Greeting.java
└── Main.javaGreeting.java:
package com.w3docs.greet;
public record Greeting(String language, String text) {}Greeter.java:
package com.w3docs.greet;
public class Greeter {
public Greeting greet(String name) {
return new Greeting("en", "Hello, " + name + "!");
}
}Main.java:
package com.w3docs.greet;
public class Main {
public static void main(String[] args) {
System.out.println(new Greeter().greet("Ada").text());
}
}All three files start with the same package com.w3docs.greet; line. Because they share a package, Greeter and Main can use Greeting with no import — you only import types from other packages.
Compiling and running from the command line
From the project/ root, the canonical commands are:
# Compile every .java file under src/ into a parallel tree under out/
javac -d out $(find src -name "*.java")
# Run a main class by its fully-qualified name, telling the JVM where out/ is.
java -cp out com.w3docs.greet.Main-d out tells javac where to put the compiled .class files; it preserves the package directory structure. -cp out (classpath) is how java finds them at runtime — the next chapter on the Java classpath goes into the details.
If the package declaration doesn't match the file's location relative to the source root, javac accepts it (the package is what's declared, not what's inferred from the path) — but java will fail at runtime with NoClassDefFoundError. Always keep the two in sync.
Sub-packages aren't nested
It's tempting to think com.example "contains" com.example.util, but to the Java compiler they're two unrelated packages that happen to share a name prefix. A class in com.example has no special access to com.example.util's package-private members. There is no package inheritance.
What sub-packages do give you is a directory tree that's easy to navigate and a logical place to group related code. Most real projects use sub-packages by feature (auth, billing, parser) or by layer (controller, service, repository) — but neither choice gives the sub-package any extra access.
Compilation units and package-info.java
A .java file is also called a compilation unit, and it can contain:
- One
packagedeclaration (or none, for the default package). - Any number of
importdeclarations. - Any number of type declarations, of which at most one may be
public, and that one must match the file name.
There's also a special file named package-info.java whose only job is to carry package-level Javadoc and annotations:
/**
* Greeting utilities for the W3Docs Java book.
*/
@NullMarked
package com.w3docs.greet;No types — just the comment, optional annotations, and the package line. You'll see this in well-documented libraries.
A worked example
This program declares two types that would live in the same package in a real project and uses them together. The runnable widget here flattens the file structure so you can see the wiring in a single source listing, but in a real project each public type would live in its own .java file under the directory layout shown above.
What's next
Custom packages cover the code you write yourself. Most of the time, though, you'll lean on the JDK's packages — the standard library classes for collections, I/O, time, and so on. The next chapter is a guided tour of the ones you'll touch most often. Continue to Java built-in packages.