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.
Appa Notka.
Analizujemy kolejne kursy na Udemy, wykorzystując nasze doświadczenie zawodowe do oceny ich efektywności i
popularności wśród uczestników. Z dużym zaangażowaniem selekcjonujemy te, które naszym zdaniem są najbardziej
efektywne i jednocześnie cieszą się uznaniem uczestników.
Poniższy kurs "[2023] Java od podstaw - zbuduj własne aplikacje!" jest efektem tej
głębokiej analizy i prezentuje idealne połączenie wysokiej jakości edukacyjnej z aktualnymi trendami i
wymaganiami rynkowymi. Około 7 000 kursantów, ocena bliska 5.0!
Tworzenie listy
Dobrą praktyką jest zadeklarowanie instancji listy z
parametrem typu, na przykład:
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:
Java 9
Od Javy 9 możemy utworzyć kolekcję z ustalonego zestawu elementów:
Java 10
Od Javy 10 można jeszcze bardziej skrócić tworzenie kolekcji, używając słowa
var:
Niemniej to rozwiązanie ma pewne ograniczenia, a także wady, o których piszemy w kursie Java 8 do 17 (obrazek poniżej).
Szukasz dobrego kursu nowej Javy? Mamy dla Ciebie kurs oparty na 150 przykładach.
Kurs nowej Javy składa się z kursu Javy 8 oraz Javy od wersji 9 do 17.
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ę.
Dodawanie elementów podtypów zadeklarowanego typu:
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.
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.
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.
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):
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.
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):
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 17.
Poświęcamy mu tam kilka rozdziałów, omawiając bogatą kolekcję przykładów.
Autor: Jarek Klimas
Data: 03 stycznia 2024
Labele: Backend, Podstawowy, Java
Czy informacje, które otrzymałeś, były pomocne?
Jeśli tak, zapraszam Cię do podarowania mi kawy.
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.
Czy da się stworzyć pustą listę tak, żeby nie było możliwe dodawanie do niej elementów?
Chodzi o to, że chcę, aby nie była ustawiona na null, ale żeby nie dało sie wkładać tam danych?
Paweł
Tak, jest to możliwe! W pakiecie
java.util jest klasa
Collections, która
ma statyczną metodę zwracającą taką listę. Na przykład, żeby stworzyć pustą, niemodyfikowalną listę stringów wystarczy napisać:
List<String> texts = Collections.emptyList();
W razie próby dodania elementu do takiej listy, zostanie wyrzucony wyjątek
UnsupportedOperationException