Study guide

6.4 The Map Interface, Sorting, Comparable, and Comparator

Oracle Java SE 17 Developer Certified Professional 1Z0-829

Track your progress as you read

Finished sections get a check mark.

1 Introduction: The 1Z0-829 Exam

About the Java SE 17 Developer (1Z0-829) Exam

2 Chapter 1: Java Fundamentals & Language Basics

1.1 Primitive Types, Literals, Wrapper Classes, and Type Promotion/Casting 1.2 Local Variable Type Inference (`var`) Rules and Scoping 1.3 Operators, Precedence, Evaluation Order, and Short-Circuit Evaluation 1.4 Text Blocks, String Immutability, and StringBuilder APIs

3 Chapter 2: Program Flow & Decision Constructs

2.1 Conditional Branching with if/else and the Ternary Operator 2.2 Switch Statements and Switch Expressions 2.3 Iteration Constructs, Loop Control, and Branching Labels

4 Chapter 3: Object-Oriented Design & Class Mechanics

3.1 Class Declarations, Field/Method Signatures, and Access Modifiers 3.2 Constructors, Overloading, Initialization Order, and Garbage Collection 3.3 Inheritance, Method Overriding, Polymorphism, and `super`/`this` 3.4 Abstract Classes, Static Members, and Object Methods (`equals`, `hashCode`, `toString`)

5 Chapter 4: Advanced OOP: Interfaces, Records & Sealed Types

4.1 Interface Architecture: Default, Static, and Private Methods 4.2 Enumerations: Constants, Constructors, Methods, and Custom Bodies 4.3 Records: Canonical/Compact Constructors, Components, and Immutability 4.4 Sealed Classes and Interfaces: `permits`, Hierarchy Constraints, and Modifiers

6 Chapter 5: Pattern Matching & Nested Types

5.1 Pattern Matching for `instanceof` and Flow Scoping Mechanics 5.2 Nested Types: Member Inner, Static Nested, Local, and Anonymous Classes 5.3 Defensive Programming, Immutability Patterns, and Validation

7 Chapter 6: Generics, Collections & Arrays

6.1 Generic Classes, Interfaces, Methods, and Type Erasure 6.2 Bounded Type Parameters and Wildcards (PECS Rule) 6.3 Collections Framework: List, Set, Queue, and Deque APIs 6.4 The Map Interface, Sorting, Comparable, and Comparator 6.5 Arrays: Declaration, Initialization, Multidimensional Arrays, and the Arrays Utility Class

8 Chapter 7: Functional Programming & Lambda Expressions

7.1 Functional Interfaces and Lambda Syntax Rules 7.2 Standard Functional Interfaces in `java.util.function` 7.3 Method References: Static, Bound, Unbound, and Constructor References

9 Chapter 8: The Stream API

8.1 Stream Lifecycle: Creation, Pipeline Architecture, and Lazy Evaluation 8.2 Intermediate Stream Operations: Filtering, Mapping, Sorting, and Slicing 8.3 Terminal Stream Operations: Reduction, Matching, Finding, and Collecting 8.4 Primitive Streams (`IntStream`, `LongStream`, `DoubleStream`) and Numeric Statistics

10 Chapter 9: Advanced Streams & Collectors

9.1 The Optional Class: Safe Null Handling, Transformation, and Chaining 9.2 The Collectors API: Downstream Reductions, Grouping, and Partitioning 9.3 Parallel Streams: Fork/Join Pool, Spliterators, and Concurrency Pitfalls

11 Chapter 10: Exception Handling

10.1 The Java Exception Hierarchy: Checked vs. Unchecked Exceptions and Errors 10.2 Exception Constructs: `try-catch-finally`, Multi-Catch, and Rethrowing 10.3 Try-With-Resources, `AutoCloseable`, Suppressed Exceptions, and Custom Exceptions

12 Chapter 11: Date/Time API & Localization

11.1 Date and Time Core Types: `LocalDate`, `LocalTime`, `LocalDateTime` 11.2 Timestamps, Intervals, and Durations: `Instant`, `Period`, and `Duration` 11.3 Time Zones, Daylight Saving Time (DST) Offsets, and `ZonedDateTime` 11.4 Internationalization and Localization: `Locale`, `ResourceBundle`, and Formatters 11.5 Formatting and Parsing Messages, Numbers, Percentages, and Localized Dates

13 Chapter 12: Java Platform Module System (JPMS)

12.1 Module Architecture, `module-info.java`, and Module Paths 12.2 Module Directives: `requires`, `requires transitive`, `exports`, and Qualified Exports 12.3 Reflection, Deep Encapsulation, `opens`, and Open Modules 12.4 Services in JPMS (`uses`, `provides...with`), Migration Paths, and Tooling (`jlink`, `jdeps`) 12.5 Compiling and Packaging Code: Non-Modular JARs, Modular JARs, and Migration Strategies

14 Chapter 13: Concurrency & Multithreading

13.1 Thread Fundamentals, `Runnable`, `Callable`, and Thread Lifecycle 13.2 Memory Visibility, `volatile`, Intrinsic Locks, and Synchronization 13.3 The Concurrency Framework: `ExecutorService`, Thread Pools, and `Future` 13.4 Concurrent Collections, Atomic Variables, Explicit Locks, and `CompletableFuture`

15 Chapter 14: Java I/O and NIO.2

14.1 Classical I/O: Byte and Character Streams, Readers, Writers, and Buffering 14.2 Object Serialization, `Serializable`, `transient`, and `serialVersionUID` 14.3 NIO.2 Architecture: `Path`, `Paths`, and Basic `Files` Operations 14.4 Advanced NIO.2: Directory Walking, Streams (`Files.lines`, `walk`), and `WatchService`

16 Chapter 15: Accessing Databases with JDBC

15.1 JDBC Architecture, Drivers, `DriverManager`, and `DataSource` Connections 15.2 SQL Execution: `Statement`, `PreparedStatement`, and `CallableStatement` 15.3 `ResultSet` Navigation, Data Types, and Transaction Management (Commit, Rollback, Savepoints)

17 Chapter 16: Annotations & the Java Logging API

16.1 Standard Annotations: @Override, @FunctionalInterface, @Deprecated, @SuppressWarnings, and @SafeVarargs 16.2 Java Logging API Basics: Logger, Levels, Handlers, and Configuration

6.4 The Map Interface, Sorting, Comparable, and Comparator

Key Takeaways Explain This Topic AI

Map implementations manage key-value pairs outside the Collection hierarchy: HashMap provides O(1) hash bucket lookups, LinkedHashMap preserves insertion/access order, and TreeMap guarantees O(log n) key-sorted traversal.

Keys in hash-based collections must adhere strictly to the equals and hashCode contract; mutating key state after insertion alters the hash code and permanently strands entries in unreachable buckets.

Modern Map functional methods (computeIfAbsent, computeIfPresent, compute, merge) execute atomic updates; returning null from a remapping function removes the corresponding entry from the map.

Comparable<T> defines intrinsic natural ordering via int compareTo(T o), which must remain consistent with equals() to prevent TreeSet and TreeMap from discarding non-identical elements as duplicates.

Comparator<T> provides external custom ordering through int compare(T o1, T o2) and fluent combinators (comparing, thenComparing, reversed, nullsFirst, nullsLast).

Last updated: October 2026

6.4 The Map Interface, Sorting, Comparable , and Comparator

Mapping keys to values and establishing precise sort orders are foundational operations in enterprise Java development. The Map<K, V> interface provides key-value associations without extending Collection . On the 1Z0-829 exam, questions frequently test the inner workings of hash bucket resolution, the strict equals() and hashCode() contract, modern lambda-enabled Map methods ( merge , computeIfAbsent ), and complex multi-tiered sorting using Comparable and Comparator combinators.

The Map Interface and Implementations

A Map<K, V> maps unique keys to values, prohibiting duplicate keys. Its primary implementations offer distinct performance and ordering trade-offs:

1. HashMap

Internal Structure : An array of hash buckets. Collisions are stored in linked lists; when a bucket exceeds 8 entries and total table capacity reaches at least 64, the bucket transforms into a balanced red-black tree ( TreeNode ) to guarantee O ( log ⁡ n ) O(\log n) O ( lo g n ) worst-case lookup rather than O ( n ) O(n) O ( n ) .

Null Policy : Allows one null key and multiple null values.

Ordering : No ordering guarantees; bucket order shifts when resizing.

2. LinkedHashMap

Internal Structure : Extends HashMap while maintaining a doubly-linked list through all entries.

Ordering Modes : Defaults to insertion order . Can be configured via its constructor ( new LinkedHashMap<>(16, 0.75f, true) ) to track access order , making it an ideal foundation for Least-Recently-Used (LRU) caches when combined with removeEldestEntry() .

3. TreeMap

Internal Structure : A Red-Black tree implementing NavigableMap<K, V> .

Ordering : Keys are sorted according to natural ordering ( Comparable ) or an explicit Comparator .

Null Policy : Prohibits null keys when using natural ordering (throws NullPointerException ). Allows null values.

Performance : O ( log ⁡ n ) O(\log n) O ( lo g n ) for get , put , remove , and containsKey . NavigableMap<Integer, String> treeMap = new TreeMap<>();

  • treeMap.put(10, "Ten");
  • treeMap.put(20, "Twenty");
  • treeMap.put(30, "Thirty");
  • System.out.println(treeMap.lowerKey(20)); // 10 (greatest key < 20)
  • System.out.println(treeMap.floorKey(20)); // 20 (greatest key <= 20)
  • System.out.println(treeMap.ceilingKey(25)); // 30 (least key >= 25)
  • System.out.println(treeMap.higherKey(20)); // 30 (least key > 20)
  • The equals() and hashCode() Contract

Hash-based collections ( HashMap , HashSet ) use an object's hashCode() to determine its bucket index, and equals() to resolve bucket collisions. The contract mandates:

If a.equals(b) is true , then a.hashCode() == b.hashCode() must be true .

If a.hashCode() == b.hashCode() , a.equals(b) is not required to be true (hash collision).

If a.equals(b) is false , hash codes are not required to be distinct, though unique hash codes optimize performance.

The Mutable Key Hazard

If an object used as a map key is mutated such that its hashCode() changes, the entry becomes permanently lost: class AccountKey {

  • int accountId;
  • AccountKey(int id) { this.accountId = id; }
  • public boolean equals(Object o) {
  • return o instanceof AccountKey k && this.accountId == k.accountId;
  • }
  • public int hashCode() { return accountId; }
  • }
  • Map<AccountKey, String> map = new HashMap<>();
  • AccountKey key = new AccountKey(101);
  • map.put(key, "Active");
  • // Mutate key field after insertion
  • key.accountId = 999;

// Lookup computes hashCode 999, searching the wrong bucket!

System.out.println(map.get(key)); // Prints null! Entry is stranded.

Warning

Always use immutable types (such as String , Integer , or Java 16 record types) as map keys to guarantee hash code stability.

Modern Functional Map Methods (Java 8+)

Java 8 introduced powerful methods on Map that accept lambdas for atomic modifications:

1. getOrDefault(key, defaultValue)

Returns the value mapped to key , or defaultValue if the key is not found or is explicitly mapped to null .

2. putIfAbsent(key, value)

Inserts value only if key is absent or currently mapped to null . Returns the existing value, or null if the new value was placed.

3. computeIfAbsent(key, k -> compute(k))

If key is absent or mapped to null , evaluates the mapping function. If the function returns non-null, inserts the result and returns it. If the function returns null , no entry is created.

4. computeIfPresent(key, (k, v) -> compute(k, v))

If key is present and mapped to a non-null value, executes the remapping function with (key, oldValue) .

If the function returns non-null, updates the entry.

CRITICAL TRAP : If the function returns null , the entry is removed from the map !

5. compute(key, (k, v) -> compute(k, v))

Executes the remapping function regardless of whether the key exists ( v will be null if absent).

If the function returns non-null, inserts or updates the entry.

If the function returns null , removes the entry (or leaves it absent).

6. merge(key, value, (oldVal, newVal) -> remap)

The merge method has the most surprising rules of the group. It takes a key, a non-null value , and a BiFunction remapping function:

If key is absent or mapped to null : associates key directly with value . The remapping function is never invoked !

If key is present with non-null oldVal : invokes remappingFunction.apply(oldVal, value) .

If the function returns non-null, updates the key with the returned result.

CRITICAL TRAP : If the function returns null , the key is removed from the map !

If the value argument passed to merge is null , it throws NullPointerException immediately. Map<String, Integer> scores = new HashMap<>();

  • scores.put("Alice", 90);
  • scores.put("Bob", 50);
  • // 1. Existing key: invokes lambda (90 + 10 = 100)
  • scores.merge("Alice", 10, (oldVal, newVal) -> oldVal + newVal); // Alice=100
  • // 2. Absent key: assigns 75 directly without calling lambda
  • scores.merge("Carol", 75, (oldVal, newVal) -> oldVal + newVal); // Carol=75

// 3. Lambda returns null: REMOVES key from map!

scores.merge("Bob", 50, (oldVal, newVal) -> null); // Bob is removed!

  • System.out.println(scores); // Prints {Alice=100, Carol=75}
  • Sorting with Comparable<T> vs. Comparator<T>

Java provides two interfaces to define order:

  • Dimension Comparable<T> Comparator<T>
  • Package java.lang java.util
  • Definition Site Defined within the domain class itself Defined externally as separate classes or lambdas
  • Abstract Method int compareTo(T other) int compare(T o1, T o2)
  • Role Natural intrinsic ordering Custom, multiple, or dynamic sort orders
  • Sorting Invocations Collections.sort(list) list.sort(comparator) / Collections.sort(list, comparator)
  • The compareTo Contract and TreeSet / TreeMap

The compareTo(T o) method returns:

  • A negative integer if this < o
  • Zero if the two objects are equal in sort order (ideally only when this.equals(o) is also true )
  • A positive integer if this > o

Warning

The TreeSet / TreeMap Consistency with Equals Trap TreeSet and TreeMap determine element equality and uniqueness using compareTo() (or compare() ), not equals() ! If a.compareTo(b) == 0 , a TreeSet treats b as an exact duplicate of a and discards it—even if a.equals(b) is false ! Always ensure natural ordering is consistent with equals() .