CompSci.rocks
FRQcsapa

MusicDownloads: 2013 FRQ 1

A step-by-step solution to the 2013 AP CSA FRQ 1 (MusicDownloads), covering searching a list for a matching title and conditionally updating or growing it in Java.

Keeping a running list of downloaded songs and updating it as new download activity comes in is the job behind this AP Computer Science A free-response question — first you search the list for a matching title, then you use that search to either update an existing entry or grow the list with a brand-new one.

What This FRQ Tests

  • AP CSA units: Unit 6 (Array) and Unit 7 (ArrayList) — the work here is searching and growing a List<DownloadInfo> backed by an ArrayList
  • Core skill: looping through a list to find an object whose field matches a target value, and returning a reference to it (or null)
  • Secondary skill: conditionally updating an existing list entry versus appending a brand-new one, while keeping already-established order untouched
  • Official category: on today's exam, this kind of list-search-and-update task would fall under "Array/ArrayList" — always FRQ 3 in the fixed order used since 2019. 2013 predates that standardization, though, and the exam's own booklet prints this question first, as FRQ 1.

The Setup

  • DownloadInfo (given, not modified):
    • DownloadInfo(String title) — creates a new entry and sets its download count to 1
    • String getTitle()
    • void incrementTimesDownloaded()
  • MusicDownloads holds:
    • private List<DownloadInfo> downloadList — guaranteed non-null, and guaranteed to never contain duplicate titles
  • You're asked to write two methods:
    • getDownloadInfo(String title) — find and return the matching object, or null
    • updateDownloads(List<String> titles) — using getDownloadInfo, update or add an entry for every title in the parameter list

Part (a): Writing getDownloadInfo(String title)

The Rule, Broken Down

  1. Search every entry in downloadList for one whose title matches the parameter.
  2. If a match is found, return a reference to that actual object.
  3. If the search reaches the end of the list with no match, return null.
  4. The search itself must not change downloadList in any way.

Step-by-Step Approach

  1. Loop through downloadList by index.
  2. Pull out each DownloadInfo object and compare its title to the parameter with .equals().
  3. The moment a match is found, return that object immediately.
  4. If the loop finishes without ever returning, return null afterward.

The Code

public DownloadInfo getDownloadInfo(String title)
{
    for (int i = 0; i < downloadList.size(); i++)
    {
        DownloadInfo info = downloadList.get(i);

        if (info.getTitle().equals(title))
        {
            return info;
        }
    }

    return null;
}

Why Each Piece Matters

  • Returning as soon as a match is found short-circuits the search — there's no reason to keep scanning once the answer is already known.
  • .equals(), not ==, since titles are Strings, and two different String objects can hold identical characters without being the same object in memory.
  • Returning info itself — not a copy, not just its title — is what "returns a reference" means: the caller gets the actual list entry and can call mutating methods on it, like incrementTimesDownloaded(), that affect the real object stored in downloadList.
  • The return null after the loop only ever runs if no return inside the loop already fired, which is exactly "if no song in downloadList has a title that matches."

Tracing the Example

Using the question's own downloadList — position 0: "Hey Jude"/5, position 1: "Soul Sister"/3, position 2: "Aqualung"/10:

  • webMusicA.getDownloadInfo("Aqualung") — compares "Hey Jude" (no), "Soul Sister" (no), "Aqualung" (yes) → returns the object at index 2, matching the question exactly.
  • webMusicA.getDownloadInfo("Happy Birthday") — compares all three titles with no match → the loop ends → returns null, matching the question exactly.

Common Mistakes to Avoid

  • Comparing titles with == instead of .equals().
  • Returning the index or the title String instead of the DownloadInfo object itself.
  • Accidentally modifying downloadList while searching (e.g., removing or reordering entries), which would violate the "no changes were made" postcondition.
  • Continuing to loop after already finding and returning a match — unnecessary, though not actually incorrect, since return exits immediately regardless.

Part (b): Writing updateDownloads(List<String> titles)

The Rule, Broken Down

  1. For every title in titles, check whether an entry with that title already exists in downloadList.
  2. If it exists, increment its download count.
  3. If it doesn't exist yet, create a brand-new DownloadInfo for that title and append it to the end of downloadList.
  4. The order of already-existing entries must never change; new entries must appear in the order they first show up in titles.
  5. The method must actually call getDownloadInfo rather than re-implementing its search logic.

Step-by-Step Approach

  1. Loop through every title in titles, by index.
  2. Call getDownloadInfo(title) to check whether that title is already being tracked.
  3. If the result isn't null, call incrementTimesDownloaded() on it.
  4. If the result is null, construct a new DownloadInfo(title) and add() it to the end of downloadList.
  5. Repeat until every title in titles has been handled.

The Code

public void updateDownloads(List<String> titles)
{
    for (int i = 0; i < titles.size(); i++)
    {
        String title = titles.get(i);
        DownloadInfo info = getDownloadInfo(title);

        if (info != null)
        {
            info.incrementTimesDownloaded();
        }
        else
        {
            downloadList.add(new DownloadInfo(title));
        }
    }
}

Why Each Piece Matters

  • Calling getDownloadInfo(title) instead of writing a second search loop reuses part (a)'s work exactly as the question requires — the question is explicit that a solution "must use the getDownloadInfo method."
  • new DownloadInfo(title) automatically sets its download count to 1, per its own constructor's documentation — no extra work is needed for a title seen for the first time.
  • downloadList.add(...) with no index argument appends to the end of the list, which is exactly what "the first time an object with a title from titles is added ... it is added to the end of the list" requires.
  • Since a title can appear more than once in titles, a title added partway through the loop needs to be found again on a later iteration — that happens automatically here, because it's already sitting in downloadList by the time the loop reaches its next occurrence.

Tracing the Example

Starting downloadList = ["Hey Jude"/5, "Soul Sister"/3, "Aqualung"/10], and titles = {"Lights", "Aqualung", "Soul Sister", "Go Now", "Lights", "Soul Sister"}:

Title processed getDownloadInfo result Action downloadList after
"Lights" null add new "Lights"/1 Hey Jude/5, Soul Sister/3, Aqualung/10, Lights/1
"Aqualung" found increment → 11 Hey Jude/5, Soul Sister/3, Aqualung/11, Lights/1
"Soul Sister" found increment → 4 Hey Jude/5, Soul Sister/4, Aqualung/11, Lights/1
"Go Now" null add new "Go Now"/1 Hey Jude/5, Soul Sister/4, Aqualung/11, Lights/1, Go Now/1
"Lights" found (added earlier this call) increment → 2 Hey Jude/5, Soul Sister/4, Aqualung/11, Lights/2, Go Now/1
"Soul Sister" found increment → 5 Hey Jude/5, Soul Sister/5, Aqualung/11, Lights/2, Go Now/1

Final list: "Hey Jude"/5, "Soul Sister"/5, "Aqualung"/11, "Lights"/2, "Go Now"/1 — matching the question's expected result exactly, including the two brand-new entries and their correct download counts.

Common Mistakes to Avoid

  • Re-searching downloadList manually instead of calling getDownloadInfo — the question explicitly requires using it.
  • Inserting new entries somewhere other than the end (for example, at the front), which breaks the "new entries appear in the same order in which they first appear in titles" requirement.
  • Forgetting that a title added earlier in the same call can — and must — be found again later in the same loop; no special-casing is needed, since downloadList is updated in place as the loop runs.
  • Creating a duplicate DownloadInfo for a title that already exists instead of incrementing the existing one, which would violate "there are no duplicate titles in downloadList."

Key Takeaways

  • Reusing a "find" method instead of duplicating its search logic elsewhere is exactly what lets updateDownloads stay short — its whole job becomes "search, then branch on what you found."
  • Returning null versus a live object reference is a meaningful design decision on its own — always check for null before calling a method on a searched-for result.
  • Conditionally updating-in-place or appending to the end of a list, based on whether a search found something, is a very common ArrayList pattern worth recognizing on sight.

Related FRQs