The cscd211Comparators Package Convention
Before You Start
Check each box you can do from memory. A box you cannot check yet is not a problem; it points you to a quick refresher, not a grade.
Not sure? Take the 60-second self-check.
1. Package declaration. Where in a Java source file does the package declaration appear?
Check
Line 1 of the file, before any import statements and before the class declaration. It takes the form package packageName;.
2. Import statement. A class in package cscd211Comparators needs to use Player from cscd211Classes. What import statement is required?
Check
import cscd211Classes.Player;
3. Package vs. directory. If a file is physically placed in the cscd211Comparators/ directory but has no package declaration, what package does Java consider it to be in?
Check
The default (unnamed) package. A class in the default package cannot be imported by name from another package. The physical directory and the declared package are separate; both must agree.
Try This First
Look at this directory listing from F19 Lab 1:
cscd211Classes/
Player.java
Team.java
cscd211Enums/
NFLTeam.java
Position.java
cscd211Comparators/
TeamComparator.java
PositionComparator.java
GamesPlayedComparator.java
cscd211Methods/
CSCD211Lab1Methods.java
cscd211Lab1/
CSCD211Lab1.java
Before reading further: a new requirement asks for a fourth comparator that orders players by jersey number. Write down (a) which directory the new file goes in and (b) what the first two non-blank lines of the file are.
Check
(a) The file goes in cscd211Comparators/.
(b) Line 1: package cscd211Comparators; Line 2 (blank), then the import: import java.util.Comparator;
What You Need To Walk In With
Player is data. TeamComparator is a strategy for ordering that data. Separating them into different packages makes the dependency direction visible in the directory tree: comparators depend on data classes, but data classes know nothing about comparators. Deleting all comparator files leaves Player.java untouched. Deleting Player.java would break every comparator in the package.
If the package and import mechanics feel uncertain right now, focus on the two required lines at the top of every comparator file: write them before the class declaration, every time, and the compiler will tell you if the directory does not match. You can: name all five standard CSCD 211 packages and what each one holds, write the correct package declaration and import statements for a new comparator from scratch, predict the compile error a missing package declaration causes, and explain the one-way dependency that keeps data classes free of comparator knowledge.
How It Works
The five-package layout
CSCD 211 labs follow this structure (from F19.Lab1-Review):
| Package | Contents |
|---|---|
cscd211Classes |
Data types: Player, Team, Book |
cscd211Enums |
Enum types: NFLTeam, Position, Genre |
cscd211Comparators |
Named Comparator classes: TeamComparator, PositionComparator, ... |
cscd211Methods |
The lab’s main class and helper methods |
cscd211Utils |
Provided utilities (ArrayUtils, FileUtils, etc.) shipped as a JAR |
The complete structure of a comparator file
Every file in cscd211Comparators follows this header:
package cscd211Comparators; // line 1: package declaration
import java.util.Comparator; // required: brings in the interface
import cscd211Classes.Player; // required: brings in the type being compared
public class TeamComparator implements Comparator<Player>
{
@Override
public int compare(final Player a, final Player b)
{
if (a == null || b == null)
throw new IllegalArgumentException("Bad Player in TeamComparator.compare");
return a.getTeam().compareTo(b.getTeam());
}
}
Four things must be in place:
| Item | What goes wrong if it is missing |
|---|---|
package cscd211Comparators; |
The class lands in the default package; any import cscd211Comparators.TeamComparator; in another file fails to resolve |
import java.util.Comparator; |
The interface name Comparator does not resolve; the compiler reports a symbol-not-found error |
import cscd211Classes.Player; |
The type Player does not resolve; the compiler reports a symbol-not-found error |
public class ... |
The class is package-private; it cannot be instantiated from cscd211Lab1 (a different package) |
Quick check
Check your understanding
A file named RatingComparator.java compares Movie objects from cscd211Classes. Which header exactly matches the required package declaration and two import statements?
Why comparators belong in their own package
The cscd211Classes package contains the domain model. It is the answer to the question “what data does this lab work with?” Adding comparators to that package mixes two concerns: “what is a Player?” and “in what orders can we sort Players?” These are separate questions that change for separate reasons.
The cscd211Comparators package contains the answer to the second question alone. Keeping them separate makes both questions easier to answer from the directory listing.
Singular vs. plural: a real drift
Labs from F17 and SP19 sometimes use cscd211Comparator (singular) instead of cscd211Comparators (plural). The correct spelling for current labs is cscd211Comparators (plural). If an IDE auto-completes the import and offers both spellings, pick the one that matches the package declaration at the top of the comparator file.
Worked Example: Predict Then Check
A student creates JerseyNumberComparator.java and places it in the cscd211Comparators/ directory but forgets to add the package declaration. The main class in cscd211Lab1/CSCD211Lab1.java contains:
import cscd211Comparators.JerseyNumberComparator;
Predict the compile error and state the fix.
Step-by-step reasoning
The file has no package declaration, so the compiler places it in the default package. The import statement import cscd211Comparators.JerseyNumberComparator looks for a class named JerseyNumberComparator in the package cscd211Comparators. That class does not exist in that package because it is in the default package. The import fails to resolve.
Show answer
Compile error (in CSCD211Lab1.java):
error: cannot find symbol
import cscd211Comparators.JerseyNumberComparator;
^
Fix: Add package cscd211Comparators; as the first line of JerseyNumberComparator.java.
Source: JLS §7.4 (Package Declarations).
Common Misconceptions
Misconception 1: comparators belong in the same package as the class they compare
Wrong mental model: “TeamComparator works with Player, so it should be in
cscd211Classes/alongside Player.”
Why it breaks: cscd211Classes is the domain model. Adding comparators to it mixes two concerns that change for separate reasons. The directory listing no longer separates “what data exists” from “how to sort that data.” More practically, adding a fifth comparator later requires editing the cscd211Classes package, which also contains entirely unrelated classes.
How to correct: Comparators go in cscd211Comparators. The dependency runs one way: comparators import from cscd211Classes; cscd211Classes imports nothing from cscd211Comparators.
Misconception 2: placing the file in the correct directory is sufficient
Wrong mental model: “I put
JerseyNumberComparator.javainsidecscd211Comparators/. The compiler knows it is in that package.”
Why it breaks: The compiler does not infer the package from the directory path. Without package cscd211Comparators; on line 1, the class is in the default package. The import statement in the main class fails to resolve it.
How to correct: Line 1 of every comparator file must be package cscd211Comparators;. The directory and the package declaration must agree; neither substitutes for the other.
Source: JLS §7.4.
Quick check
Check your understanding
A student places BookComparator.java inside cscd211Comparators/ and writes the class body correctly, but the first line of the file is ‘import java.util.Comparator;’ with no package declaration above it. What is the outcome when the main class tries to compile ‘import cscd211Comparators.BookComparator;’?
Formal Definition and Interface Contract
From JLS §7.4 (Package Declarations):
A package declaration in a compilation unit specifies the package to which the compilation unit belongs. [...] If a compilation unit has no package declaration, it is considered to be part of an unnamed package.
From JLS §7.6 (Top Level Type Declarations):
A class or interface may be accessed from code in packages other than the package in which it is declared only if the class or interface is declared
public.
These two rules explain why the package declaration must be present and why the comparator class must be public when the main class is in a different package.
Mental Model
Think of the project layout as a building with labeled floors. The ground floor (cscd211Classes) holds the raw materials. A separate floor (cscd211Comparators) holds the tools for sorting those materials. Tools depend on materials; materials do not carry tools around. If you move a tool to the materials floor, neither changes functionally, but the directory listing no longer tells you which floor is which. The package declaration is the floor number posted on the door.
Connections
Within CSCD 210/211: Every CSCD 210 lab uses multiple packages. The Steiner layout in CSCD 211 adds cscd211Comparators as a new destination for a new kind of class. The mechanics (package declaration, import) are unchanged from CSCD 210.
Looking back: Implementing Comparator<T> as a Named Class established how to write the body of a comparator class. This lesson establishes where that class lives and how its file header is constructed.
Looking ahead: Instantiating a Comparator and Passing It to Arrays.sort covers how the main class imports the comparator, creates an instance, and passes it to Arrays.sort.
Go Deeper (optional)
None of what follows is needed to write correct comparator code. It is here for readers who want to see where the ideas connect to larger territory.
The Steiner layout is a teaching-scale version of what architects call the layered pattern: data-transfer objects in one layer, business logic (in this case, sorting strategies) in another, utilities in a third. In large production codebases the same principle appears, sometimes organized by layer (all service classes together, all data classes together) and sometimes by feature (all files for one product feature together). Either way, the underlying contract is identical to what you practiced here: the direction of imports encodes which layer depends on which, and data types do not carry sorting strategies around inside them.
A Comparator is also, from a design-pattern perspective, the Strategy pattern in its simplest form: you separate the algorithm (how to compare two things) from the objects being compared (the data). Each named comparator class is one interchangeable strategy. This is also the earliest example in the course of a function being treated as a value, something you will formalize when lambdas appear later.
For readers interested in the language specification: Bloch, Effective Java, Item 15 argues for minimizing accessibility, which is the same principle that gives package boundaries their meaning. The Java Platform Module System (JPMS, introduced in Java 9) takes this one step further by making inter-package dependencies explicit at the language level: a module must declare which of its packages it exports, and code in another module cannot see packages that are not exported. The cscd211Comparators package importing from cscd211Classes while cscd211Classes exports nothing back is precisely the structure JPMS was designed to enforce at scale.
In professional code you will encounter this pattern in standard library internals, in frameworks that use comparator injection (passing a sort strategy into a data structure), and in any system where the ordering of records must change without touching the records themselves.
Practice
Level 1
Write the complete file header (package declaration, import statements, class declaration) for a new BookByPagesComparator class that orders Book objects (in cscd211Classes) by page count. Do not write the method body.
Thought process
Follow the template: package declaration first, then imports (one for Comparator, one for Book), then the class declaration with implements Comparator<Book>.
Show answer
package cscd211Comparators;
import java.util.Comparator;
import cscd211Classes.Book;
public class BookByPagesComparator implements Comparator<Book>
{
@Override
public int compare(final Book a, final Book b)
{
// body goes here
}
}
Level 2
Given this directory listing:
cscd211Classes/ → Product.java
cscd211Enums/ → Category.java
cscd211Comparators/→ ProductByPriceComparator.java
cscd211Methods/ → Lab3Methods.java
A student’s ProductByPriceComparator.java begins with:
import java.util.Comparator;
import cscd211Classes.Product;
public class ProductByPriceComparator implements Comparator<Product>
Lab3Methods.java contains import cscd211Comparators.ProductByPriceComparator;. The build fails. Identify the problem and state the fix in one line.
Show answer
The comparator file is missing its package declaration. It is in the default package. The fix: add package cscd211Comparators; as the first line of ProductByPriceComparator.java.
Level 3
Explain in 3-4 sentences why the Steiner lab layout places TeamComparator in cscd211Comparators rather than in cscd211Classes. Include in your answer: (a) the direction of the dependency, (b) what happens to Player.java if all comparator files are deleted, and (c) which Bloch item supports this design.
Show answer
The dependency runs one way: TeamComparator imports cscd211Classes.Player, but Player imports nothing from cscd211Comparators. Placing both in the same package would hide that asymmetry. If all comparator files are deleted, Player.java still compiles and runs without modification; Player has no knowledge of and no dependency on the comparators. Keeping comparators in their own package encodes separation of concerns at the file-system level, making it immediately clear which code is the domain model and which code is a sortation strategy. Bloch, Effective Java, Item 15 (minimize accessibility) supports this design by encouraging narrow, explicit package boundaries.
Check Yourself
Close the notes and answer each one from memory, then reveal it. Pulling an idea back from memory is one of the strongest ways to make it stick.
Check your understanding
Which of the five standard CSCD 211 packages is the correct home for a class named TeamComparator?
A student places JerseyNumberComparator.java inside the cscd211Comparators/ directory but omits the package declaration. What does the Java compiler do with this class?
In the five-package Steiner layout, which direction does the dependency run between cscd211Comparators and cscd211Classes?
Trace the compile outcome. Lab3Methods.java (in cscd211Methods) contains: import cscd211Comparators.ProductByPriceComparator; ProductByPriceComparator.java is in the cscd211Comparators/ directory. Its first non-blank line is: import java.util.Comparator; (no package declaration above it). What does the compiler report when building Lab3Methods.java?
Which two import statements are required in the header of every file in cscd211Comparators that compares Player objects?