CodeGym /Kurslar /JAVA 25 SELF /Mutable vs Immutable kolleksiyalar: fərqlər və tətbiq sah...

Mutable vs Immutable kolleksiyalar: fərqlər və tətbiq sahələri

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

1. Giriş

Sadə dillə desək, mutable kolleksiya — yaradıldıqdan sonra onu dəyişmək mümkündür: elementləri əlavə etmək, silmək və dəyişmək olar. Immutable (dəyişməz) kolleksiya — yaradıldıqdan sonra dəyişdirilə bilməyən kolleksiyadır. Elə bərkimiş betona bənzəyir: baxmaq, toxunmaq olar, amma yeni fiqurlar “yoğurmaq” artıq mümkün deyil.

Mutable-kolleksiya — qələmlə dəftər kimidir: yazırsan, pozursan, yeni qeydlər əlavə edirsən. Immutable-kolleksiya — laminasiya etdiyiniz bir səhifə kimidir: artıq heç kim ora nə isə əlavə edə və ya silə bilməz.

Dəyişən (mutable) kolleksiyalara nümunələr

Java-da demək olar ki, bütün standart kolleksiyalar susmaya görə dəyişəndir. Məsələn, bu kimi siniflər:

  • ArrayList
  • LinkedList
  • HashSet
  • TreeSet
  • HashMap
  • LinkedHashMap
  • və daha bir çoxu

Nümunə: ArrayList

import java.util.*;

List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.set(1, "Charlie"); // Bob-u Charlie ilə əvəz etdik
names.remove("Alice");   // Alice-i sildik
System.out.println(names); // [Charlie]

Burada kolleksiya ilə istədiyimizi edə bilərik: əlavə etmək, silmək, elementlərin yerini dəyişmək. Bu, kolleksiya dinamik şəkildə qurulduqda, məsələn, fayldan oxuma və ya istifadəçi daxil etməsi zamanı əlverişlidir.

2. Dəyişməz (immutable) kolleksiyalara nümunələr

Java 9-da yaranan bu alətlərlə artıq tanışsınız, amma onlara hələ də öyrəşmək lazımdır:

  • List.of(...)
  • Set.of(...)
  • Map.of(...)
  • List.copyOf(collection)
  • Set.copyOf(collection)
  • Map.copyOf(map)

Nümunə: List.of

List<String> planets = List.of("Mercury", "Venus", "Earth", "Mars");
System.out.println(planets); // [Mercury, Venus, Earth, Mars]
planets.add("Jupiter"); // UnsupportedOperationException atacaq!

Kolleksiyanı dəyişdirməyə cəhd icra zamanı istisnaya gətirib çıxarır.

Nümunə: Collections.unmodifiableList

List<String> modifiable = new ArrayList<>(List.of("a", "b"));
List<String> unmodifiable = Collections.unmodifiableList(modifiable);
unmodifiable.add("c"); // UnsupportedOperationException!

Amma burada incə bir məqam var: əgər ilkin kolleksiyanı dəyişsəniz, örtük də dəyişəcək!

modifiable.add("c");
System.out.println(unmodifiable); // [a, b, c] — element əlavə olundu!

3. Mutable və immutable kolleksiyalar arasındakı əsas fərqlər

Xüsusiyyət Mutable (dəyişən) Immutable (dəyişməz)
Element əlavə etmək mümkündürmü? Bəli Xeyr
Elementi silmək mümkündürmü? Bəli Xeyr
Elementi dəyişmək mümkündürmü? Bəli (məsələn, set) Xeyr
Çoxaxınlı təhlükəsizlik Xeyr (susmaya görə) Bəli (daxili vəziyyət yoxdur — dəyişdiriləsi heç nə yoxdur)
null əlavə etmək olar? Bəli (adətən) Xeyr (Java 9+ fabrik metodlarında)
Reallaşdırma ArrayList, HashSet və s. List.of, Set.of, Map.of, copyOf

4. Dəyişməz kolleksiyalar ümumiyyətlə nə üçün lazımdır?

Dərhal sual yaranır: əgər dəyişən kolleksiyalar bu qədər çevikdirsə, niyə dəyişməzlərə ehtiyac var? Səbəblər çoxdur və hamısı təhlükəsizlik, oxunaqlıq və kodun proqnozlaşdırıla bilməsi ilə bağlıdır.

Təhlükəsizlik və səhvlərdən qorunma

Kolleksiyanı xaricə (məsələn, metoddən və ya sinifdən) verdikdə, heç kimin onun məzmununu təsadüfən dəyişməyəcəyinə əmin olmaq istəyirsiniz. Bu xüsusilə vacibdir, əgər kolleksiya ilkinləşdirmədən sonra dəyişməməli olan “vacib” məlumatları ehtiva edirsə.

Nümunə:

public class Team {
    private final List<String> players;

    public Team(List<String> players) {
        // Heç kim heyəti dəyişə bilməsin deyə dəyişməz nüsxə yaradırıq
        this.players = List.copyOf(players);
    }

    public List<String> getPlayers() {
        return players;
    }
}

Artıq oyunçular siyahısını alan istənilən kod ora “dostunu” əlavə edə bilməyəcək.

Çoxaxınlı təhlükəsizlik

Dəyişən kolleksiyalar eyni vaxtda bir neçə axından giriş üçün təhlükəsiz deyil. Dəyişməz kolleksiyalar isə əksinə, axınlar arasında sərbəst ötürülə bilər — heç kim onları korlaya bilməz.

Sazlamanı asanlaşdırmaq

Kolleksiya dəyişmirsə, həmişə orada nə olduğunu bilirsiniz. Kimsə onu kodun başqa yerində “səssizcə” dəyişib-deyişməməsindən narahat olmağa ehtiyac yoxdur.

Başqa kolleksiyalarda açar və ya dəyər kimi istifadə

Dəyişməz obyektlər Map-də açar, Set-də element kimi istifadə üçün ideal namizəddir. Obyekt əlavə edildikdən sonra dəyişə bilirsə, ona çıxışı itirmək riskiniz var (bax: hashCodeequals).

5. Dəyişən kolleksiyaları nə vaxt istifadə etmək daha yaxşıdır?

Dəyişən kolleksiyalar aşağıdakı hallarda əlverişlidir:

  • Kolleksiya mərhələli şəkildə, dövrdə və ya müxtəlif mənbələrdən qurulursa.
  • Tez-tez dəyişikliklər lazımdırsa: əlavə etmə, silmə, çeşidləmə.
  • Kolleksiya daxili istifadə üçündür və “çöldən” heç kim onu poza bilməyəcək.

Nümunə: Siyahının qurulması

List<String> shoppingList = new ArrayList<>();
shoppingList.add("Süd");
shoppingList.add("Çörək");
shoppingList.add("Almalar");
// Qurulduqdan sonra — dəyişməz versiyasını yaratmaq olar
List<String> finalList = List.copyOf(shoppingList);

6. Dəyişməz kolleksiyaları nə vaxt istifadə etmək daha yaxşıdır?

  • Sabit məlumatları saxlamaq üçün (məsələn, həftənin günləri siyahısı).
  • Tətbiqin qatları arasında kolleksiyaları ötürmək üçün (məsələn, DAO-dan servisə).
  • Kolleksiyaları metodlardan qaytararkən onları dəyişikliklərdən qorumaq üçün.
  • Çoxaxınlı ssenarilərdə təhlükəsizlik vacib olduqda.

Nümunə: Sabit məlumatlar

public static final List<String> WEEKDAYS = List.of(
    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"
);

Nümunə: Çölə ötürmə

public List<String> getReadOnlyNames() {
    return List.copyOf(names); // heç kim siyahını dəyişə bilməyəcək
}

7. Xüsusiyyətlər və gizli tələlər

Dəyişməzlik ≠ Çoxaxınlı təhlükəsizlik

Dəyişməz kolleksiya dəyişikliklərdən qorunur, amma bu, çoxaxınlı mühitdə digər problemlərdən qorunduğu anlamına gəlmir (məsələn, kolleksiyanın elementləri dəyişən obyektlərdirsə).

List<List<String>> listOfLists = List.of(new ArrayList<>());
listOfLists.get(0).add("Oops!"); // Daxili siyahını dəyişmək olar!

Örtüklər vs nüsxələr

Daha əvvəl müzakirə etdiyimiz kimi, Collections.unmodifiableList — sadəcə örtükdür və əgər ilkin kolleksiya dəyişdirilsə, örtük də dəyişəcək. List.copyOf isə həqiqi, müstəqil nüsxə yaradır.

List<String> base = new ArrayList<>(List.of("a", "b"));
List<String> wrap = Collections.unmodifiableList(base);
List<String> copy = List.copyOf(base);

base.add("c");
System.out.println(wrap); // [a, b, c] — dəyişdi!
System.out.println(copy); // [a, b] — əvvəlki kimi qaldı!

NullPointerException

Fabrik metodları (List.of, Set.of, Map.of) null əlavə etməyə imkan vermir:

List<String> bad = List.of("a", null); // Artıq yaradılma zamanı NullPointerException atacaq!

8. Yanaşmaların müqayisəsi: üstünlüklər və çatışmazlıqlar

Dəyişən kolleksiyalar

Dəyişən kolleksiyaların əsas üstünlüyü — çevikliyidir. Elementləri “yolda” əlavə edib silə, proqram məntiqi inkişaf etdikcə kolleksiyanı yenidən qura bilərsiniz. Bu yanaşma xüsusilə müvəqqəti strukturu tez toplamaq və ya nəyisə dinamik dəyişmək lazım olanda rahatdır.

Amma rahatlığın da qiyməti var. Dəyişən kolleksiya həmişə təsadüfi müdaxilə riski daşıyır: koddakı kimsə məlumatları bilmədən dəyişə bilər və bu, izlənməsi çətin xətalara gətirib çıxarar. Çoxaxınlı proqramlarda vəziyyət daha da pisdir — paralel dəyişikliklər asanlıqla yarış şəraitinə (race conditions) və gözlənilməz nasazlıqlara səbəb olur. Belə məlumatların həyat dövrünə nəzarət də çətindir: kim və nə zaman kolleksiyanı dəyişə bilər — bunu daim yadda saxlamaq lazımdır.

Dəyişməz kolleksiyalar

Dəyişməz kolleksiyalarla işləmək daha rahatdır. Dəqiq bilirsiniz ki, onları heç kim “arxadan” dəyişməyəcək. Bu, kodu daha təhlükəsiz edir, onu sazlamaq və test etmək asanlaşır, həmçinin bu kolleksiyaları əlavə bloklamalara ehtiyac olmadan axınlar arasında ötürmək rahatdır.

Eks tərəfi odur ki, bəzən məhsuldarlıqdan güzəştə getmək lazım gəlir. Yeni element əlavə etmək üçün çox vaxt kolleksiyanın yeni nüsxəsini yaratmaq lazım olur ki, bu da əlavə yaddaş və vaxt xərcləri deməkdir. Bundan başqa, böyük və mürəkkəb strukturları dərhal dəyişməz formada yığmaq bəzən əlverişli olmur. Adətən onlar müvəqqəti dəyişən kolleksiyada qurulur, hər şey hazır olanda isə “dondurulur”.

9. Tipik səhvlər

Səhv № 1: Dəyişən kolleksiyanın çölə qaytarılması. Metoddan adi ArrayList qaytarırsınızsa, istənilən xarici kod elementləri əlavə edib silə bilər. Bu isə izləması çox çətin olan xətalara səbəb ola bilər.

Səhv № 2: Nüsxə əvəzinə örtükdən istifadə. Əgər Collections.unmodifiableList istifadə edirsinizsə, amma ilkin kolleksiya haradasa dəyişdirilirsə, “dəyişməzlik” — illüziyadır.

Səhv № 3: Immutable kolleksiyalar daxilində dəyişən obyektlər. Kolleksiyanın özü dəyişməz olsa belə, onun elementləri dəyişən ola bilər. Bu, vəziyyətin gözlənilməz dəyişməsinə səbəb ola bilər.

Səhv № 4: Fabrik metodları ilə yaradılmış kolleksiyaya null əlavə etməyə cəhd. Köhnə kolleksiyalardan fərqli olaraq, yeni fabrik metodları null əlavə etməyə imkan vermir — NullPointerException alacaqsınız.

Səhv № 5: Konkret implementasiyanı gözləmək. List.of və ya Set.of vasitəsilə yaradılan kolleksiyalar implementasiya tipini zəmanət vermir (bu, mütləq ArrayList və ya HashSet deyil). Buna arxayın olmayın.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Heyvan inventarı: canlı siyahı yoxsa statik anlıq görüntü? 🐾
Heyvan inventarı: canlı siyahı yoxsa statik anlıq görüntü? 🐾
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Pleylistlər: siyahı dəyişməzdir, amma mahnılar içində dəyişir 🎶
Pleylistlər: siyahı dəyişməzdir, amma mahnılar içində dəyişir 🎶
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION