Java中Comparator使用问题:Map<String, AtomicInteger>按值排序
Map<String, AtomicInteger> by Its Values in Java Let's break down the issues with your current approaches and fix them, plus show you a cleaner way to handle this using Java 8+ streams.
Why Your Current Code Isn't Working
- Lambda Comparator Issue: When you cast
entrytoObject, the compiler doesn't recognize it as aMap.Entry—so callingentry.getValue()throws a compile error. You need to explicitly cast it to the correct entry type. - Anonymous Inner Class Issue: Using a raw
Comparator(without specifying the generic type) leads to unsafe type casts, and the incomplete code in your snippet (you cut offgetValue(...)) likely causes compilation or runtime errors.
Fixed Approach 1: Corrected Lambda with Arrays.sort()
Fix the type casting in your lambda to tell the compiler you're dealing with Map.Entry<String, AtomicInteger>:
Object[] a = map.entrySet().toArray(); // Ascending order (smallest to largest AtomicInteger value) Arrays.sort(a, Comparator.comparingInt(entry -> ((Map.Entry<String, AtomicInteger>) entry).getValue().get() )); // For descending order (largest to smallest), add .reversed() Arrays.sort(a, Comparator.comparingInt((Map.Entry<String, AtomicInteger> entry) -> entry.getValue().get() ).reversed());
Fixed Approach 2: Type-Safe Anonymous Inner Class
Avoid raw types by specifying the generic Comparator<Map.Entry<String, AtomicInteger>>, and use Integer.compare() to prevent integer overflow issues (better than subtracting values directly):
Object[] a = map.entrySet().toArray(); Arrays.sort(a, new Comparator<Map.Entry<String, AtomicInteger>>() { @Override public int compare(Map.Entry<String, AtomicInteger> o1, Map.Entry<String, AtomicInteger> o2) { // Ascending order return Integer.compare(o1.getValue().get(), o2.getValue().get()); // Descending order: return Integer.compare(o2.getValue().get(), o1.getValue().get()); } });
Recommended Approach: Use Java Streams (Cleaner & Type-Safe)
Instead of dealing with Object[] arrays, use streams to directly sort and collect the entries into a list—this avoids manual type casts and makes the code more readable:
// Sort entries in ascending order of AtomicInteger value List<Map.Entry<String, AtomicInteger>> sortedAsc = map.entrySet() .stream() .sorted(Comparator.comparingInt(entry -> entry.getValue().get())) .collect(Collectors.toList()); // Sort in descending order List<Map.Entry<String, AtomicInteger>> sortedDesc = map.entrySet() .stream() .sorted(Comparator.comparingInt((Map.Entry<String, AtomicInteger> entry) -> entry.getValue().get()) .reversed()) .collect(Collectors.toList()); // Print the sorted results for (Map.Entry<String, AtomicInteger> entry : sortedAsc) { System.out.printf("%s: %d%n", entry.getKey(), entry.getValue().get()); }
Bonus: Handle Ties with Secondary Sort
If multiple entries have the same AtomicInteger value, you can add a secondary sort on the key to ensure consistent ordering:
List<Map.Entry<String, AtomicInteger>> sortedWithTiebreaker = map.entrySet() .stream() .sorted(Comparator.comparingInt(entry -> entry.getValue().get()) .thenComparing(Map.Entry::getKey)) // Sort by key ascending if values match .collect(Collectors.toList());
Important Note for Multi-Threaded Environments
Since AtomicInteger is thread-safe, keep in mind that if other threads modify the values while you're sorting, your results might be inconsistent. If this is a concern, consider locking the map during the sorting process or making a copy of the values before sorting.
内容的提问来源于stack exchange,提问作者Karl

