杰瑞科技汇

Java dictionary如何高效实现?

Of course! In Java, the term "dictionary" isn't a built-in class. Instead, it refers to a general concept of a data structure that stores key-value pairs. You look up a value using its unique key.

Java dictionary如何高效实现?-图1
(图片来源网络,侵删)

The primary and most common interface for this in Java is the java.util.Map interface. The most frequently used implementation of Map is HashMap.

Let's break it down, starting from the most common approach and covering other important types.


The Main Player: Map Interface and HashMap

This is the go-to for most situations where you need a dictionary.

Key Characteristics of HashMap:

  • Unordered: The elements are not stored in any predictable order (neither insertion order nor sorted order).
  • Fast Lookups, Insertions, and Deletions: On average, these operations take constant time, O(1).
  • Allows one null key and multiple null values.
  • Not Synchronized: It is not thread-safe. If multiple threads modify a HashMap concurrently, you must synchronize it externally.

How to Use HashMap (The Classic Way)

Here's a complete, runnable example.

Java dictionary如何高效实现?-图2
(图片来源网络,侵删)
import java.util.HashMap;
import java.util.Map;
public class JavaDictionaryExample {
    public static void main(String[] args) {
        // 1. Create a HashMap (the dictionary)
        // The syntax is Map<KeyType, ValueType>
        Map<String, Integer> wordCount = new HashMap<>();
        // 2. Add key-value pairs (put)
        wordCount.put("apple", 5);
        wordCount.put("banana", 3);
        wordCount.put("orange", 8);
        wordCount.put("apple", 10); // This will update the value for "apple" from 5 to 10
        System.out.println("Initial dictionary: " + wordCount);
        // 3. Get a value by its key (get)
        Integer countOfApple = wordCount.get("apple");
        System.out.println("Count of 'apple': " + countOfApple); // Output: 10
        // 4. Check if a key exists (containsKey)
        if (wordCount.containsKey("banana")) {
            System.out.println("'banana' is in the dictionary.");
        }
        // 5. Check if a value exists (containsValue)
        if (wordCount.containsValue(8)) {
            System.out.println("The value 8 is in the dictionary.");
        }
        // 6. Remove a key-value pair (remove)
        wordCount.remove("orange");
        System.out.println("After removing 'orange': " + wordCount);
        // 7. Get the size of the dictionary (size)
        System.out.println("Size of the dictionary: " + wordCount.size());
        // 8. Iterate over the dictionary
        System.out.println("\nIterating over the dictionary:");
        // Using a for-each loop to get the entries (key-value pairs)
        for (Map.Entry<String, Integer> entry : wordCount.entrySet()) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }
    }
}

Output:

Initial dictionary: {orange=8, banana=3, apple=10}
Count of 'apple': 10
'banana' is in the dictionary.
The value 8 is in the dictionary.
After removing 'orange': {banana=3, apple=10}
Size of the dictionary: 2
Iterating over the dictionary:
Key: banana, Value: 3
Key: apple, Value: 10

Modern Java: Map.of() (For Immutable Dictionaries)

Since Java 9, you can create small, immutable dictionaries (maps) very easily using the Map.of() factory methods. These are great for configuration data that shouldn't change.

import java.util.Map;
public class ImmutableDictionaryExample {
    public static void main(String[] args) {
        // Create an immutable map with key-value pairs
        Map<String, String> countryCapitals = Map.of(
            "USA", "Washington D.C.",
            "UK", "London",
            "Japan", "Tokyo"
        );
        System.out.println("Immutable map: " + countryCapitals);
        // You can still read data
        System.out.println("Capital of Japan: " + countryCapitals.get("Japan"));
        // But you cannot modify it! The following lines will cause a compilation error.
        // countryCapitals.put("France", "Paris"); // -> java.lang.UnsupportedOperationException
        // countryCapitals.remove("UK");           // -> java.lang.UnsupportedOperationException
    }
}

Other Map Implementations (When to Use What)

Java provides several Map implementations for different needs.

Implementation Order Key Characteristics When to Use
HashMap Unordered Fastest for general-purpose use. Not thread-safe. The default choice. Use when you don't care about order and need fast performance.
LinkedHashMap Insertion Order Maintains the order in which keys were inserted. Slightly slower than HashMap. When you need to preserve the insertion order of keys (e.g., caching with LRU logic).
TreeMap Sorted (Natural or Custom) Keys are stored in a sorted tree structure. Slower than HashMap (O(log n)). When you need the keys to be sorted (e.g., alphabetical, numerical).
Hashtable Unordered Legacy class. Synchronized (thread-safe), but slow. Does not allow null keys or values. Avoid in new code. Use ConcurrentHashMap for thread-safe maps instead.
ConcurrentHashMap Unordered High-performance, thread-safe alternative to Hashtable. When multiple threads need to read and write to the map concurrently.

Example: TreeMap for Sorted Data

import java.util.Map;
import java.util.TreeMap;
public class SortedDictionaryExample {
    public static void main(String[] args) {
        // TreeMap automatically sorts keys based on their natural order (for Strings, alphabetically)
        Map<String, Integer> scores = new TreeMap<>();
        scores.put("Charlie", 95);
        scores.put("Alice", 100);
        scores.put("Bob", 85);
        System.out.println("Scores in alphabetical order: " + scores);
        // Output: Scores in alphabetical order: {Alice=100, Bob=85, Charlie=95}
    }
}

Java 8+ Streams and Functional Operations

Modern Java makes working with dictionaries even more powerful using Streams.

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class DictionaryStreamExample {
    public static void main(String[] args) {
        Map<String, Integer> inventory = new HashMap<>();
        inventory.put("apples", 10);
        inventory.put("bananas", 25);
        inventory.put("oranges", 18);
        inventory.put("grapes", 5);
        // 1. Filter: Find all fruits with more than 15 items
        Map<String, Integer> highStock = inventory.entrySet()
                .stream()
                .filter(entry -> entry.getValue() > 15)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        System.out.println("High stock items: " + highStock);
        // Output: High stock items: {bananas=25, oranges=18}
        // 2. Transform: Create a new map with keys in uppercase
        Map<String, Integer> upperCaseInventory = inventory.entrySet()
                .stream()
                .collect(Collectors.toMap(
                        entry -> entry.getKey().toUpperCase(), // Key mapper
                        Map.Entry::getValue                     // Value mapper
                ));
        System.out.println("Inventory with uppercase keys: " + upperCaseInventory);
        // Output: Inventory with uppercase keys: {APPLES=10, BANANAS=25, ORANGES=18, GRAPES=5}
        // 3. Calculate: Get the total number of fruits
        int totalFruits = inventory.values().stream().mapToInt(Integer::intValue).sum();
        System.out.println("Total fruits in inventory: " + totalFruits);
        // Output: Total fruits in inventory: 58
    }
}

Summary

If you want a... Use... Why?
Simple, fast, general-purpose dictionary HashMap It's the standard, most efficient choice for most use cases.
Dictionary that remembers insertion order LinkedHashMap It's a HashMap with a linked list to track order.
Dictionary with sorted keys TreeMap It automatically sorts keys for you.
A small, unchangeable dictionary Map.of() It's concise, safe, and easy to read for immutable data.
A thread-safe dictionary for concurrent access ConcurrentHashMap It's highly optimized for multi-threaded environments.
分享:
扫描分享到社交APP
上一篇
下一篇