CodeGym /Kurslar /JAVA 25 SELF /Dəyişdirilməyən kolleksiyalar: Collections.unmodifiable

Dəyişdirilməyən kolleksiyalar: Collections.unmodifiable

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. Kolleksiyaların dəyişkənliyi problemi

Java-da kolleksiyalar anbardakı malları xatırladır: hər kəs gəlib nəsə əlavə edə, çıxara, dəyişə bilər. Bəzən bu rahatdır, amma böyük proqramlarda bu, başağrısına çevrilir. Təsəvvür edin ki, sinfinizdən mal siyahısını kənara verdiniz, kimsə isə götürüb yarısını sildi. Və — daha da “əyəncəli” — çox axınlı proqramda bir axın elementlər əlavə edir, digəri isə oxuyur: nəticə gözlənilməz ola bilər, səhvlər isə tutması çətin (məsələn, ConcurrentModificationException).

Budur, niyə kolleksiyaların dəyişkənliyi xətaların mənbəyidir:

import java.util.*;

public class Inventory {
    private List<String> products = new ArrayList<>();

    public Inventory() {
        products.add("Çay");
        products.add("Qəhvə");
    }

    public List<String> getProducts() {
        // TEHLÜKƏLİ! Daxili siyahıya istinadı qaytarırıq
        return products;
    }
}
public class Main {
    public static void main(String[] args) {
        Inventory inv = new Inventory();
        List<String> external = inv.getProducts();
        external.remove("Çay"); // Hop! İndi inventarda çay yoxdur
        System.out.println(inv.getProducts()); // [Qəhvə]
    }
}

Finti gördünüzmü? Bir metod daxili kolleksiyanı qaytarır, digəri isə onu dəyişir. Beləcə, qorunmalı olan məlumatlar təsadüfən məhv edilə bilər.

2. Dəyişdirilməyən kolleksiyaların yaradılması: Collections.unmodifiable*

Belə anlaşılmazlıqlardan qaçmaq üçün Java effektiv mühafizə təklif edir: kolleksiyanı xüsusi örtüklərlə “dəyişdirilməyən” etmək olar — bunlar Collections sinfindədir:

  • Collections.unmodifiableList(list)
  • Collections.unmodifiableSet(set)
  • Collections.unmodifiableMap(map)

Bu necə işləyir? Əvvəl adi kolleksiya yaradırsınız, sonra onu “dəyişdirilməyən” örtüklə bürüyürsünüz:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<String> drinks = new ArrayList<>();
        drinks.add("Çay");
        drinks.add("Qəhvə");

        List<String> immutableDrinks = Collections.unmodifiableList(drinks);

        System.out.println(immutableDrinks); // [Çay, Qəhvə]

        // Element əlavə etməyə cəhd edək
        immutableDrinks.add("Kakao"); // Bam! UnsupportedOperationException
    }
}

Belə kolleksiyanı dəyişdirmə cəhdi UnsupportedOperationException istisnası atılmasına gətirib çıxarır. Bu, sanki qutunun üstünə böyük bir "TOXUNMAYIN!" stikerini yapışdırmısınız — kim nəsə əlavə etməyə və ya silməyə çalışsa, “əllərinə (və ya çağırış yığınının üstündə)” şillə dəyəcək.

Nümunə: daxili vəziyyəti qoruyuruq

Gəlin əvvəlki nümunədəki Inventory sinfini düzəldək:

import java.util.*;

public class Inventory {
    private List<String> products = new ArrayList<>();

    public Inventory() {
        products.add("Çay");
        products.add("Qəhvə");
    }

    public List<String> getProducts() {
        // İndi örtük qaytarırıq
        return Collections.unmodifiableList(products);
    }
}

İndi kimsə əldə etdiyi siyahını dəyişməyə çalışsa, istisna alacaq.

3. Dəyişdirilməyən kolleksiyaların davranışı: səthi qoruma

Vacib məqam: unmodifiableList və “qardaşları” yalnız ilkin kolleksiyanın üzərinə örtük qoyur. Onlar surət yaratmır — daxildəki (yəni “içində olan”) kolleksiyaya edilən istənilən dəyişikliklər örtükdə də görünəcək!

Nümayiş

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<String> drinks = new ArrayList<>();
        drinks.add("Çay");
        List<String> immutableDrinks = Collections.unmodifiableList(drinks);

        drinks.add("Qəhvə"); // Mənbə kolleksiyanı dəyişirik
        System.out.println(immutableDrinks); // [Çay, Qəhvə] — element göründü!
    }
}

Nəticə: örtük yalnız özündən dəyişikliklərə qarşı qoruyur. Kimsə mənbə kolleksiyanın istinadını saxlayırsa, onu yenə də dəyişə bilər.

4. Dərin dəyişdirilməzlik: miflər və reallıq

unmodifiable* örtükləri kolleksiyanı yalnız xaricdən dəyişdirilməz edir. Amma kolleksiya dəyişdirilə bilən obyektlər saxlayırsa, həmin obyektləri dəyişmək olar!

Nümunə

import java.util.*;

class Product {
    String name;
    Product(String name) {
        this.name = name;
    }
    public String toString() {
        return name;
    }
}

public class Main {
    public static void main(String[] args) {
        List<Product> products = new ArrayList<>();
        products.add(new Product("Çay"));
        List<Product> immutableProducts = Collections.unmodifiableList(products);

        // Kolleksiya daxilində obyektə dəyişiklik edirik
        immutableProducts.get(0).name = "Qəhvə";
        System.out.println(immutableProducts); // [Qəhvə]
    }
}

Nəticə:

  • Kolleksiya “dəyişdirilməzdir”, amma içindəki obyektlər — yox.
  • Tam (dərin) dəyişdirilməzlik üçün dəyişdirilməyən obyektlərdən istifadə edin (məsələn, String, Integer, record-siniflər) və ya öz siniflərinizi dəyişdirilməyən edin.

5. Dəyişdirilməyən kolleksiyalardan nə vaxt istifadə etməli

Daxili vəziyyəti qorumaq üçün

Əgər kolleksiya saxlayan sinif yazırsınızsa və onu kənara verirsinizsə, kimsənin məlumatlarınızı təsadüfən (və ya qəsdən) dəyişə bilməməsi üçün həmişə örtük qaytarın:

public List<String> getProducts() {
    return Collections.unmodifiableList(products);
}

Çox axınlı proqramlarda

Çox axınlı tətbiqlərdə dəyişən kolleksiyalar problemlərin mənbəyidir (race condition, ConcurrentModificationException və digər “həyat sevinc(ləri)”). Kolleksiya yaradıldıqdan sonra dəyişməməlidirsə — onu dəyişdirilməyən edin.

Laylar arasında məlumat ötürmək üçün

Kolleksiyanı proqramın bir layından digərinə ötürürsünüzsə (məsələn, DAO-dan servisa), təsadüfi dəyişikliklərdən qorunmaq üçün dəyişdirilməyən surəti və ya örtüyü ötürün.

6. Praktik nümunələr

Nümunə 1: tələbələr siyahısını qoruyuruq

import java.util.*;

public class Group {
    private final List<String> students = new ArrayList<>();

    public void addStudent(String name) {
        students.add(name);
    }

    public List<String> getStudents() {
        return Collections.unmodifiableList(students);
    }
}

İndi heç kim getStudents() vasitəsilə birbaşa tələbə əlavə edə və ya silə bilməz.

Nümunə 2: dəyişdirilməyən xəritə (Map)

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> grades = new HashMap<>();
        grades.put("Vasya", 5);
        grades.put("Masha", 4);

        Map<String, Integer> immutableGrades = Collections.unmodifiableMap(grades);

        // immutableGrades.put("Petya", 3); // UnsupportedOperationException
    }
}

7. Faydalı nüanslar

Müasir alternativlər: List.of, Set.of, Map.of

Java 9-da dəyişdirilməyən kolleksiyaları yaratmağın daha da rahat yolları meydana çıxdı:

List<String> drinks = List.of("Çay", "Qəhvə");
Set<String> fruits = Set.of("Alma", "Banan");
Map<String, Integer> ages = Map.of("Vasya", 20, "Masha", 21);
  • Bu kolleksiyalar dəyişdirilməzdir (istənilən dəyişiklik cəhdi — istisna).
  • Onların “mənbə” dəyişən kolleksiyası yoxdur ( Collections.unmodifiable* ilə fərqli olaraq).
  • null dəyərinə icazə vermirlər.

Həmçinin Java 10-dan etibarən List.copyOf, Set.copyOf, Map.copyOf kimi surət metodları var — verilən kolleksiyanın dəyişdirilməyən surətini yaradır.

Dəyişdirilməyən kolleksiyaları yaratma üsullarının müqayisəsi

Üsul Dərin dəyişdirilməzlik Mənbə kolleksiyanı dəyişmək mümkündürmü? null-a icazə verirmi? Java versiyası
Collections.unmodifiableList(list)
Yox Bəli Bəli 1.2
List.of(...), Set.of(...), Map.of(...)
Yox Yox (mənbə kolleksiya yoxdur) Yox 9+

8. Dəyişdirilməyən kolleksiyalarla işləyərkən tipik səhvlər

Səhv №1: Örtük yaradıldıqdan sonra mənbə kolleksiyanı dəyişmək. Siz unmodifiableList yaratdınız, sonra isə kimsə mənbə siyahını dəyişir. Örtük buna qarşı qorumur — dəyişikliklər örtüyün istifadə olunduğu bütün yerlərdə görünəcək.

Səhv №2: Dərin dəyişdirilməzliyi gözləmək. Bir çoxları düşünür ki, əgər kolleksiya dəyişdirilməzdirsə, deməli onun daxilindəki obyektləri də dəyişmək olmaz. Əslində yalnız struktur (əlavəetmə/silmə/kolleksiya vasitəsilə dəyişiklik) qorunur, obyektlərin məzmunu isə yox.

Səhv №3: Müasir fabriklərdə null dəyəri ilə dəyişdirilməyən kolleksiyalardan istifadə. List.of, Set.of, Map.of vasitəsilə yaradılan kolleksiyalar null-a icazə vermir. null əlavə etməyə və ya əldə etməyə cəhd istisnaya gətirib çıxaracaq.

Səhv №4: Dəyişən kolleksiyalara istinadların kənara ötürülməsi. Əgər daxili kolleksiyaya (örtüksüz) kənara istinad qaytarırsınızsa, məlumatlar üzərində nəzarəti itirirsiniz — bu, xətalara və invariantların “sızmasına” birbaşa yoldur.

Səhv №5: Dəyişənlik gözləyən koddakı dəyişdirilməyən kolleksiyalardan istifadə. Əgər xarici kod kolleksiyanı dəyişməyə (məsələn, element əlavə etməyə) cəhd edərsə, UnsupportedOperationException alacaq. İstehlakçıların məlumatların dəyişdirilməz olduğunu bildiyinə əmin olun.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Kitabxanada nadir kitabların qorunan siyahısının yaradılması 📚
Kitabxanada nadir kitabların qorunan siyahısının yaradılması 📚
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Dinamik restoran menyusu: reseptdəki dəyişikliklər qonaq versiyasına necə təsir edir 🍽️
Dinamik restoran menyusu: reseptdəki dəyişikliklər qonaq versiyasına necə təsir edir 🍽️
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION