Przyszedł czas na struktury danych takie jak tablice i listy. Są to struktury danych bardzo często używane w programowaniu, ponieważ pozwalają przechować więcej niż jeden obiekt danego typu oraz wykonywać operacje na nich. Struktury danych brzmi “groźnie”, ale tak na prawdę nie są one skomplikowane. W poprzednich artykułach opisałem teorię i pokazałem przykłady kodu dotyczące tworzenia pierwszej klasy w języku Java, jak i gdzie zapisać wartości w klasie, jak wykonywać działania na klasie oraz jak ukryć kod klasy przed niepowołanym dostępem.
Zanim przejdę do samej teorii odnośnie tablic i list pokażę o co chodzi z tym przechowywaniem więcej niż jednego obiektu danego typu. Poniższy kod pokazuje nie najlepsze podejście do tematu wielu zmiennych, obiektów tego samego typu.
public class PaintShop {
private String blackPaint;
private String whitePaint;
private String bluePaint;
// etc.
// getter/setter
// toString
}
W powyższym przykładzie za każdym razem kiedy w klasie PaintShop chcielibyśmy dodać nowy kolor musielibyśmy tworzyć nową zmienną, a to już na tym etapie łamie zasadę “O – open/closed principle” z SOLID. Dodatkowo istnieje bardzo duża liczba kolorów i klasa z np. 99 zmiennymi nie będzie łatwa w utrzymaniu, nie mówiąc już o tym jak będzie wyglądać.
Poniżej kod pokazujący użycie zmiennych z klasy PaintShop.
public class LocalPaintShop {
public static void main(String[] args) {
PaintShop paintShop = new PaintShop();
paintShop.setBlackPaint("black");
paintShop.setGreenPaint("green");
paintShop.setWhitePaint("white");
System.out.println("Colors in the Shop: " + paintShop);
}
}
Poniższy kod pokazuje jak zadeklarować tablicę obiektów klasy/typu String i uniknąć powyższej sytuacji z oddzielnymi zmiennymi dla każdego koloru.
public class PaintShop {
private String[] paintColors;
}
Tym razem prezentację działania tablic zrobię po prostu w metodzie main() bez klasy zawierającej zmienną tablicową oraz bez metod dostępowych do tablicy. Ułatwi, to zrozumienie istoty tablic bez “zaciemniania” obrazu dodatkową. Docelowo zmienna tablicowa musi być w oddzielnej klasie, która umożliwi działanie na tej tablicy. Nie należy modyfikować dowolnej zmiennej, również tablicy, bezpośrednio, bez użycia metod.
Poniższy kod pokazuje i opisuje tworzenie tablicy.
public class ArrayUsageMain {
public static void main(String[] args) {
// Deklaracja tablicy typu/klasy String
// tablica przechowująca 10 elementów
// ---
// Wyjaśnienie elementów od lewej do prawej:
// - String - typ zmiennych przechowywanych w tablicy,
// - [] - informacja, o tym, że tworzymy tablicę,
// - colors - nazwa tablicy
// = - przypisanie wartości do tablicy
// new - tworzenie tablicy
// [10] - rozmiar tablicy
String[] colors = new String[10];
}
}
Tworząc i korzystając z tablicy należy pamiętać o kilku ważnych elementach:
– tablica zawsze musi mieć podany rozmiar,
– jeżeli skończy nam się miejsce w tablicy, musimy utworzyć większą,
– nie można dynamicznie zmieniać rozmiaru tablicy,
– elementy w tablicy są przechowywane na pozycjach od [0] do [n-1],
– tablice przechowują wartości pod konkretnym indeksem.
Poniższy kod pokazuje przypisanie i pobranie danych/wartości dla tablicy.
public class ArrayUsageMain {
public static void main(String[] args) {
String[] colors = new String[10];
// przypisanie wartości do pierwszego elementu
colors[0] = "black";
// przypisanie wartości do ósmego elementu
colors[9] = "white";
String firstElement = colors[0];
String fourthElement = colors[3];
String tenthElement = colors[9];
System.out.println("Pierwszy element tablicy: " + firstElement);
System.out.println("Czwarty element tablicy: " + secondElement);
System.out.println("Dziesiąty, ostatni element tablicy: " + eightElement);
}
}

Numerowanie elementów tablicy i ich indeksy zawsze sprawiają najwięcej problemów, bo na pierwszy rzut oka nie są intuicyjne. Wartość tablicy dla konkretnego indeksu można wyjaśnić za pomocą analogi ze skrzynkami na listy np. w bloku, gdzie jest więcej niż jedna skrzynka na listy.
– Ustawianie wartości tablicy: listonosz umieszczając listy musi znać numer mieszkania adresata i wkłada list do właściwej skrzynki, dla tablicy numerem skrzynki jest jej indeks.
– Pobieranie wartości tablicy: osoba wyjmująca list również musi wiedzieć, z której skrzynki wyjąć list, czyli znać swój numer mieszkania, dla tablicy jest, to jej indeks. Dopiero dla konkretnego numeru/indeksu można wyjąć listy, wartości z tablicy.
Dostęp do elementów tablicy uzyskujemy za pomocą indeksu np. colors[0] pobiera pierwszy, gdzie 0 jest indeksem tablicy. Kod String color = colors[0] pobiera do zmiennej String color wartość będącą pod indeksem 0. Przypisywanie wartości do tablicy również odbywa się za pomocą indeksów np. colors[0] = “black”, teraz w tablicy pierwszy element będzie miał wartość “black”.
W telegraficznym skrócie starałem się przybliżyć temat tablic, ale tak jak pisałem wcześniej tablice mają pewne ograniczenia, o których należy pamiętać. Po mimo tych ograniczeń tablice są strukturą danych, która jest bardzo często używana. W wielu algorytmach np. sortowania działa się na tablicach, niektóre implementacje List w języku Java oparte są na tablicach.
Teraz postaram się przybliżyć listy w języku Java. Listy również jak tablice przechowują więcej niż jeden element danego typu, ale nie mają takich ograniczeń jak tablice np.
– nie trzeba podawać rozmiaru listy przy jej tworzeniu,
– rozmiar tablicy jest zmieniany dynamicznie podczas wstawiania elementów,
– sposób przechowywania elementów zależy od konkretnego typu listy,
– elementy w liście przechowywane są od indeksu 0.
Listy w Java w odróżnieniu od tablic są klasami, czyli typami złożonymi. Wszystkie listy w Java są oparte na wspólnym interfejsie java.util.Collection. Dla interfejsu Collection mamy kilka interfejsów rozszerzających, jednym z nich jest właśnie java.util.List, która przechowuje listę elementów. Dla Collection dostępne są również java.util.Set, java.util.Queue oraz wspomniana java.util.List. Dlaczego stworzono wspólny interfejs? Dlatego, aby ujednolicić dostępne operacje na kolekcjach (java.util.Collection) m.in. java.util.List.
Operacje na listach wykonujemy za pomocą metod z interfejsu java.util.Collection np. add(E), remove(Object), size(). Niezależnie od tego jaką implementację java.util.List wybierzemy, zawsze mamy dostępne powyższe metody, co ułatwia pracę z kolekcjami w języku Java. Nie będę tutaj pisał o różnicach pomiędzy różnymi typami/implementacjami list np. ArrayList, LinkedList, Vector, więcej informacji można znaleźć w oficjalnej dokumentacji Oracle – List Implementations. W poniższych przykładach będę używał ArrayList jako implementacji interfejsu java.util.List.
Poniższy kod pokazuje i opisuje tworzenie listy.
public class ListUsageMain {
public static void main(String[] args) {
// Deklaracja listy typu/klasy String
// domyślnie ArrayList przechowuje 10 elementów
// ---
// Wyjaśnienie elementów od lewej do prawej:
// - List - typ zmiennej umożliwiającej operacje na liście
// - <String> - typ generyczny listy, mówi o tym jakie elementy może przechowywać lista
// - colors - nazwa zmiennej
// = - przypisanie wartości do listy
// new - tworzenie obiektu
// ArrayList - typ listy
List<String> colors = new ArrayList<>();
}
}
Poniższy kod pokazuje przypisanie i pobranie danych/wartości dla listy.
public class ListUsageMain {
public static void main(String[] args) {
List<String> colors = new ArrayList<>();
colors.add("black");
colors.add("white");
colors.add("red");
System.out.println("Pierwszy element listy: " + colors.get(0));
System.out.println("Drugi element listy: " + colors.get(1));
System.out.println("Trzeci element listy: " + colors.get(2));
System.out.println("Zawartość całej listy: " + colors);
}
}
Nieodzownym elementem tablic i list są pętle, o których napiszę w kolejnych artykułach.
Całość kodu można znaleźć na:
Zapraszam do regularnego odwiedzania mojej strony, będą pojawiać się kolejne artykuły oraz do kontaktu przez email kontakt(at)juniorjavadeveloper.pl.


