Kolekcijų karkasas

M.Gžegoževskis ... 2021-10-01 Java
  • Programavimas
  • Java
About 6 min

# Kolekcijų karkasas arba duomenų struktūros

Kolekcija - tai duomenų saugykla (panaudojimo prasme). Kolekcija – tai atitinkamą kolekcijos interfeisą (sąsają) įdiegiančios klasės objektas (programavimo prasme). Kolekcija – tai dinaminis masyvas: gali "augti" tiek, kiek reikia (apimtis neribojama); gali mažėti iki tuščios. Kolekcija gali talpinti įvairių tipų objektus (tik objektus!). Pagal ideologiją panašu C++ naudojamą Standard Template Library (STL).

# Kolekcijų privalumai

  • Supaprastina programavimo procesą, kadangi yra pateikiamos dažniausiai naudojamos duomenų struktūros ir algoritmai, kurių nereikia realizuoti atskirai.
  • Paspartina naudojamų duomenų struktūrų ir algoritmų darbą, kadangi sukurtas karkasas yra gerai suprojektuotas.
  • Suteikia sąveiką tarp nesusijusių API’s, sukuriant bendrą kalbą kolekcijoms perduoti pirmyn ir atgal.

Kolekcijų karkaso klasių hierarchija (žr. 1.8 pav.) nuo JDK 1.5 kadangi buvo perrašytas naudojant generics tipus, taip apsaugant nuo pagrindinės problemos ClassCastException. 1.8 paveikslėlyje pateiktas supaprastintoss kolekcijų karkaso hierarchijos vaizdas išėmus tarpines abstrakčias klases, kurias galima surasti oficialiojoje dokumentacijoje. Programuotojui užtenka žinoti kokios duomenų struktūros ir kokie interfeisai sudaro šį kolekcijų karkasą. Detalesnį sąrašą peržiūrėti reikia tuo atveju jeigu norime sukurti savo asmenines kolekcijas.

Collections interfeisas Java.png

1.8 pav. Kolekcijų karkasas

Kolekcijų karkasas neturi kai kurių klasių pavyzdžiui duomenų struktūros map šios duomenų struktūros interfeisas yra sukurtas atskirai nuo kolekcijų karkaso (žr. 1.9 pav.).

Map interfeisas Java.png

1.9 pav. Map interfeiso hierarchija

Ši duomenų struktūra sudaryta iš rakto (angl. key) - K ir reikšmės (angl. value) - V. Tai nusako rakto ir reikšmės saugojimą atmintyje pagal. kurių porą yra patogu užrašyti duomenis turinčius didelius teksto fragmentus. Turint tokią duomenų struktūrą yra daug paprasčiau atlikti paiešką pagal raktinį žodį. Realaus gyvenimo pavyzdys tai facebook #-hashtag pagal, kuriuos yra surandami ir atvaizduojami visi paskelbti straipsniai su paminėtu raktiniu žodžiu.

# Comparable ir Comparator interfeisų skirtumas ir paskirtis.

Kadangi kolekcijų karkasas yra objektų rinkiniai su kuriais įprastai yra naudojami pagrindiniai metodai, kurie yra aprašyti klasėse: Arrays arba Collections, taip pat galima turėti ir filtrus norint išrinkti informaciją iš esamų rinkinių. Skirtumas tarp šių dviejų interfeisų:

  • Comparable interfeisas yra skirtas duomenų rūšiavimui viena išdėstymo tvarka, o Comparator interfeisas gali būti naudojamas duomenų rinkinius rūšiuoti keliomis skirtingomis kryptimis.
  • Naudoti Comparable interfeisą reikia jį reikia įgyvendinti, kur naudojant Comparator nereikia atlikti jokių pakeitimų.
  • Comparable interfeisas yra įgyvendintas java.lang klasių kataloge, Comparator yra kitame java.util kataloge.
  • Nereikia jokio kodo pakeitimų kliento kodo pusėje naudojant Comparable Arrays.sort() arba Collections.sort() metodus, kurie automatiškai naudoja compareTo() metodus prisitaikant prie tos klasės tipo. Naudojant Comparator klientas privalo aprašyti metodą compare().

Pavyzdžiui turime įprastą sandėlį, kuriame yra sudėtos įvairios dėžės skirtingų tipų/rūšių: Auksinė, Celofaninė, Sidabrinė, Medinė ir kt. Užduotis surūšiuoti sandėlyje esančias dėžes pagal svorį didėjimo tvarka. Tada programiškai reikėtų aprašyti taip: sukurti kolekciją java ArrayList<Deze>, joje patalpinti dėžės tipo objektus, aprašyti metodą compare() pagal kokį filtrą rūšiuosime dėžes, šiam tikslui pasiekti naudosime Comparator interfeisą kaip anoniminę klasę:


class Deze {
  private String tipas;
  private int svoris;
  public Deze(String tipas, int svoris) {
    this.tipas = tipas;
    this.svoris = svoris;
  }
  public String getTipas() {
    return tipas;
  }
  public int getSvoris() {
    return svoris;
  }
  @Override
  public String toString() {
    return "Deze{" +
        "tipas='" + tipas + '\'' +
        ", svoris=" + svoris +
        '}';
  }
}
public class Main {
  public static void main(String[] args) {
    List<Deze> sandelys = new ArrayList<>();
    sandelys.add(new Deze("Auksinė", 111));
    sandelys.add(new Deze("Stiklinė", 599));
    sandelys.add(new Deze("Plastikinė", 33));
    sandelys.add(new Deze("Celofaninė", 11));
    sandelys.add(new Deze("Medinė", 68));
    // Comparator kaip anoniminė klasė iki 1.7 JDK be lambda išraiškų
    Comparator<Deze> pagalSvori = new Comparator<Deze>() {
      @Override
      public int compare(Deze o1, Deze o2) {
        return o1.getSvoris() - o2.getSvoris();
      }
    };
    // Comparator įvedūs lambda išraiškas nuo 1.8 analogiškai pagal didėjimo tvarką rūšiuoja elementus
    Comparator<Deze> pagalSvori2Budas = (o1, o2) -> o1.getSvoris() - o2.getSvoris();
    // Comparator įvestas naujas metodas nuo 1.8 JDK supaprastėjo užrašymas
    Comparator<Deze> pagalSvori3Budas = Comparator.comparingInt(Deze::getSvoris);

    // 2 būdai kaip rikiuoti sandelyje esančias dėžes pagal numatytą tvarką šiuo atveju didėjimo.
    // Comparator objektas yra paprasčiausias filtras
    sandelys.sort(pagalSvori);
    //analogiškai Collections.sort(sandelys, pagalSvori);
    System.out.println("Pagal dėžės svorį didėjimo tvarka:");
    for (Deze deze: sandelys)
      System.out.println(deze);

    // Filtras skirtas surikiuoti elementus pagal dėžės tipą didėjimo tvarka
    Comparator<Deze> dezesTipas = new Comparator<Deze>() {
      @Override
      public int compare(Deze e1, Deze e2) {
        return e1.getTipas().compareTo(e2.getTipas());
      }
    };
    sandelys.sort(dezesTipas);
    System.out.println("Pagal dėžės tipą didėjimo tvarka:");
    for (Deze deze: sandelys)
      System.out.println(deze);
  }
}

//Įvykdžius programinį kodą į ekraną išves dėžės svorį didėjimo tvarka:

Deze(tipas='Celofaninė', svoris=11);
Deze(tipas='Plastikinė', svoris=33);
Deze(tipas='Medinė', svoris=68);
Deze(tipas='Auksinė', svoris=111);
Deze(tipas='Stiklinė', svoris=599);

//Pastaba! compare() metodą galima aprašyti ir pagal individualų poreikį. Elementų tvarka taip pat gali būti didėjimo ar mažėjimo vėliau apžvelgsime kaip parašyti rūšiavima pagal 2 ir daugiau parametrų.Kaip veikia rūšiavimas labai paprastai jeigu rezultatas o1.getSvoris() - o2.getSvoris() yra lygus:

// 0 - reiškia jog abu elementai yra lygūs.
// 1 ir daugiau - reiškia jog elementas yra didesnis už lyginamą elementą.
// -1 ir mažiau - reiškia jog elementas yra mažesnis už lyginimą elemetą.

//Norint surikiuoti elementus pagal kitą parametrą t.y. objektą naudosime tą patį prieš tai pateiktą pavyzdį, kuriame buvo rikiuojamos dėžės esančios sandėlyje pagal svorį. Šį kartą tikiuosime pagal tos dėžės tipą. Kadangi parametras yra nuorodos (angl. reference) tipo return dalyje naudosime compareTo() metodą skirtą palyginti objektus tarpusavyje pagal dėžės tipą. 
// Įvykdžius programinį kodą su naujai parašytų filtru dezesTipas į ekraną bus išvestas dėžės tipas didėjimo tvarka:

Deze(tipas='Auksinė', svoris=111);
Deze(tipas='Celofaninė', svoris=11);
Deze(tipas='Medinė', svoris=68);
Deze(tipas='Plastikinė', svoris=33);
Deze(tipas='Stiklinė', svoris=599);

//Laikantis tvarkingo kodo rašymo norint turėtį filtrus pagal paskirtį reikėtų duotą filtrą aprašyti toje klasėje, kurios tipo duomenis ir rūšiuosime. 
//Pavyzdžiui turime situaciją realiame gyvenime turime sąrašus sudarytus iš asmenų su papildoma informacija. Programiškai reikia sukurti objektą Asmuo ir Main metodą, kuriame patikrinsime realizuotą programą. 
// Tikslas surūšiuoti asmenis pagal vardą, atlyginimą arba pagal abu laukus pagal atlyginimą ir pagal vardą.

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

class Asmuo{
  private String vardas;
  private double atlyginimas;

  public Asmuo(String vardas, double atlyginimas) {
    this.vardas = vardas;
    this.atlyginimas = atlyginimas;
  }

  public String getVardas() {
    return vardas;
  }

  public double getAtlyginimas() {
    return atlyginimas;
  }
  // Aprašomi įvairūs filtrai susiiję su Asmens klase nuo JDK 1.7
  public static Comparator<Asmuo> asmuoPagalVarda = new Comparator<Asmuo>() {
    @Override
    public int compare(Asmuo o1, Asmuo o2) {
      return o1.getVardas().compareTo(o2.getVardas());
    }
  };
  public static Comparator<Asmuo> asmuoPagalAtlyginima = new Comparator<Asmuo>() {
    @Override
    public int compare(Asmuo o1, Asmuo o2) {
      return (int)o1.getAtlyginimas() - (int)o2.getAtlyginimas();
    }
  };
  public static Comparator<Asmuo> pagalAtlyginimaIrVarda = new Comparator<Asmuo>() {
    @Override
    public int compare(Asmuo o1, Asmuo o2) {
      int flag = (int)o1.getAtlyginimas() - (int)o2.getAtlyginimas();
      if(flag == 0)
        flag = o1.getVardas().compareTo(o2.getVardas());
      return flag; // flag tai laikinasis kintamasis pagal, kurį pritaikome antrą filtrą pagal vardą
    }
  };
  @Override
  public String toString() {
    return "Asmuo{" +
        "vardas='" + vardas + '\'' +
        ", atlyginimas=" + atlyginimas +
        '}';
  }
}
public class Main {
  public static void main(String[] args) {
    List<Asmuo> asmenys = new ArrayList<>();
    asmenys.add(new Asmuo("Darius", 2200));
    asmenys.add(new Asmuo("Marius", 1500));
    asmenys.add(new Asmuo("Andrius", 1888));
    asmenys.add(new Asmuo("Tomas", 1500));
    asmenys.add(new Asmuo("Arnas", 1500));
    asmenys.add(new Asmuo("Tomas", 4444));

    // Sukurto filtro naudojant Comparator interfeisą filtras pagal asmens vardą
    asmenys.sort(Asmuo.asmuoPagalVarda);
    System.out.println("Asmuo pagal vardą didėjimo tvarka:");
    for (Asmuo asmuo : asmenys) {
      System.out.println(asmuo);
    }
    // Sukurto filtro naudojant Comparator interfeisą filtras pagal asmens atlyginimą
    asmenys.sort(Asmuo.asmuoPagalAtlyginima);
    System.out.println("Asmuo pagal atlyginimą didėjimo tvarka:");
    for (Asmuo asmuo : asmenys) {
      System.out.println(asmuo);
    }
    // Sukurto filtro naudojant Comparator interfeisą filtras pagal asmens atlyginimą ir pagal vardą
    asmenys.sort(Asmuo.pagalAtlyginimaIrVarda);
    System.out.println("Asmuo pagal atlyginimą ir pagal vardą didėjimo tvarka:");
    for (Asmuo asmuo : asmenys) {
      System.out.println(asmuo);
    }
  }
}

// REZULTATAS BUS IŠVESTAS EKRANĄ
Asmuo pagal vardą didėjimo tvarka:
Asmuo(vardas='Andrius', atlyginimas=1888.0);
Asmuo(vardas='Arnas', atlyginimas=1500.0);
Asmuo(vardas='Darius', atlyginimas=2200.0);
Asmuo(vardas='Marius', atlyginimas=1500.0);
Asmuo(vardas='Tomas', atlyginimas=1500.0);
Asmuo(vardas='Tomas', atlyginimas=4444.0);

Asmuo pagal atlyginimą didėjimo tvarka:
Asmuo(vardas='Arnas', atlyginimas=1500.0);
Asmuo(vardas='Marius', atlyginimas=1500.0);
Asmuo(vardas='Tomas', atlyginimas=1500.0);
Asmuo(vardas='Andrius', atlyginimas=1888.0);
Asmuo(vardas='Darius', atlyginimas=2200.0);
Asmuo(vardas='Tomas', atlyginimas=4444.0);

Asmuo pagal atlyginimą ir pagal vardą didėjimo tvarka:
Asmuo(vardas='Arnas', atlyginimas=1500.0);
Asmuo(vardas='Marius', atlyginimas=1500.0);
Asmuo(vardas='Tomas', atlyginimas=1500.0);
Asmuo(vardas='Andrius', atlyginimas=1888.0);
Asmuo(vardas='Darius', atlyginimas=2200.0);
Asmuo(vardas='Tomas', atlyginimas=4444.0);

// Comparable interfeisas yra ribotas jį galima rasti java.lang pakete. Kadangi vartotojas privalo aprašyti metodą compareTo() šiame metode galima aprašyti tik vienos sekos rūšiavimą pagal kažkurį objekto parametrą. 
// Žemiau bus pateiktas programinio kodas, kuriame bus rūšiuojami Studentai pagal amžių.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Studentas implements Comparable<Studentas>{

  private String vardas;
  private int amzius;

  public Studentas(String vardas, int amzius) {
    this.vardas = vardas;
    this.amzius = amzius;
  }
  public String getVardas() {
    return vardas;
  }

  public int getAmzius() {
    return amzius;
  }
  // Aprašomas filtras rūšiavimui pagal amžių
  @Override
  public int compareTo(Studentas o) {
    if(amzius == o.amzius){
      return 0;
    }
    else if(amzius < o.amzius){
      return 1;
    }else{
      return -1;
    }
  }
  @Override
  public String toString() {
    return "Studentas{" +
        "vardas='" + vardas + '\'' +
        ", amzius='" + amzius + '\'' +
        '}';
  }
}
public class Main {
  public static void main(String[] args) {
    List<Studentas> studentai = new ArrayList<>();
    studentai.add(new Studentas("Jonas", 25));
    studentai.add(new Studentas("Ona", 18));
    studentai.add(new Studentas("Petras", 19));
    studentai.add(new Studentas("Kazimieras", 19));

    // Rūšiuojama pagal amžių naudojant Comparable interfeisą
    Collections.sort(studentai);
    System.out.println("Studentų sąrašas pagal amžių mažėjimo tvarka:");
    for (Studentas studentas : studentai) {
      System.out.println(studentas);
    }
  }
}

Į ekraną bus išvestas Studentų sąrašas pagal amžių mažėjimo tvarka:
Studentas(vardas='Jonas', amzius='25');
Studentas(vardas='Petras', amzius='19');
Studentas(vardas='Kazimieras', amzius='19');
Studentas(vardas='Ona', amzius='18');

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

Savarankiškai dar kartą peržiūrėkite pavyzdžius. Pabandykite sukurti savo asmeninį filtrą naudojant Comparator ar Comparable interfeisą.

Last update: September 20, 2021 06:35
Contributors: Marius Gžegoževskis