1. Giriş
Həyatda tez-tez elə situasiyalarla qarşılaşırıq ki, hər unikal “açar”a hansısa “dəyər” uyğunlaşdırmaq lazımdır. Telefon kitabçası telefon nömrəsini və şəxsin adını saxlayır, lüğət sözü onun tərcüməsi ilə bağlayır, qiymət cədvəlində isə hər tələbənin öz adı və uyğun balı olur.
Java-da bu cür vəzifələr üçün Map interfeysi var. Bu, “açar — dəyər” (key-value pair) cütlərini saxlayan kolleksiyadır.
Map-in əsas xüsusiyyətləri:
- Hər açar unikal olur (dublikatlara icazə verilmir).
- Bir açara yalnız bir dəyər uyğun gələ bilər.
- Dəyərlər təkrarlana bilər.
Analogiyanı təsəvvür edək. Əgər siyahı (List) — yeməkxanadakı növbə kimidirsə (hər kəs öz mövqeyindədir, nömrə ilə müraciət etmək olur), xəritə (Map) — gözləri olan şkaf kimidir: hər gözün bir nömrəsi (açar) var və orada hansısa “özünə məxsus” şey (dəyər) durur.
Map interfeysi: əsas əməliyyatlar
Map interfeysi açar–dəyər cütləri ilə işləmək üçün əsas metodları elan edir:
| Metod | Təsvir |
|---|---|
|
Açar üzrə dəyəri əlavə etmək/əvəzləmək |
|
Açar üzrə dəyəri almaq |
|
Açar üzrə cütlüyü silmək |
|
Belə açarın olub-olmadığını yoxlamaq |
|
Belə dəyərin olub-olmadığını yoxlamaq |
|
Xəritədəki cütlərin sayı |
|
Map boşdurmu — yoxlamaq |
|
Bütün cütləri silmək |
K və V tipləri generik parametrlərdir: K (Key) — açarın tipi, V (Value) — dəyərin tipidir.
3. HashMap sinfi: açar üzrə sürətli giriş
HashMap nədir?
HashMap — Map interfeysinin ən məşhur reallaşdırmasıdır. O, dəyərlərə açar üzrə sürətli giriş təmin edir.
Vacib: HashMap elementlərin saxlanma ardıcıllığına zəmanət vermir! Açarları müəyyən ardıcıllıqla əlavə etsəniz belə, iterasiya zamanı fərqli sırada gələ bilərlər.
HashMap necə yaradılır?
import java.util.HashMap;
import java.util.Map;
public class Example {
public static void main(String[] args) {
// Xəritə yaradırıq: açar — String, dəyər — Integer
Map<String, Integer> ages = new HashMap<>();
// Elementlər əlavə edirik
ages.put("Vasya", 25);
ages.put("Petya", 30);
ages.put("Masha", 22);
// Açar üzrə dəyəri alırıq
int vasyaAge = ages.get("Vasya");
System.out.println("Vasyanın yaşı: " + vasyaAge); // 25
// Açarın olub-olmadığını yoxlayırıq
if (ages.containsKey("Masha")) {
System.out.println("Masha siyahıda var!");
}
// Elementi silirik
ages.remove("Petya");
// Bütün açar–dəyər cütlərini keçiririk
for (String name : ages.keySet()) {
System.out.println(name + ": " + ages.get(name));
}
}
}
Çıxış:
Vasyanın yaşı: 25
Masha siyahıda var!
Vasya: 25
Masha: 22
HashMap-ın xüsusiyyətləri
Əsas yadda saxlamaq lazım olan: HashMap-də açarlar həmişə unikaldır. Əgər mövcud açarla yeni element qoysanız, köhnə dəyər yenisi ilə əvəz olunacaq.
Dəyərlər təkrarlana bilər: bir neçə fərqli açar eyni dəyərə işarə edə bilər.
Və daha bir vacib məqam — elementlərin ardıcıllığı. HashMap əlavəetmə ardıcıllığına baxmır. Çap zamanı yazılar qarışıq ola bilər — bu, normal davranışdır.
4. TreeMap sinfi: açar üzrə sıralama
HashMap-dan fərqli olaraq, TreeMap elementləri açara görə sıralanmış şəkildə saxlayır.
TreeMap-i nə vaxt istifadə etməli?
Elementlərin açarlar üzrə artan (və ya azalan) qaydada getməsi vacib olduqda. Məsələn, telefon kitabçasını əlifba ilə çap etmək istəyirsinizsə.
Nümunə:
import java.util.Map;
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
Map<String, String> phoneBook = new TreeMap<>();
phoneBook.put("Vasya", "+1-900-123-45-67");
phoneBook.put("Masha", "+1-900-555-55-55");
phoneBook.put("Petya", "+1-900-222-33-44");
for (String name : phoneBook.keySet()) {
System.out.println(name + ": " + phoneBook.get(name));
}
}
}
Çıxış:
Masha: +1-900-555-55-55
Petya: +1-900-222-33-44
Vasya: +1-900-123-45-67
Nəzərə alın: açarlar əlifbaya görə sıralanıb.
5. Map ilə əsas əməliyyatlar
Elementlərin əlavə edilməsi və əvəzlənməsi
Map<String, Integer> scores = new HashMap<>();
scores.put("Anna", 90);
scores.put("Ivan", 85);
scores.put("Anna", 95); // "Anna" üçün dəyəri yenidən yazacaq
Dəyərin alınması
Integer annaScore = scores.get("Anna"); // 95
Integer unknown = scores.get("Vasya"); // əgər belə açar yoxdursa, null
Açarın və ya dəyərin mövcudluğunu yoxlama
scores.containsKey("Ivan"); // true
scores.containsValue(85); // true
Cütün açar üzrə silinməsi
scores.remove("Ivan");
Xəritənin ölçüsü və təmizləmə
int size = scores.size();
scores.clear(); // Bütün elementləri silir
5. Map elementlərinin üzərindən keçid
Map — siyahı deyil, burada indekslər yoxdur. Amma keçmək olar:
Açarlar üzrə:
for (String key : scores.keySet()) {
System.out.println("Açar: " + key + ", Dəyər: " + scores.get(key));
}
Dəyərlər üzrə:
for (Integer value : scores.values()) {
System.out.println("Dəyər: " + value);
}
Açar–dəyər cütləri üzrə (ən yaxşı üsul):
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " => " + value);
}
HashMap-i nə vaxt, TreeMap-i nə vaxt istifadə etməli?
HashMap — “default” üçün universal seçimdir. Əgər açarların ardıcıllığı vacib deyilsə və əsas məqsəd əməliyyatların sürətidirsə, demək olar ki, həmişə onu seçirlər.
TreeMap isə ardıcıllıq lazımdırsa, faydalıdır. O, açarları avtomatik olaraq sıralı saxlayır və minimal/maksimal açarı tez tapmağa və ya diapazonlarla işləməyə imkan verir.
Nəticə: halların 90 %‑ində HashMap götürürük. Məlumatlar dərhal “sıralı” olmalıdırsa, TreeMap istifadə edirik.
6. Map-dan istifadə nümunələri
Nümunə 1: Telefon kitabçası
Map<String, String> phoneBook = new HashMap<>();
phoneBook.put("Katya", "+1-999-111-22-33");
phoneBook.put("Oleg", "+1-999-222-33-44");
phoneBook.put("Katya", "+1-999-555-66-77"); // Katyanın köhnə nömrəsi yenisi ilə əvəz olunacaq
for (Map.Entry<String, String> entry : phoneBook.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Çıxış:
Oleg: +1-999-222-33-44
Katya: +1-999-555-66-77
Nümunə 2: Sözlərin sayının hesablanması
Tutaq ki, bizdə sözlərdən ibarət siyahı var və hər sözün neçə dəfə təkrarlandığını bilmək istəyirik:
import java.util.*;
public class WordCount {
public static void main(String[] args) {
List<String> words = Arrays.asList("alma", "banan", "alma", "armud", "banan", "alma");
Map<String, Integer> counts = new HashMap<>();
for (String word : words) {
int oldCount = counts.getOrDefault(word, 0); // əgər açar yoxdursa — 0
counts.put(word, oldCount + 1);
}
System.out.println(counts); // {armud=1, alma=3, banan=2}
}
}
7. Map ilə işləyərkən tipik səhvlər
Səhv №1: Açarlarla dəyərləri qarışdırmaq. Yeni başlayanlar tez-tez dəyəri siyahıdakı kimi indekslə almağa çalışır və ya açarların unikal olmalı olduğunu unudurlar. Map-də indeks yoxdur — yalnız açarlar var.
Səhv №2: null açar və dəyərlərdən istifadə. HashMap-da null açara icazə verilir, amma TreeMap-də — yox ( NullPointerException olacaq). Hər iki reallaşdırmada dəyərlər null ola bilər, amma bu nadir hallarda faydalıdır.
Səhv №3: HashMap-da elementlərin ardıcıllığını gözləmək. HashMap heç bir ardıcıllığa zəmanət vermir. Ardıcıllıq lazımdırsa — LinkedHashMap (əlavəetmə ardıcıllığını saxlayır) və ya TreeMap (açar üzrə sıralayır) istifadə edin.
Səhv №4: İterasiya zamanı Map-ı dəyişmək. Əgər dövrdə Map üzərindən keçərək eyni vaxtda elementlər əlavə edib/silirsinizsə — ConcurrentModificationException yarana bilər. Bu cür tapşırıqlar üçün remove() metodu olan iterator və ya xüsusi kolleksiyalardan istifadə edin.
Səhv №5: Açar və dəyərləri == ilə, equals əvəzinə müqayisə etmək. Map açarları (və dəyərləri) müqayisə etmək üçün equals metodundan istifadə edir. Öz açar siniflərinizi yaradırsınızsa, mütləq equals və hashCode-u yenidən təyin edin.
GO TO FULL VERSION