Implementing the Comparable interface establishes a natural ordering for a class. When a domain object overrides compareTo, standard collection utilities can sort instances without external configuration.
import java.util.ArrayList;
import java.util.List;
public class NaturalOrderingDemo {
public static void main(String[] args) {
List<StaffMember> team = new ArrayList<>();
team.add(new StaffMember("Alice"));
team.add(new StaffMember("Charlie"));
team.add(new StaffMember("Bob"));
team.forEach(m -> System.out.println(m.identifier));
System.out.println("--- After Sorting ---");
// Utilizes the natural ordering defined in StaffMember
team.sort(null);
team.forEach(m -> System.out.println(m.identifier));
}
}
class StaffMember implements Comparable<StaffMember> {
String identifier;
StaffMember(String identifier) {
this.identifier = identifier;
}
@Override
public int compareTo(StaffMember other) {
// Descending alphabetical order
return other.identifier.compareTo(this.identifier);
}
}
Output:
Alice
Charlie
Bob
--- After Sorting ---
Charlie
Bob
Alice
When modifying the source class is impossible or multiple sorting criteria are needed, Comparator decouples the ordering logic from the data model. This approach allows dynamic strategy selection at runtime.
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class ExternalOrderingDemo {
public static void main(String[] args) {
List<InventoryItem> stock = Arrays.asList(
new InventoryItem("Laptop", 1200),
new InventoryItem("Mouse", 25),
new InventoryItem("Monitor", 300)
);
stock.forEach(i -> System.out.println(i.label + ": $" + i.cost));
System.out.println("--- Sorted by Cost ---");
// Applies an external comparison strategy
stock.sort(new CostAscendingComparator());
stock.forEach(i -> System.out.println(i.label + ": $" + i.cost));
}
}
class InventoryItem {
String label;
int cost;
InventoryItem(String label, int cost) {
this.label = label;
this.cost = cost;
}
}
class CostAscendingComparator implements Comparator<InventoryItem> {
@Override
public int compare(InventoryItem first, InventoryItem second) {
return Integer.compare(first.cost, second.cost);
}
}
Output:
Laptop: $1200
Mouse: $25
Monitor: $300
--- Sorted by Cost ---
Mouse: $25
Monitor: $300
Laptop: $1200
Standard HashMap instances do not guarantee iteration order. To reorder map entries based on keys or values, the entry set can be streamed, sorted with a comparator, and collected into a LinkedHashMap to preserve the new sequence.
import java.util.*;
import java.util.stream.Collectors;
public class MapSortingUtil {
// Orders entries by their values in ascending order
public static <K, V extends Comparable<? super V>> Map<K, V> orderByValue(Map<K, V> source) {
return source.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
}
// Orders entries by their keys in descending order
public static <K extends Comparable<? super K>, V> Map<K, V> orderByKeyDesc(Map<K, V> source) {
return source.entrySet().stream()
.sorted((entryA, entryB) -> entryB.getKey().compareTo(entryA.getKey()))
.peek(e -> System.out.println("Processing -> Key: " + e.getKey() + " | Val: " + e.getValue()))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
}
public static void main(String[] args) {
Map<Integer, String> priorityTasks = new HashMap<>();
priorityTasks.put(3, "Deploy");
priorityTasks.put(1, "Design");
priorityTasks.put(2, "Develop");
Map<Integer, String> sortedByKey = orderByKeyDesc(priorityTasks);
System.out.println("Final Map: " + sortedByKey);
}
}
LinkedHashMap maintains insertion order through an internal doubly-linked list. While standard API traversal requires O(N) time to reach the end, the most recently inserted element can be retrieved in O(1) by accessing the private tail node via reflection. This technique bypasses public API limitaitons but depends on internal JDK structure.
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapInternals {
public static void main(String[] args) throws Exception {
Map<String, Integer> cache = new LinkedHashMap<>();
cache.put("alpha", 10);
cache.put("beta", 20);
cache.put("gamma", 30);
// Access internal tail field directly
Field tailField = LinkedHashMap.class.getDeclaredField("tail");
tailField.setAccessible(true);
@SuppressWarnings("unchecked")
Map.Entry<String, Integer> lastNode = (Map.Entry<String, Integer>) tailField.get(cache);
if (lastNode != null) {
System.out.println("Last Key: " + lastNode.getKey());
System.out.println("Last Value: " + lastNode.getValue());
}
}
}