Audience: adult learners who need to review, read, and approve Java code (including code generated by AI agents) — not necessarily write it from scratch.
Format: each exercise gives a spec (what the code is supposed to do), an example, and a code snippet. Answer the question, then click Answer to check yourself and read the explanation.
Assumptions (unless an exercise says otherwise):
- Arguments are non-null.
- The code compiles and is being reviewed for behavioral correctness.
- "Java 11+" or "Java 15+" is noted next to exercises that use newer String APIs.
There are 50 exercises across 8 topics. Most snippets are correct; some contain common String-handling mistakes for you to catch.
Spec: Return true if the two greetings have the same text content ("hello").
public static boolean sameGreeting(String input) {
String a = "hello";
String b = new StringBuilder("hel").append("lo").toString();
return a == b;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
==compares object references, andbwas built withStringBuilder, so it's a different object even though the text matches. It should use.equals(). - C. No —
StringBuilder.appendmutates the original string, sobno longer equals"hello". - D. No — string literals in Java are case-sensitive, so
"hello"and"hel" + "lo"are different values.
Answer
Answer: B — == on Strings checks object identity, not content. new StringBuilder(...).toString() always creates a brand-new String object, so a == b is false even though both hold "hello". Use a.equals(b).
Spec: Return true if two strings have the same content.
public static boolean sameGreeting(String a, String b) {
return a.equals(b);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
equals()only checks whether the two references point to the same object, not the content. - C. No —
equals()throws an exception whenever the two strings have different lengths. - D. No —
equals()is case-insensitive by default, so"Hi"and"hi"would incorrectly be treated as equal.
Answer
Answer: A — String.equals() compares character content, which is exactly what's needed here. (B describes ==, not equals(); C and D are fabricated behaviors.)
Spec: Return true, since both variables are assigned the same string literal.
String a = "cat";
String b = "cat";
boolean same = (a == b);Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — since
aandbare different variables,==always compares references and returnsfalse. - C. No — comparing Strings with
==requires calling.intern()explicitly first, or the code won't compile. - D. No — Java only pools single-character string literals in the string constant pool, not longer ones like
"cat".
Answer
Answer: A — Identical string literals are interned by the compiler into the same object in the string constant pool, so a and b refer to the same object and == correctly returns true. This only holds for compile-time literals/constants, not for strings built at runtime (see Exercise 1).
Spec: Return true if two strings are equal, using compareTo.
public static boolean areEqual(String a, String b) {
return a.compareTo(b) == 1;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
compareTo()ignores case, so it can't reliably detect equal strings. - C. No —
compareTo()returns0when the strings are equal, not1; this should check== 0. - D. No —
compareTo()only compares the first character of each string.
Answer
Answer: C — compareTo() returns 0 for equal strings, a negative number if a comes before b, and a positive number if a comes after b. Checking == 1 will almost always be false, even for equal strings.
Spec: Return true if two strings are equal, ignoring case.
public static boolean sameWord(String a, String b) {
return a.equalsIgnoreCase(b);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
equalsIgnoreCase()requires both strings to be the same length or it throws an exception. - C. No —
equalsIgnoreCase()only ignores case for the first letter of each string. - D. No —
equalsIgnoreCase()compares references, like==, so it returnsfalseunlessaandbare the same object.
Answer
Answer: A — equalsIgnoreCase() is exactly the right tool for a case-insensitive content comparison.
Spec: Return true if both strings hold the same content, or are both null; must not throw NullPointerException.
public static boolean sameOrBothNull(String a, String b) {
return java.util.Objects.equals(a, b);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
Objects.equals()still throws aNullPointerExceptionif either argument isnull, just like calling.equals()directly. - C. No —
Objects.equals()only works when comparing twonullvalues; it can't compare two non-null strings. - D. No —
Objects.equals()performs reference comparison (like==) rather than checking string content.
Answer
Answer: A — Objects.equals(a, b) is null-safe: it returns true if both are null, false if only one is null, and otherwise delegates to a.equals(b).
Spec: Append " world" to name and return the updated string.
public static String greet(String name) {
name.concat(" world");
return name;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
concat()only works withStringBuilderobjects, notString, so this fails to compile. - C. No —
concat()mutates the string in place, but only the first call in a method is remembered. - D. No — Strings are immutable in Java;
concat()returns a new String rather than modifyingnamein place, so the returned value is unchanged. It should bename = name.concat(" world");.
Answer
Answer: D — Every String method that looks like it "modifies" the string (concat, trim, toUpperCase, replace, substring, ...) actually returns a new String and leaves the original untouched. The result has to be captured, usually by reassigning it.
Spec: Append " world" to name and return the updated string.
public static String greet(String name) {
name = name.concat(" world");
return name;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — reassigning
nameinside the method also changes the variable in the caller, causing unexpected side effects. - C. No —
concat()throws an exception when passed a string literal. - D. No — since Strings are immutable, this code will not compile.
Answer
Answer: A — Reassigning the local variable name to the new concatenated string, then returning it, is the correct fix for the immutability issue in Exercise 7.
Spec: Return the uppercase version of a string, leaving the original string unchanged.
public static String shout(String s) {
return s.toUpperCase();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
toUpperCase()modifiessin place, so the caller's original string is unexpectedly changed too. - C. No —
toUpperCase()without aLocaleargument throws an exception starting in Java 11. - D. No — this returns
voidsince Strings are immutable, so the method fails to compile.
Answer
Answer: A — toUpperCase() returns a new uppercase String and never modifies the original, which is exactly what the spec asks for.
Spec: Remove all spaces from a string.
public static String removeSpaces(String s) {
return s.replace(" ", "");
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
replace()only removes the first occurrence of the target substring, so multiple spaces will remain. - C. No —
replace()treats its first argument as a regular expression, so a literal space won't be matched correctly. - D. No —
replace()returnsvoid, so this method actually returnsnull.
Answer
Answer: A — String.replace(CharSequence, CharSequence) replaces all literal occurrences (unlike replaceAll, which uses regex — see Exercise 50). This correctly strips every space.
Spec: Remove the first character of the string "in place" so the caller sees the change.
public static void removeFirstChar(String s) {
s = s.substring(1);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — Java passes the reference by value; reassigning the local parameter
shas no effect on the caller's variable, and since the method returns nothing, the change is lost entirely. - C. No —
substring(1)actually removes the last character, not the first. - D. No —
substring()throws an exception whenever the string is longer than one character.
Answer
Answer: B — There's no way to modify a String "in place" from inside a method in Java — Strings are immutable, and reassigning a parameter only changes the local copy of the reference. The method must return the new string, and the caller must capture it.
Spec: Return true, since combined and literal represent the exact same compile-time constant text.
public static boolean check() {
final String part = "wor";
String combined = "Hello " + part + "ld";
String literal = "Hello world";
return combined == literal;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — string concatenation with
+always creates a new object at runtime, so==must returnfalsehere. - C. No —
finallocal variables are stored on the stack, so they can never be part of the string constant pool. - D. No — comparing a concatenated result to a literal with
==always throws an exception unlessnew String(...)was used.
Answer
Answer: A — Because part is a final variable initialized with a compile-time constant, the expression "Hello " + part + "ld" is itself a compile-time constant. The compiler folds it into "Hello world" and interns it in the same pool as the literal, so == returns true. (Without final, or with a non-constant value, this would not hold — that's the case in Exercise 1.)
Spec: Return the last 3 characters of a string (length ≥ 3). Example: "hello" → "llo".
public static String lastThree(String s) {
return s.substring(s.length() - 3, s.length() - 1);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
substring()cannot be called with two arguments in modern Java; only a single starting index is supported. - C. No —
substring()'s end index is exclusive, so usings.length() - 1excludes the final character. It should bes.length(). - D. No — the start index is inclusive of one extra character, so it should be
s.length() - 2.
Answer
Answer: C — substring(begin, end) includes begin but excludes end. s.substring(s.length() - 3, s.length() - 1) only grabs 2 characters (e.g., "ll" from "hello"), not 3. The fix is s.substring(s.length() - 3, s.length()), or equivalently s.substring(s.length() - 3).
Spec: Return the last 3 characters of a string (length ≥ 3).
public static String lastThree(String s) {
return s.substring(s.length() - 3);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
substring()with a single argument returns everything up to that index, not from it, so this returns the firstlength - 3characters instead of the last 3. - C. No — this throws an exception whenever the string's length is exactly 3.
- D. No —
substring()always allocates a full copy of the original string internally, causing a memory leak.
Answer
Answer: A — substring(begin) (single-argument form) returns everything from begin to the end of the string, which correctly gives the last 3 characters here.
Spec: Print every character in the string, one per line.
public static void printChars(String s) {
for (int i = 0; i <= s.length(); i++) {
System.out.println(s.charAt(i));
}
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
charAt()is zero-indexed from the end of the string, not the beginning, so characters print in reverse order. - C. No —
charAt()returns anintcharacter code instead of achar, so this fails to compile. - D. No — the loop condition
i <= s.length()allowsito equals.length(), which is out of bounds forcharAt()and throws aStringIndexOutOfBoundsException.
Answer
Answer: D — Valid indices for a string of length n are 0 through n - 1. The condition should be i < s.length().
Spec: Print every character in the string, one per line.
public static void printChars(String s) {
for (int i = 0; i < s.length(); i++) {
System.out.println(s.charAt(i));
}
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — this skips the last character because
i < s.length()should bei <= s.length(). - C. No —
charAt()is deprecated and won't compile in modern Java. - D. No — the loop never terminates for empty strings because
s.length()returns-1for an empty string.
Answer
Answer: A — i < s.length() correctly visits indices 0 through length() - 1, printing every character exactly once. (length() returns 0 for an empty string, not -1, so the loop simply doesn't run.)
Spec: Return true if the string contains the character 'z'. Example: hasZ("zoo") → true.
public static boolean hasZ(String s) {
return s.indexOf('z') >= 0;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
indexOf(char)only checks the first character of the string, not the whole string. - C. No — the comparison should be
> 0, since a real match never legitimately returns0. - D. No —
indexOf(char)requires the argument to be aStringlike"z", not acharliteral like'z', so this fails to compile.
Answer
Answer: A — indexOf() returns -1 when there's no match and a valid index (0 or greater) otherwise. Checking >= 0 correctly catches a match at any position, including a leading 'z' at index 0 — which is exactly why >= 0 is needed instead of > 0 (compare to Exercise 21, which makes this mistake).
Spec: Return the extension of a filename (the text after the last .), or an empty string if there's no .. Example: "report.final.pdf" → "pdf".
public static String extension(String filename) {
int dot = filename.lastIndexOf('.');
if (dot == -1) {
return "";
}
return filename.substring(dot + 1);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
lastIndexOf('.')finds the first dot, not the last, so"report.final.pdf"would incorrectly return"final.pdf". - C. No —
substring(dot + 1)throws an exception when the filename ends in a dot. - D. No — this returns
nullinstead of an empty string when there is no dot in the filename.
Answer
Answer: A — lastIndexOf() correctly finds the last occurrence, and the -1 check correctly handles filenames with no extension.
Spec: Return true if text contains word, ignoring case. Example: containsWord("Hello World", "world") → true.
public static boolean containsWord(String text, String word) {
return text.contains(word);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
contains()is case-sensitive, so"Hello World".contains("world")returnsfalse. Both strings should be lower-cased first. - C. No —
contains()can only check for single characters, not multi-character substrings. - D. No —
contains()requires its argument to be a valid regular expression, and"world"isn't valid regex.
Answer
Answer: B — String.contains() does an exact, case-sensitive substring search. To match the "ignoring case" requirement, both text and word need to be normalized first, e.g. text.toLowerCase().contains(word.toLowerCase()).
Spec: Return true if text contains word, ignoring case.
public static boolean containsWord(String text, String word) {
return text.toLowerCase().contains(word.toLowerCase());
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
toLowerCase()requires aLocaleargument in modern Java, so this won't compile. - C. No — the two
toLowerCase()calls must use the exact sameLocale, orcontains()will still fail to match. - D. No —
contains()returns the index of the match rather than aboolean, so this doesn't compile.
Answer
Answer: A — Lower-casing both sides before comparing is the standard, correct way to do a case-insensitive contains() check.
Spec: Return true if the URL uses HTTPS. Example: isSecure("https://example.com") → true.
public static boolean isSecure(String url) {
return url.equals("https://");
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
equals()only returnstruewhenurlis exactly"https://"with nothing after it. Real URLs like"https://example.com"incorrectly returnfalse. This should usestartsWith("https://"). - C. No —
String.equals()ignores everything after the first:character, so this only checks the protocol name. - D. No — this throws a
NullPointerExceptionwhenever the URL doesn't start with"http".
Answer
Answer: B — The spec asks whether the URL starts with "https://", not whether it is "https://". equals() demands an exact full match, which almost no real URL will satisfy.
Spec: Return true if the URL uses HTTPS.
public static boolean isSecure(String url) {
return url.startsWith("https://");
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
startsWith()is case-insensitive, so it would also incorrectly match"HTTPS://"as a different protocol. - C. No —
startsWith()checks only the first character, not the whole prefix, so"hxxps://"would also match. - D. No —
startsWith()returns anintindex instead of aboolean, so this fails to compile.
Answer
Answer: A — startsWith("https://") correctly checks the beginning of the string for that literal prefix. (startsWith() is actually case-sensitive, which is desirable here.)
Spec: Return true if a comes before b alphabetically.
public static boolean comesBefore(String a, String b) {
return a.compareTo(b) < 0;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
compareTo()already returns aboolean, so wrapping it in< 0fails to compile. - C. No —
compareTo()compares string lengths, not alphabetical order, so"ant"would only come before"ox"because it's shorter. - D. No —
compareTo()is case-insensitive, so"Zebra"and"apple"would be compared only by length.
Answer
Answer: A — compareTo() performs a lexicographic (dictionary-order) comparison and returns a negative number when the calling string comes first. < 0 is the correct check for "comes before".
Spec: Return true if text ends with the word "end".
public static boolean endsWithWord(String text) {
return text.endsWith("end");
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
endsWith()also matches the substring anywhere inside the string, not just at the end, so"the end is near"would incorrectly returntrue. - C. No —
endsWith()is case-insensitive, so"the END"would also match"end". - D. No —
endsWith()returns the matching index as anint, not aboolean, so this fails to compile.
Answer
Answer: A — endsWith() specifically checks the suffix of the string, unlike lastIndexOf()/indexOf(), which just find a match anywhere. "the end is near".endsWith("end") correctly returns false (it ends in "near"), while "weekend".endsWith("end") correctly returns true.
Spec: Return true if the string is empty or contains only whitespace.
public static boolean isBlank(String s) {
return s.isEmpty();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
isEmpty()throws an exception when called on a string containing only whitespace. - C. No —
isEmpty()only returnstruefor a zero-length string; a string like" "is not empty, so this misses whitespace-only input. It should uses.trim().isEmpty()(ors.isBlank()in Java 11+). - D. No —
isEmpty()ands.length() == 0give different results for the same string, so this method is unreliable.
Answer
Answer: C — isEmpty() checks length, not whitespace content. A string of pure spaces has length > 0, so isEmpty() wrongly returns false for it.
Spec: Return true if the string is empty or contains only whitespace.
public static boolean isBlank(String s) {
return s.trim().isEmpty();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
trim()only removes leading whitespace, not trailing, so" hi "would still be considered blank. - C. No —
trim()creates a new String, soisEmpty()checks the wrong object and always returnsfalse. - D. No — this incorrectly reports strings like
"cat"as blank, becausetrim()also strips ordinary letters that resemble whitespace.
Answer
Answer: A — trim() removes whitespace from both ends; if nothing but whitespace remains, .isEmpty() correctly returns true.
Spec: Remove leading and trailing whitespace, including Unicode whitespace characters like the non-breaking space ( ).
public static String clean(String s) {
return s.trim();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
trim()removes whitespace from the middle of the string too, changing content it shouldn't touch. - C. No —
trim()was removed starting in Java 9, so this code will not compile. - D. No —
trim()only removes characters with code point ≤U+0020. It does not remove other Unicode whitespace like. Usestrip()(Java 11+), which follows proper Unicode whitespace rules.
Answer
Answer: D — trim() predates Unicode-aware whitespace handling and only strips ASCII control/space characters at the ends. strip()/stripLeading()/stripTrailing() (Java 11+) use Character.isWhitespace(), which correctly recognizes non-breaking spaces and other Unicode whitespace.
Spec: Remove leading and trailing whitespace, including Unicode whitespace characters. (Java 11+)
public static String clean(String s) {
return s.strip();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
strip()requires aLocaleargument to know which whitespace characters to remove. - C. No —
strip()only removes leading whitespace; trailing whitespace needs a separate call tostripTrailing(). - D. No —
strip()is only available onStringBuilder, notString, so this fails to compile.
Answer
Answer: A — strip() removes Unicode-aware whitespace from both ends in a single call, correctly satisfying the spec.
Spec: Capitalize the first letter of each word and lowercase the rest. Words are separated by single spaces. Example: "hello WORLD" → "Hello World".
public static String titleCase(String s) {
String[] words = s.split(" ");
StringBuilder result = new StringBuilder();
for (String w : words) {
result.append(Character.toUpperCase(w.charAt(0)));
result.append(w.substring(1));
result.append(" ");
}
return result.toString().trim();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
split(" ")throws an exception whenever there are two consecutive spaces in the string. - C. No — the code capitalizes the first letter but appends
w.substring(1)unchanged, so it never lowercases the rest of the word;"WORLD"becomes"WORLD"instead of"World". - D. No —
Character.toUpperCase()cannot be applied to a singlechar, only to full Strings.
Answer
Answer: C — Only the first character is forced to uppercase; the remainder of each word is appended verbatim, so any letters that were already uppercase (like the rest of "WORLD") stay uppercase instead of being lowercased.
Spec: Capitalize the first letter of each word and lowercase the rest.
public static String titleCase(String s) {
String[] words = s.split(" ");
StringBuilder result = new StringBuilder();
for (String w : words) {
result.append(Character.toUpperCase(w.charAt(0)));
result.append(w.substring(1).toLowerCase());
result.append(" ");
}
return result.toString().trim();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — calling
.trim()at the end also removes the spaces between words, collapsing"Hello World"into"HelloWorld". - C. No —
w.substring(1).toLowerCase()throws an exception whenever a word is longer than 10 characters. - D. No —
Character.toUpperCase()returns anint, not achar, soresult.append(...)appends a number instead of a letter.
Answer
Answer: A — Each word's first letter is uppercased and the rest is lowercased before appending; the final .trim() only removes the single trailing space added after the last word, not the internal separators (those are literal single characters appended by the loop, not whitespace runs trim() would collapse).
Spec: Split a version string like "1.2.3" into its three numeric parts.
public static String[] parts(String version) {
return version.split(".");
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
split()can only split on a single literal character, and"."isn't a valid character to split on. - C. No —
split()removes the delimiter but keeps only the first two resulting pieces, discarding the rest. - D. No —
split()treats its argument as a regular expression, and an unescaped.matches any character. This splits between every character instead of at the literal dots; it should besplit("\\.").
Answer
Answer: D — String.split() takes a regex, and . in regex means "any character". "1.2.3".split(".") splits the string apart almost everywhere, not just at the actual dots.
Spec: Split a version string like "1.2.3" into its three numeric parts.
public static String[] parts(String version) {
return version.split("\\.");
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
\\.in a Java string literal represents two literal backslashes followed by a dot, so this still won't split correctly. - C. No —
split()with a regex argument always returns aList<String>, not aString[], so this fails to compile. - D. No — this only works for version strings with exactly 3 parts; anything with 2 or 4 parts throws an exception.
Answer
Answer: A — "\\." in Java source is the two-character regex \., which matches a literal dot. This correctly splits "1.2.3" into ["1", "2", "3"].
Spec: Split a comma-separated string and return the number of fields, including trailing empty fields. Example: countFields("a,b,,") → 4.
public static int countFields(String csv) {
return csv.split(",").length;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
split()throws an exception if the string ends with the delimiter character. - C. No —
split()can only handle single-character delimiters when there are consecutive delimiters in a row. - D. No —
split(",")uses a default limit of0, which discards trailing empty strings."a,b,,".split(",")returns["a", "b"](length 2), not 4. Usesplit(",", -1)to keep them.
Answer
Answer: D — By default, split() strips trailing empty strings from the result. To count them, pass a negative limit: csv.split(",", -1).
Spec: Split a comma-separated string and return the number of fields, including trailing empty fields.
public static int countFields(String csv) {
return csv.split(",", -1).length;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — passing
-1as the limit means "return at most negative one results," which is always zero. - C. No — the second argument to
split()must be a regex pattern, not a number, so this fails to compile. - D. No —
split(",", -1)removes empty strings from the beginning of the array but keeps trailing ones, so leading empty fields would still be miscounted.
Answer
Answer: A — A negative limit tells split() to apply the pattern as many times as possible and keep all resulting fields, including trailing empty ones.
Spec: Join a list of words with a comma and a space between them. Example: ["a", "b", "c"] → "a, b, c".
public static String joinWords(java.util.List<String> words) {
return String.join(", ", words);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
String.join()puts the delimiter before the first element too, producing", a, b, c". - C. No —
String.join()only accepts aString[]array, not aList<String>, so this fails to compile. - D. No —
String.join()trims each element automatically, which would remove intentional spaces inside words.
Answer
Answer: A — String.join(delimiter, iterable) places the delimiter strictly between elements, which is exactly what's needed here. It has overloads for both varargs CharSequence... and any Iterable<? extends CharSequence> (including List<String>).
Spec: Join a list of words with commas, with no trailing comma. Example: ["a", "b", "c"] → "a,b,c".
public static String joinWords(java.util.List<String> words) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < words.size(); i++) {
sb.append(words.get(i));
if (i < words.size() - 1) {
sb.append(",");
}
}
return sb.toString();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — calling
words.size()inside the loop condition recalculates the list size every iteration, which breaks for lists larger than 10 elements. - C. No — the condition
i < words.size() - 1skips appending the last word entirely, not just its trailing comma. - D. No —
StringBuilder.append()cannot be called more than once per loop iteration, so this fails to compile.
Answer
Answer: A — The comma is only appended when there's a next element (i < words.size() - 1), so every word is appended and only the interior gaps get commas — no trailing comma. (String.join, from Exercise 35, is the simpler way to do this, but this manual version is also correct.)
Spec: Reverse a string. Example: "hello" → "olleh".
public static String reverse(String s) {
StringBuilder sb = new StringBuilder(s);
sb.reverse();
return s;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
StringBuilder.reverse()does not actually reverse character order; it only reverses the internal capacity array. - C. No —
sb.reverse()mutatessb, but the method returns the original variables, which is untouched. It shouldreturn sb.toString();. - D. No —
reverse()only works correctly on strings with an even number of characters.
Answer
Answer: C — sb.reverse() correctly reverses the characters inside sb, but the method then returns s — the original, unreversed String — instead of sb.toString().
Spec: Reverse a string.
public static String reverse(String s) {
return new StringBuilder(s).reverse().toString();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — chaining
.reverse().toString()callstoString()beforereverse()finishes, due to Java's method call ordering. - C. No —
StringBuilder's constructor copies only the first 16 characters ofsby default, truncating longer strings. - D. No — this reverses the words in a sentence, not the individual characters.
Answer
Answer: A — Method chaining executes left to right: the StringBuilder is built from s, then reversed in place, then converted back to a String. This correctly reverses the characters.
Spec: Return true if the string is a palindrome (reads the same forwards and backwards), case-sensitive. Example: "racecar" → true, "hello" → false.
public static boolean isPalindrome(String s) {
String reversed = new StringBuilder(s).reverse().toString();
return s.equals(reversed);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
s.equals(reversed)always returnsfalsebecausereversedis a different object created byStringBuilder, andequals()behaves like==in that case. - C. No —
StringBuilder.reverse()reverses word order, not character order, so this checks whether the sentence reads the same in reverse word order. - D. No — palindrome checks must ignore case and punctuation by definition, so this implementation is too strict for any valid input.
Answer
Answer: A — String.equals() always compares content, regardless of how the strings were constructed, so this correctly compares s to its reverse. (D is a common trap: the spec given here is explicitly case-sensitive with no punctuation handling — don't assume requirements beyond what's stated.)
Spec: Return true if the string is a palindrome, ignoring case. Example: "Racecar" → true.
public static boolean isPalindrome(String s) {
String lower = s.toLowerCase();
String reversed = new StringBuilder(lower).reverse().toString();
return lower.equals(reversed);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
toLowerCase()must also be called onreversed, or the comparison fails becausereversedretains the original mixed case. - C. No — this only works correctly for palindromes with an odd number of characters.
- D. No —
String.toLowerCase()throws an exception when the string contains digits or punctuation.
Answer
Answer: A — lower is computed once, up front, and reversed is built from lower, so it's already all lowercase — no second toLowerCase() call is needed. "Racecar".toLowerCase() → "racecar", whose reverse is also "racecar", so the comparison correctly succeeds.
Spec: Remove the character at a given index from a string. Example: removeAt("hello", 1) → "hllo".
public static String removeAt(String s, int index) {
StringBuilder sb = new StringBuilder(s);
sb.deleteCharAt(index);
return sb.toString();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
deleteCharAt()removes the character after the given index, not at it, soremoveAt("hello", 1)would return"helo". - C. No —
deleteCharAt()shifts all later indices by two positions instead of one, corrupting the rest of the string. - D. No —
StringBuilder's internal array is fixed-size, sodeleteCharAt()throws an exception unless extra capacity was reserved.
Answer
Answer: A — deleteCharAt(index) removes exactly the character at that index and shifts the rest left by one. deleteCharAt(1) on "hello" removes 'e', giving "hllo", matching the spec.
Spec: Count how many times substr appears in text, non-overlapping. Assume substr is non-empty. Example: countOccurrences("abababab", "ab") → 4.
public static int countOccurrences(String text, String substr) {
int count = 0;
int index = text.indexOf(substr);
while (index != -1) {
count++;
index = text.indexOf(substr, index + substr.length());
}
return count;
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
index + substr.length()skips past valid overlapping matches, undercounting occurrences like"aa"inside"aaa". - C. No —
text.indexOf(substr, ...)throws an exception onceindexreaches the end of the string. - D. No — this requires importing
java.util.regex, becauseindexOf(String, int)is a regex-based method.
Answer
Answer: A — Each match advances the search past the matched text (index + substr.length()), so matches are counted non-overlapping, exactly as the spec asks. indexOf with a start position beyond the string simply returns -1 rather than throwing, so the loop terminates cleanly. (B correctly describes why overlapping matches aren't counted — but the spec explicitly asks for non-overlapping counting, so that's the intended behavior, not a bug.)
Spec: Format a name and age into "Name is Age years old.". Example: describe("Ana", 30) → "Ana is 30 years old.".
public static String describe(String name, int age) {
return String.format("%d is %s years old.", name, age);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No — format specifiers are matched positionally to arguments;
%dis matched toname(aString), which throws anIllegalFormatConversionExceptionat runtime. The specifiers should be"%s is %d years old.". - C. No —
String.format()ignores mismatched specifiers and just prints arguments in the order given, regardless of%sor%d. - D. No —
String.format()requires exactly as many%specifiers as there are periods in the format string.
Answer
Answer: B — %d expects a numeric argument and is matched to the first argument, name. Since name is a String, this throws at runtime rather than producing output.
Spec: Format a name and age into "Name is Age years old.".
public static String describe(String name, int age) {
return String.format("%s is %d years old.", name, age);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
%drequires the argument to be along, not anint, so this throws an exception. - C. No —
String.format()returnsvoidand prints directly to the console, so this method actually returnsnull. - D. No — the specifiers are applied in reverse order, so this prints the age first.
Answer
Answer: A — %s correctly matches the String argument and %d correctly matches the int argument, in order, producing "Ana is 30 years old.".
Spec: Format an integer with leading zeros to a width of 5. Example: padded(42) → "00042".
public static String padded(int n) {
return String.format("%5d", n);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
%5dpads with spaces to reach a width of 5, not zeros;padded(42)returns" 42", not"00042". Use%05dto zero-pad. - C. No — the
5in%5dsets the number of decimal places, not the total width, so this only works for numbers under 5 digits. - D. No —
String.format()cannot pad integers at all; padding only works with%sfor strings.
Answer
Answer: B — A plain width specifier like %5d pads with spaces. The 0 flag (%05d) is what tells it to pad with zeros instead.
Spec: Format an integer with leading zeros to a width of 5.
public static String padded(int n) {
return String.format("%05d", n);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
%05dpads with zeros only on negative numbers; positive numbers are still padded with spaces. - C. No — this throws an exception whenever
nis already 5 digits or longer. - D. No — the leading
0in the specifier is interpreted as an argument index, not a padding flag, so this inserts the number twice.
Answer
Answer: A — The 0 flag in %05d zero-pads the number to the given width for any non-negative int. padded(42) correctly returns "00042".
Spec: Return a string of n dashes. Example: repeatDash(4) → "----". (Java 11+)
public static String repeatDash(int n) {
return "-".repeat(n);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
repeat()concatenates the string with itself only once regardless ofn, always returning"--"for any positiven. - C. No —
repeat()is aStringBuilder-only method, not available onString, so this fails to compile. - D. No —
repeat(n)repeats the stringn + 1times due to an off-by-one in its implementation.
Answer
Answer: A — String.repeat(n) (Java 11+) returns the string concatenated with itself n times, so "-".repeat(4) correctly returns "----".
Spec: Convert an object to its string representation, returning the text "null" if the object is null (rather than throwing).
public static String describe(Object obj) {
return obj.toString();
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
toString()only works on Strings, not general Objects, so this fails to compile for non-String arguments. - C. No — calling
.toString()onobjthrows aNullPointerExceptionwhenobjisnull. UseString.valueOf(obj), which safely returns the text"null"instead of throwing. - D. No —
toString()andString.valueOf()behave identically in every case, so this is just a differently-named equivalent.
Answer
Answer: C — obj.toString() requires dereferencing obj, which fails immediately if obj is null. String.valueOf(Object) explicitly checks for null first and returns the literal text "null" instead.
Spec: Convert an object to its string representation, returning the text "null" if the object is null.
public static String describe(Object obj) {
return String.valueOf(obj);
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
String.valueOf()throws aNullPointerExceptionfornullinput, just like callingtoString()directly. - C. No —
String.valueOf(Object)requires an explicit cast toObject, or it resolves to the wrong overload for non-null arguments. - D. No —
String.valueOf()returns an empty string""fornullinput instead of the text"null".
Answer
Answer: A — String.valueOf(Object obj) is documented to return "null" when obj is null, and obj.toString() otherwise. This correctly satisfies the spec without risking a NullPointerException.
Spec: Remove all periods from a string. Example: "a.b.c" → "abc".
public static String removeDots(String s) {
return s.replaceAll(".", "");
}Does this code do this correctly? If not, why not?
- A. Yes, it is correct.
- B. No —
replaceAll()only removes the first matching character, not all occurrences, despite the name. - C. No —
replaceAll()cannot take an empty string as its replacement argument and throws an exception. - D. No —
replaceAll()treats its first argument as a regular expression, and an unescaped.matches any character, so this removes every character in the string, returning""instead of"abc". Uses.replace(".", "")(literal, see Exercise 10) ors.replaceAll("\\.", "")(escaped regex).
Answer
Answer: D — Just like split() (Exercise 31), replaceAll() takes a regex pattern. An unescaped . matches any character, so every character gets "replaced" with nothing, leaving an empty string.
| # | Ans | # | Ans | # | Ans | # | Ans | |||
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | B | 14 | A | 27 | D | 40 | A | |||
| 2 | A | 15 | D | 28 | A | 41 | A | |||
| 3 | A | 16 | A | 29 | C | 42 | A | |||
| 4 | C | 17 | A | 30 | A | 43 | B | |||
| 5 | A | 18 | A | 31 | D | 44 | A | |||
| 6 | A | 19 | B | 32 | A | 45 | B | |||
| 7 | D | 20 | A | 33 | D | 46 | A | |||
| 8 | A | 21 | B | 34 | A | 47 | A | |||
| 9 | A | 22 | A | 35 | A | 48 | C | |||
| 10 | A | 23 | A | 36 | A | 49 | A | |||
| 11 | B | 24 | A | 37 | C | 50 | D | |||
| 12 | A | 25 | C | 38 | A | |||||
| 13 | C | 26 | A | 39 | A |