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 anArrayList - 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 1String getTitle()void incrementTimesDownloaded()
MusicDownloadsholds: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, ornullupdateDownloads(List<String> titles)— usinggetDownloadInfo, update or add an entry for every title in the parameter list
Part (a): Writing getDownloadInfo(String title)
The Rule, Broken Down
- Search every entry in
downloadListfor one whose title matches the parameter. - If a match is found, return a reference to that actual object.
- If the search reaches the end of the list with no match, return
null. - The search itself must not change
downloadListin any way.
Step-by-Step Approach
- Loop through
downloadListby index. - Pull out each
DownloadInfoobject and compare its title to the parameter with.equals(). - The moment a match is found, return that object immediately.
- If the loop finishes without ever returning, return
nullafterward.
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 areStrings, and two differentStringobjects can hold identical characters without being the same object in memory.- Returning
infoitself — 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, likeincrementTimesDownloaded(), that affect the real object stored indownloadList. - The
return nullafter the loop only ever runs if noreturninside the loop already fired, which is exactly "if no song indownloadListhas 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 → returnsnull, matching the question exactly.
Common Mistakes to Avoid
- Comparing titles with
==instead of.equals(). - Returning the index or the title
Stringinstead of theDownloadInfoobject itself. - Accidentally modifying
downloadListwhile 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
returnexits immediately regardless.
Part (b): Writing updateDownloads(List<String> titles)
The Rule, Broken Down
- For every title in
titles, check whether an entry with that title already exists indownloadList. - If it exists, increment its download count.
- If it doesn't exist yet, create a brand-new
DownloadInfofor that title and append it to the end ofdownloadList. - The order of already-existing entries must never change; new entries must appear in the order they first show up in
titles. - The method must actually call
getDownloadInforather than re-implementing its search logic.
Step-by-Step Approach
- Loop through every title in
titles, by index. - Call
getDownloadInfo(title)to check whether that title is already being tracked. - If the result isn't
null, callincrementTimesDownloaded()on it. - If the result is
null, construct a newDownloadInfo(title)andadd()it to the end ofdownloadList. - Repeat until every title in
titleshas 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 thegetDownloadInfomethod." 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 fromtitlesis 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 indownloadListby 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
downloadListmanually instead of callinggetDownloadInfo— 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
downloadListis updated in place as the loop runs. - Creating a duplicate
DownloadInfofor a title that already exists instead of incrementing the existing one, which would violate "there are no duplicate titles indownloadList."
Key Takeaways
- Reusing a "find" method instead of duplicating its search logic elsewhere is exactly what lets
updateDownloadsstay short — its whole job becomes "search, then branch on what you found." - Returning
nullversus a live object reference is a meaningful design decision on its own — always check fornullbefore 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
ArrayListpattern worth recognizing on sight.