Review object comparison, list sorting, exception checking, and the distinction between a Thread object and an executing thread.
Answer: Collections.sort(list) and the object-array overload Arrays.sort(array) are two familiar examples. They use Comparable rather than requiring a separate comparator. In Java SE 25, list.sort(null) also requests natural ordering, and Comparator.naturalOrder() supplies it explicitly where a comparator is accepted.
The elements must be mutually comparable; mixing incompatible types or encountering null can cause a runtime exception. A correct compareTo implementation must obey the ordering contract, including transitivity. Use Integer.compare or comparator construction methods rather than subtraction when comparing integer fields.
Answer: String implements Comparable<String>. Primitive wrapper classes such as Integer and Double also define natural orderings for values of their own wrapper type. String is not itself a primitive wrapper, and the Number superclass does not establish one common ordering across all numeric subclasses.
A custom class can implement Comparable when it has a useful default ordering. Alternatively, supply a Comparator at the point of use; the class being sorted does not then need to implement Comparable. Comparators are especially useful when users can sort the same objects by several different fields.
Answer: Comparable requires compareTo; it does not require an equals override. However, natural ordering should normally be consistent with equality: comparison returns zero exactly when equals returns true. If equals is overridden, hashCode must also follow its contract.
BigDecimal is a documented exception: new BigDecimal("1.0") and new BigDecimal("1.00") compare as zero, but are not equal because their scales differ. Consequently, a TreeSet can treat them as one element while a HashSet stores both. Understand this distinction before choosing sorted or hash-based collections for a domain model.
Answer: A common declaration is List<String> names = new ArrayList<>();, with both types imported from java.util. The variable exposes the List interface while the object supplies ArrayList's implementation. Generics let the compiler reject additions of incompatible types.
Use the concrete type when you need an implementation-specific operation. Local-variable inference, var names = new ArrayList<String>();, is also valid but infers ArrayList. Avoid raw declarations such as List names. If no mutation is needed, List.of("Ada", "Grace") offers an unmodifiable alternative rather than a mutable ArrayList.
Answer: Call list.sort(comparator) to reorder a mutable list in place. Collections.sort(list) uses natural ordering; Collections is a utility class, not a package. An unmodifiable list does not support in-place sorting, so first copy it into a mutable list or obtain a separately sorted result.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class ListSorting {
public static void main(String[] args) {
List<String> names = new ArrayList<>(List.of("Grace", "Ada", "Linus"));
names.sort(Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder()));
System.out.println(names);
}
}
The output is [Ada, Grace, Linus]. The comparator orders by length first, then natural order for ties. List sorting is stable: elements that compare as equal retain their relative order.
Answer: A checked exception is an exception type subject to the compiler's catch-or-declare rules. Throwable subclasses other than RuntimeException, Error, and their respective subclasses are checked. Most application examples extend Exception, such as IOException.
If an operation can throw a checked exception that escapes a method, that method must declare an appropriate throws clause, unless the exception is handled within it. This is a compile-time obligation, not a guarantee that the operation will fail. Choose handling that adds useful recovery or context; an empty catch block merely hides the problem.
Answer: Both directly extend Throwable. Throwable provides the message, cause, stack trace, and suppressed-exception facilities used to describe failures. Exception generally represents conditions an application may want to handle, while Error represents serious problems that ordinary application code generally should not try to recover from indiscriminately.
RuntimeException extends Exception, so âall Exceptions are checkedâ is incorrect. Catching Exception also catches RuntimeException subclasses but does not catch Error. Catching Throwable includes both branches and should be reserved for a carefully designed boundary, rather than used as routine error handling.
Answer: RuntimeException and Error, together with their subclasses, are unchecked. Examples include NullPointerException, IllegalArgumentException, and OutOfMemoryError. The compiler does not require callers to catch or declare them.
Unchecked does not mean harmless or impossible to anticipate. Validate inputs, maintain invariants, and fix programming errors rather than catching a broad RuntimeException around every operation. It can still be appropriate to catch a specific unchecked exception at a meaningful boundary, such as handling invalid number input, provided the code has a clear recovery policy.
Answer: No. Error subclasses are unchecked, so a method does not need a throws declaration merely because such an error could occur. This does not exempt code from other compiler rules: a thrown value must still have a Throwable-compatible type, and catch clauses must still be legal.
Do not interpret the absence of a compiler obligation as an instruction to ignore all failures. Application-level cleanup should use constructs such as try-with-resources and finally where appropriate, while recognizing that abrupt process termination cannot guarantee cleanup. Recovery from an Error requires specific knowledge of the condition.
Answer: A Thread object is the Java object used to represent and control a thread's lifecycle. Constructing an ordinary Thread creates an object in the NEW state; invoking start schedules execution of its task. After the task terminates, the object can remain reachable even though its execution has ended.
Java SE 25 supports platform threads and virtual threads. Platform threads are typically associated with operating-system threads; virtual threads are scheduled by the Java runtime. Both use the Thread API, start at most once, and have the same Thread.State enum. Calling a Runnable's run method directly is an ordinary method call, not a request for another thread.
References: Comparable, List, Java exception rules, and Thread.