Java • Data Structures • CLI • File Input

Java Movie CLI

This was a Data Structures class project where I built a Java command-line movie database. The app loads movie records, stores them in memory, suggests random movies, searches by title, and lets the user add or remove movies from the running program.

The main point of the project was not just making a menu. It was choosing the right data structures for the job: an ArrayList for storing and randomly selecting movies, and a TreeMap for title lookup and prefix search.

Project context: this was built for a Data Structures course, so the important part is explaining why each structure was used, what the tradeoffs are, and how the program behaves with real input.
movies_data.tsv Load 12-column movie records from a tab-separated file.
ArrayList<Movie> Store movies for iteration, appending, and random indexed access.
TreeMap title index Map normalized titles to matching Movie objects.
CLI menu Suggest, search, add, remove, or quit.
This project connects Java objects, file parsing, random access, associative lookup, and menu-driven programs.

What I built

I built a single-file Java console application called Movies.java. It defines a movie record, loads data from a file when available, falls back to sample data when needed, and gives the user an interactive menu.

Java

Object model

Each movie is represented as a Movie object with fields like title, year, duration, rating, studio, summary, genres, directors, writers, and cast.

CLI

Interactive menu

The user can request a list of random movies, search by title, add a new movie, remove a movie, or quit from a simple terminal menu.

Data structures

ArrayList and TreeMap

The project uses an ArrayList for movie storage and a TreeMap for a searchable title index.

Program features

The app is small, but it has a complete working loop: load data, show a menu, process user input, update the movie list, and rebuild the title index when the data changes.

01

Suggest random movies

The user chooses how many movies to display, and the app prints that many distinct random movies.

02

Search by title

The app normalizes titles, checks for exact matches first, then prints prefix matches.

03

Add movies

The user can add a new movie through prompts, and the movie is appended to the list.

04

Remove movies

The user can remove the first movie with an exact matching title.

Data structures used

This was the core data structures part of the project. Each structure has a clear reason.

Structure Used for Why it fits
ArrayList<Movie> Main movie storage. Good for appending records, iterating through movies, and selecting random movies by index in constant time.
boolean[] used Tracking already-selected random movie indexes. Prevents duplicates during a random suggestion run without modifying or shuffling the original movie list.
TreeMap<String, List<Movie>> Title search index. Stores normalized title keys in sorted order and maps each title key to one or more matching movie objects.
List<Movie> Map value for duplicate title keys. Allows more than one movie to share the same normalized title key.

Why ArrayList works for random suggestions

Random movie suggestions need fast indexed access. That makes ArrayList a good choice because the program can generate a random index and immediately retrieve the movie at that position.

Good fit

ArrayList

ArrayList gives efficient indexed access, which is exactly what random selection needs. The program generates a random index and uses it to pull a movie from the list.

Poorer fit

LinkedList

A LinkedList would be weaker here because indexed access requires walking through the list. This project does not need frequent middle insertions or removals.

static void showRandom(ArrayList<Movie> list, int k) {
    if (list.isEmpty()) {
        System.out.println("(No Results)");
        return;
    }

    int size = list.size();
    int n = Math.min(k, size);
    boolean[] used = new boolean[size];
    int printed = 0;

    while (printed < n) {
        int idx = (int) (Math.random() * size);

        if (used[idx]) continue;

        used[idx] = true;
        System.out.println("#" + (printed + 1) + ". " + list.get(idx));
        printed++;
    }
}

How title normalization works

Search works better when titles are normalized. The program lowercases titles and removes leading articles like the, a, and an.

static String normTitle(String s) {
    if (s == null) return "";

    s = s.trim().toLowerCase();

    if (s.startsWith("the ")) return s.substring(4).trim();
    if (s.startsWith("an "))  return s.substring(3).trim();
    if (s.startsWith("a "))   return s.substring(2).trim();

    return s;
}
Example: The Matrix becomes matrix, so a user can search for matrix without needing to type the leading article.

How the TreeMap title index works

The title index maps a normalized title string to a list of matching movie objects. This is better than only storing titles because the program can retrieve and print the full movie record.

static Map<String, List<Movie>> buildTitleIndex(List<Movie> movies) {
    Map<String, List<Movie>> index = new TreeMap<>();

    for (Movie m : movies) {
        String key = normTitle(m.title);
        List<Movie> bucket = index.computeIfAbsent(key, k -> new ArrayList<>());
        bucket.add(m);
    }

    return index;
}
Why TreeMap: a HashMap would be faster for direct lookup on average, but it does not keep keys sorted. TreeMap keeps keys ordered, which makes it a better fit for prefix-style title search.

Exact search first, prefix search second

When the user searches, the program first checks for an exact normalized title match. After that, it scans the sorted keys for titles that start with the search text.

// Exact match first
List<Movie> exact = titleIndex.get(searchTitle);

if (exact != null) {
    for (Movie m : exact) {
        System.out.println(m);
    }
}

// Prefix matches second
for (Map.Entry<String, List<Movie>> entry : titleIndex.entrySet()) {
    String key = entry.getKey();

    if (!key.startsWith(searchTitle) || key.equals(searchTitle)) continue;

    for (Movie m : entry.getValue()) {
        System.out.println(m);
    }
}
Important distinction: this version performs exact and prefix matching. It is not the same as a general substring search with contains().

Input file format

The program tries to load a file named movies_data.tsv. It expects a header row and exactly 12 tab-separated fields per movie.

Column Field Example
1 id S001
2 title The Matrix
3 year 1999
4 durationMinutes 136
5 criticRating 8.7
6 mpaaRating R
7-12 Studio, summary, genres, directors, writers, cast Longer text fields from the movie dataset.
String[] c = line.split("\t", -1);

if (c.length != EXPECTED_COLS) continue;

movies.add(new Movie(
    c[0], c[1], c[2], c[3], c[4], c[5],
    c[6], c[7], c[8], c[9], c[10], c[11]
));

Fallback sample data

If the TSV file is missing or no valid rows are loaded, the program falls back to a built-in sample dataset of 25 movies. That makes the project easier to demo because it still works without an external file.

ArrayList<Movie> movies = loadFile();

if (movies.isEmpty()) {
    movies = seedSample();
    System.out.println("File Not Found: Reverting to sample dataset");
} else {
    System.out.println("Loaded " + movies.size() + " movies from: movies_data.tsv");
}
Why this is useful: the app can run in a classroom, Codespace, or local terminal even if the data file is not present.

Add and remove operations

Adding and removing movies changes the main ArrayList. After either operation, the program rebuilds the TreeMap title index so search results stay current.

01

User selects add or remove

The menu sends the program to the correct method.

02

ArrayList changes

A movie is appended, or the first exact title match is removed.

03

TreeMap rebuilds

The title index is recreated from the updated movie list.

04

Search stays accurate

Future title searches reflect the current list.

case "3": {
    addMovie(in, movies);
    titleIndex = buildTitleIndex(movies);
    returnToMenu(in);
    break;
}

case "4": {
    removeMovieByTitle(in, movies);
    titleIndex = buildTitleIndex(movies);
    returnToMenu(in);
    break;
}

Complexity notes

The project is small, but it still shows how data-structure choices affect performance.

Operation Approximate complexity Reason
Append movie Amortized O(1) ArrayList append is usually constant time.
Random indexed access O(1) The app can directly access list.get(index).
Suggest K random movies Expected about O(K) The app picks random indexes and uses a boolean array to avoid duplicates.
Exact title lookup O(log n) TreeMap lookup is logarithmic.
Prefix search O(n) This version scans the sorted map keys and checks startsWith().
Remove by exact title O(n) The program scans the list until it finds the first matching title.

What I learned

This project helped connect class data-structure concepts to a working program.

Data structures

Use the structure that matches the task

ArrayList is a good fit for indexed random access. TreeMap is a better fit when sorted keys and prefix search matter.

File input

Input format matters

The TSV loader has to preserve empty columns and skip malformed rows so the program does not build broken movie objects.

Program design

Indexes must stay synced

If the movie list changes, the search index has to be rebuilt or updated. Otherwise, search results can become stale.

Future improvements

The current version works for the assignment, but there are clear ways to make it more robust.

Code improvements

Make it safer

  • Add try/catch input validation for numbers.
  • Print a clearer error when the TSV file cannot load.
  • Prevent duplicate generated IDs after removals.
  • Move the Movie class into its own file for larger versions.
Feature upgrades

Make it more useful

  • Add search by director, actor, genre, or rating.
  • Save added movies back to a file.
  • Support contains-anywhere title search as a separate option.
  • Sort results by year, title, or rating.

Run it locally

The project can be compiled and run directly with the Java compiler and runtime.

javac Movies.java
java Movies
Optional: place movies_data.tsv in the same folder before running. If the file is missing, the program falls back to sample data.

Final idea

This project is a good example of a class assignment becoming a real portfolio piece. It shows Java basics, object modeling, file parsing, menu-driven programs, random access with ArrayList, associative lookup with TreeMap, and the reasoning behind choosing one data structure over another.