Ma

Maps في Java

11 تمرينًا

نبذة عن Maps

Map هي بنية بيانات لتخزين أزواج المفتاح والقيمة. وهي مشابهة للقواميس في لغات البرمجة الأخرى. وتحدد واجهة Map العمليات التي يمكنك إجراؤها على Map.

HashMap

تحتوي Java على عدد من تطبيقات Map المختلفة. ويُعد HashMap من أكثرها استخدامًا.

// Make an instance
Map<String, Integer> fruitPrices = new HashMap<>();
Note

عند تعريف متغير من نوع Map، يُوصى بتعريف المتغير بنوع Map بدلًا من النوع المحدد، كما في المثال أعلاه. تسهّل هذه الممارسة تغيير تطبيق Map لاحقًا.

كما أن لـ HashMap مُنشئ نسخ.

// Make a copy of a map
Map<String, Integer> copy = new HashMap<>(fruitPrices);

أضف مدخلات إلى Map باستخدام put.

fruitPrices.put("apple", 100);
fruitPrices.put("pear", 80);
// => { "apple" => 100, "pear" => 80 }

يمكن ربط قيمة واحدة فقط بكل مفتاح. استدعاء put بالمفتاح نفسه سيحدّث قيمة ذلك المفتاح.

fruitPrices.put("pear", 40);
// => { "apple" => 100, "pear" => 40 }

استخدم get للحصول على قيمة مفتاح ما.

fruitPrices.get("apple"); // => 100

استخدم containsKey للتحقق مما إذا كانت Map تحتوي على مفتاح معين.

fruitPrices.containsKey("apple");   // => true
fruitPrices.containsKey("orange");  // => false

أزل المدخلات باستخدام remove.

fruitPrices.put("plum", 90);  // Add plum to map
fruitPrices.remove("plum");   // Removes plum from map

تُرجع طريقة size عدد المدخلات.

fruitPrices.size();  // Returns 2

يمكنك استخدام طريقتَي keySet أو values للحصول على المفاتيح أو القيم في Map على هيئة Set أو collection على الترتيب.

fruitPrices.keySet();  // Returns "apple" and "pear" in a set
fruitPrices.values();  // Returns 100 and 80, in a Collection

استخدام HashMap لـ hashCode و equals

يستخدم HashMap طريقتي hashCode و equals الخاصة بالكائن لتحديد مكان تخزين القيم وكيفية استرجاعها لمفتاح معين. ولهذا السبب، من المهم ألا تتغيّر القيم التي تُرجعانها بين التخزين والاسترجاع، وإلا فقد لا يتمكن HashMap من العثور على القيمة.

على سبيل المثال، لنفترض أن لدينا الصنف التالي الذي سيُستخدم مفتاحًا في Map:

public class Stock {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (Objects.equals(Stock.class, obj.getClass()) && obj instanceof Stock other) {
            return Objects.equals(name, other.name);
        }
        return false;
    }
}

تعتمد hashCode و equals على الحقل name، الذي يمكن تغييره عبر setName. قد يؤدي تغيير hashCode إلى نتائج مفاجئة:

Stock stock = new Stock();
stock.setName("Beanies");

Map<Stock, Integer> stockCount = new HashMap<>();
stockCount.put(stock, 80);

stockCount.get(stock); // Returns 80

Stock other = new Stock();
other.setName("Beanies");

stockCount.get(other); // Returns 80 because "other" and "stock" are equal

stock.setName("Choccies");
stockCount.get(stock); // Returns null because hashCode value has changed

stockCount.get(other);  // Also returns null because "other" and "stock" are not equal

stock.setName("Beanies");
stockCount.get(stock); // HashCode restored, so returns 80 again

stockCount.get(other); // Also returns 80 again because "other" and "stock" are back to equal

Map.of و Map.copyOf

من الطرق الشائعة الأخرى لإنشاء Map استخدام Map.of أو Map.ofEntries.

// Using Map.of
Map<String, Integer> temperatures = Map.of("Mon", 30, "Tue", 28, "Wed", 32);

// or using Map.ofEntries
Map<String, Integer> temperatures2 = Map.ofEntries(
    Map.entry("Mon", 30),
    Map.entry("Tue", 28),
    Map.entry("Wed", 32)
);

وعلى عكس HashMap، فإنها تملأ Map مسبقًا وتصبح للقراءة فقط بمجرد إنشائها. وتنشئ Map.copyOf نسخة للقراءة فقط من Map.

Map<String, Integer> readOnlyFruitPrices = Map.copyOf(fruitPrices);

يؤدي استدعاء طرق مثل put أو remove أو clear إلى ظهور UnsupportedOperationException.

تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة

تعلّم Maps

التدريب مقفل

افتح 1 تمرين إضافي لممارسة Maps