Kurs Java

Kolekcje - Listy

Tak jak napisaliśmy w poprzednim rozdziale, listy są dostarczane w ramach kolekcji za pośrednictwem interfejsu List z pakietu java.util. Listę możemy zasadniczo zdefiniować jako bardziej elastyczną wersję tablicy. Jest to jednak pewne uproszczenie, dlatego też przyjrzyjmy się teraz dokładnie jakie są cechy charakterystyczne list:
  • Elementy listy mają określoną kolejność.

  • Dozwolone są duplikaty elementów.

  • Elementy można umieścić na liście w określonej pozycji.

  • Element znajdujący się w określonej pozycji można prosto pobrać z listy.

  • Element w określonej pozycji możemy łatwo podmienić na inny.

  • Listy możemy łatwo sortować.

  • Nie musimy deklarować na początku rozmiaru listy (choć ogólnie warto to robić, jeśli jesteśmy w stanie przewidzieć jej rozmiar).

Popularne implementacje list

Zdecydowana najpopularniejszymi listami używanymi w budowie programów są implementacje dostarczane przez klasy:
  • ArrayList z pakietu java.util

    Implementuje listę jako tablicę. Rozmiar tablicy zostanie automatycznie rozszerzony, jeśli nie będzie wystarczającej ilości miejsca podczas dodawania nowych elementów do listy. Można ustawić domyślny rozmiar, określając początkową pojemność podczas tworzenia nowej listy. Doprecyzowanie rozmiaru nie jest obowiązkowe, ale jest wydajniejsze, gdyż przebudowa listy na większą zajmuje trochę czasu. Lista typu ArrayList jest szybka podczas wyszukiwania elementów i ich pobierania (metoda get) oraz podczas ich podmiany (metoda set).

  • LinkedList z pakietu java.util

    Implementacja przechowująca elementy w strukturze danych w postaci podwójnie połączonej listy. Dodatkowo implementuje ona interfejs (Queue), co powoduje, że możemy tutaj używać metod niedostępnych w ramach klasy ArrayList, na przykład peek i poll. Lista typu LinkedList jest szybka podczas dodawania i usuwania elementów (metody add i remove), ale jest wolniejsza w przypadku pobierania elementów za pomocą metody get.
Można to podsumować tak, że jeśli potrzebujemy często dodawać i usuwać elementy z listy, a rzadko wyszukujemy i pobieramy z niej elementy, wówczas powinniśmy użyć LinkedList. W przeciwnym wypadku, czyli wtedy gdy rzadko dodajemy/usuwamy elementy, a bardzo często je wyszukujemy w celu pobrania, wtedy zdecydowanie lepiej jest użyć ArrayList.
Znacznie rzadziej używaną listą jest Vector. Jest to lista bardzo podobna do ArrayList, z tą różnicą, że Vector jest listą synchronizowaną. Tak więc, jeśli w inny sposób nie zapewniamy synchronizacji operacji, a jest ona istotna w kontekście pracy wykonywanej w programie, powinniśmy wtedy użyć klasy Vector. Trzeba jednak pamiętać, że ta implementacja jest znacznie wolniejsza od ArrayList.

Tworzenie listy

Dobrą praktyką jest zadeklarowanie instancji listy z parametrem typu, na przykład:
List<Object> listAnything = new ArrayList<Object>();
List<Integer> listNumbers = new ArrayList<Integer>();
List<String> linkedWords = new LinkedList<String>();
Do tej pory nie mówiliśmy jeszcze o parametrach typu, ale na tę chwilę warto wiedzieć, że podając nazwę typu w nawiasach ostrych, określamy jakiego typu obiekty mogą być przechowywane w danej liście. Dzięki temu już na etapie kompilacji jesteśmy w stanie się zorientować, czy nie popełniliśmy błędu - na przykład przekazując obiekt klasy String do listy, w której możemy przechowywać tylko obiekty klasy Integer. W takiej sytuacji dowiemy się o tym od razu, gdyż po prostu otrzymamy błąd kompilacji. Szerzej piszemy o tym w rozdziale Typy generyczne w Javie.

Java 7

Od Javy 7 możemy usunąć parametr typu po prawej stronie, co upraszcza zapis do następującej postaci:
List<Integer> listNumbers = new ArrayList<>();
List<String> linkedWords = new LinkedList<>();

Java 9

Od Javy 9 możemy utworzyć kolekcję z ustalonego zestawu elementów:
List listNumbers = List.of(1, 2, 3, 4, 5, 6);

Java 10

Od Javy 10 można jeszcze bardziej skrócić tworzenie kolekcji, używając słowa var:
var items = new ArrayList<Item>();
Niemniej to rozwiązanie ma pewne ograniczenia, a także wady, o których piszemy w kursie Java 8 do 14 (obrazek poniżej).
Szukasz dobrego kursu nowej Javy? Mamy dla Ciebie kurs oparty na 150 przykładach.
Kurs od Javy 8 do 14
Kurs nowej Javy składa się z kursu Javy 8 oraz Javy od wersji 9 do 15.

Podstawowe operacje na listach

Podstawowymi operacjami, jakie możemy wykonywać na listach, jest dodawanie, pobieranie, aktualizowanie oraz usuwanie elementów. Operacje te są realizowane przez następujące metody:
  • add(<obiekt>)

    Umożliwia ona dodanie elementu do listy. Co ważne - wymagane jest dodanie elementów tego samego typu (lub podtypu) co parametr typu zadeklarowanego przez listę.
    List<String> listStrings = new ArrayList<String>();
    // Poniższe elementy zostaną dodane do listy - wszystkie są typu String:
    listStrings.add("One");
    listStrings.add("Two");
    listStrings.add("Three");
    // Poniższy element nie zostanie dodany do listy - kompilator zgłosi błąd:
    listStrings.add(123);
    
    Dodawanie elementów podtypów zadeklarowanego typu:
    List<Number> linkedNumbers = new LinkedList<>();
    linkedNumbers.add(new Integer(123));
    linkedNumbers.add(new Float(3.1415));
    linkedNumbers.add(new Double(299.988));
    linkedNumbers.add(new Long(67000));
    
    Pozycje w liście - podobnie jak w przypadku tablic - są numerowane od zera. Dodawanie następnego elementu powoduje umieszczenie go w kolejnym wolnym indeksie (0, 1, 2, 3...itd.).

  • get(<indeks>)

    Umożliwia ona pobranie elementu z listy poprzez podanie indeksu, na którym znajduje się ten element.
    String element = listStrings.get(1);
    Number number = linkedNumbers.get(3);
    
    Powyższy kod pobiera element położony na drugiej pozycji w liście listStrings i element z czwartej pozycji w liście linkedNumbers (wynika to stąd, że numeracja indeksów zaczyna się od zera).

  • set(<indeks>, <obiekt>)

    Metoda aktualizuje element w danej pozycji listy, a dokładniej mówiąc zastępuje ten element.
    listStrings.set(3, "Hello Javappa");
    
    Zapis ten oznacza, że czwarty element na liście, będzie zastąpiony nowym ciągiem znaków.

  • remove(<indeks>)

    Metoda usuwa element w danej pozycji listy. Innymi słowy element znajdujący się na danym indeksie jest całkowicie usuwany z listy.
    listStrings.remove(3);
    
    Zapis ten oznacza, że czwarty element na liście zostanie z niej usunięty.
Wymieniliśmy tutaj zaledwie kilka podstawowych metod, które umożliwiają pracę z listami. Z biegiem czasu wymagane będzie zapoznanie się również z innymi metodami. Uruchamiając mechanizm podpowiedzi w IDE, na przykład w IntelliJ, można łatwo poznać, jakie metody są dostępne (obrazek zawiera podpowiedź dla listy linkedNumbers, stąd wszędzie od razu jest ustawiony typ obiektu Number):
Rozpakowanie Eclipse IDE

Przeglądanie zawartości listy

Zgodnie z tym, co pisaliśmy w poprzednim rozdziale, listy implementują interfejs Iterable, co umożliwia przeglądanie ich element po elemencie. W tym celu wykorzystujemy interfejs Iterator. Jego działanie polega na przeglądaniu listy, dopóki po danym elemencie występuje kolejny element. Pobranie bieżącego elementu i przejście do następnego wykonywane jest za pomocą metody next.
List<Number> someNumbers = new ArrayList<>();
someNumbers.add(new Integer(123));
someNumbers.add(new Float(3.1415));
someNumbers.add(new Double(299.988));
someNumbers.add(new Long(67000));

Iterator<Number> someNumbersIterator = someNumbers.iterator();

while(someNumbersIterator.hasNext()) {
    System.out.println(someNumbersIterator.next());
}
Przekazanie zadania iteracji zewnętrznemu mechanizmowi (obiektowi klasy Iterator) powoduje, że nie zależymy od implementacji naszej struktury danych. Trzeba bowiem pamiętać, że nie tylko listy możemy iterować w Javie.

Natomiast i tak najczęściej stosowanymi rozwiązaniami do przeglądania list są udoskonalone pętle for (tzw. for-each):
List<Number> someNumbers = new ArrayList<>();
someNumbers.add(new Integer(123));
someNumbers.add(new Float(3.1415));
someNumbers.add(new Double(299.988));
someNumbers.add(new Long(67000));

for (Number number : someNumbers) {
    System.out.println(number);
}
albo też zupełna nowość od Javy w wersji 8, a więc strumienie. To jednak jest już zupełnie inne, obszerne zagadnienie, które poruszamy w ramach Kursu Javy 8 do 14. Poświęcamy mu tam kilka rozdziałów, omawiając bogatą kolekcję przykładów.
Linki
https://www.geeksforgeeks.org/list-interface-java-examples
Masz pytanie dotyczące tego rozdziału? Zadaj je nam!
Masz pytanie dotyczące prezentowanego materiału?
Coś jest dla Ciebie niejasne i Twoje wątpliwości przeszkadzają Ci w pełnym zrozumieniu treści?
Napisz do nas maila, a my chętnie znajdziemy odpowiednie rozwiązanie.
Najciekawsze pytania wraz z odpowiedziami będziemy publikować pod rozdziałem.
Nie czekaj. Naucz się programować jeszcze lepiej.
kursjava@javappa.com

Stale się rozwijamy, a więc bądź na bieżąco!
Na ten adres będziemy przesyłać informacje o ważniejszych aktualizacjach, a także o nowych materiałach pojawiających się na stronie.
Polub nas na Facebooku:
Nasi partnerzy: stackshare
Javappa to również profesjonalne usługi programistyczne oparte o technologie JAVA. Jeśli chesz nawiązać z nami kontakt w celu uzyskania doradztwa bądź stworzenia aplikacji webowej powinieneś poznać nasze doświadczenia.
Kliknij O nas .


Pozycjonowanie stron: Grupa TENSE