W tym artykule szczegółowo omówimy klasę ArrayList z Collections Framework, która jest być może najłatwiejsza do zrozumienia, ponieważ opiera się na zwykłej tablicy. Prawie na pewno podczas rozmowy kwalifikacyjnej zostaniesz zapytany o tę klasę i jej implementację w Javie. W drugiej części przeanalizujemy pozostałe metody i napiszemy własną implementację tablicy dynamicznej dla liczb. Klasa ArrayList dziedziczy po klasie AbstractList i implementuje następujące interfejsy: List, RandomAccess, Cloneable, Serializable. Szczegółowa analiza klasy ArrayList [Część 2] Klasa ArrayList obsługuje tablice dynamiczne, które można rozszerzać w miarę potrzeb. Jego konieczność i skuteczność wynika z faktu, że zwykła tablica ma stałą długość: raz utworzona nie może się zwiększać ani zmniejszać, co nakłada ograniczenia, jeśli nie wiadomo, jak duża będzie potrzebna tablica. Zasadniczo klasa ArrayList jest tablicą list o zmiennej długości, zawierającą odniesienia do obiektów. Ważne jest, aby zrozumieć, że rozmiar (liczba komórek) tablicy wewnętrznej nie zmniejsza się automatycznie po usunięciu z niej elementów. W rzeczywistości zmniejsza się wartość zmiennej
Tym samym, gdy element zostanie wstawiony w indeksie, a w tablicy nie będzie już wolnych spacji, wywołanie
Możesz także dodawać elementy do naszej kolekcji za pomocą pliku
Spróbujmy usunąć element o indeksie 3 z poniższej tablicy:
Rozważmy drugą wersję metody:
Usuwa elementy, które nie należą do przekazanej kolekcji:
Powiedzmy, że mamy kolekcję:
Wymiana elementów
Sprawdź kolekcję pod kątem elementów:
size
, która wskazuje liczbę elementów faktycznie występujących w tablicy. Załóżmy, że tworzymy nowy obiekt klasy ArrayList i dodajemy do niego 5 elementów. Domyślnie tworzona jest tablica złożona z 10 elementów. W tym przypadku tzw. pojemność (rozmiar/objętość) naszego obiektu będzie równa 10, natomiast wartość zmiennej size
będzie równa pięć. A kiedy usuwamy elementy, widzimy zmiany wartości zmiennej size
, ponieważ .length
nie możemy uzyskać dostępu do wewnętrznej tablicy klasy ArrayList i sprawdzić jej długości. Rozmiar można zmniejszyć za pomocą dodatkowej metody trimToSize()
, która zostanie omówiona później. Przyjrzyjmy się polom klas.
-
Pole odpowiedzialne za domyślny wolumin tablicy dynamicznej:
private static final int DEFAULT_CAPACITY = 10
Podczas tworzenia nowego obiektu new ArrayList<>() (konstruktor bez parametrów) wewnątrz tworzona jest tablica złożona z 10 elementów.
-
Pole, w którym przechowywane są wszystkie elementy kolekcji:
transient Object[] elementData
Oznaczone słowem kluczowym
transient
- pole nie jest zapisywane do strumienia bajtów przy zastosowaniu standardowego algorytmu serializacji. Warto zaznaczyć, że pole nie jest oznaczone słowem kluczowymprivate
, ale zrobiono to po to, aby ułatwić dostęp do tego pola z klas zagnieżdżonych (np. SubList). - Pole licznika przechowujące rzeczywistą liczbę elementów w tablicy:
private int size
Wartość jest zwiększana/zmniejszana podczas wykonywania operacji takich jak wstawianie i usuwanie.
public ArrayList()
– tworzy pustą tablicę list zawierającą 10 elementów;public ArrayList(Collection < ? extends E > c)
– tworzy tablicę list inicjowaną elementami z przekazanej kolekcji (jeśli chcemy stworzyć nową ArrayList na podstawie jakiejś kolekcji);public ArrayList(int initialCapacity)
– tworzy tablicę list o początkowej pojemności. Jeżeli przekazany parametr początkowyCapacity jest większy od 0, to tworzona jest tablica o określonej wielkości (do wewnętrznego pola elementData zostaje przypisany link do nowej tablicy typu Object o rozmiarze początkowyCapacity). Jeżeli parametr ma wartość 0, wówczas tworzona jest pusta tablica. Jeśli określony parametr jest mniejszy niż 0, zgłaszany jest wyjątek IllegalArgumentException.
List < String> list = new ArrayList<>();
Nowo utworzony obiekt list
zawiera właściwości (pola) elementData
oraz size
. Magazyn wartości elementData
to nic innego jak tablica określonego typu (określonego ogólnie – <>
), w naszym przypadku String[]
. Jeżeli zostanie wywołany konstruktor bez parametrów, to domyślnie utworzona zostanie tablica składająca się z 10 elementów typu Object (oczywiście z rzutowaniem na typ). Dodawanie elementów Klasycznie dodawanie elementów do tablicy list odbywa się przy użyciu przeciążonych wariantów metody add()
.
public boolean add(E элемент)
No cóż, dodajmy: list.add("0");
Wewnątrz tej metody wywoływana jest przeciążona wersja metody add()
, oznaczona jako private
, która z kolei przyjmuje na wejściu trzy parametry: element, który ma zostać dodany, tablicę wewnętrzną i jej rozmiar. W metodzie prywatnej następuje sprawdzenie: jeżeli przekazany parametr size jest równy długości tablicy wewnętrznej (czyli tablica jest pełna), to do tablicy przypisywany jest wynik metody grow(int minCapacity)
(bieżąca wartość pola size + 1 jest przekazywany do metody, gdyż konieczne jest uwzględnienie dodawanego elementu), w której do wewnętrznej tablicy przypisywany jest link do nowo utworzonej tablicy uzyskany poprzez skopiowanie elementów oryginalnej tablicy:
Arrays.copyOf(elementData, newCapacity(minCapacity))
Jako drugi parametr metody copyOf
podajemy wynik metody newCapacity(int minCapacity)
, w ramach którego obliczany jest nowy rozmiar tablicy. Oblicza się go według następującego wzoru: int newCapacity = oldCapacity + (oldCapacity >> 1)
Dla tablicy o domyślnym rozmiarze będzie obowiązywać: >> 1
– bitowe przesunięcie w prawo o jeden (operator zmniejszający liczbę o połowę). Zasadniczo oznacza to dzielenie przez 2 do potęgi 1. Okazuje się, że dzielimy 10 przez 2 i dodajemy 10. W sumie nowa pojemność tablicy wynosi 15, ale skoro dodajemy 11. element, to 15 + 1 = 16. Wróćmy do naszej listy i załóżmy, że dodaliśmy już do niej 10 elementów i spróbujemy dodać 11. Sprawdzenie wykaże, że w tablicy nie ma miejsca. W związku z tym tworzona i wywoływana jest nowa tablica Arrays.copyOf
, która wewnętrznie wykorzystuje metodę systemową System.arraycopy()
. Lub oto wyraźny przykład z jednego artykułu na JavaRush: Po tych wszystkich sprawdzeniach i zwiększeniu rozmiaru tablicy, jeśli to konieczne, w metodzie prywatnej add()
dodawany jest nowy element na końcu tablicy, a bieżący parametr size
jest zwiększany o jeden . Stara tablica zostanie następnie przetworzona przez moduł zbierający elementy bezużyteczne. Tak działa tablica dynamiczna: dodając elementy sprawdzamy, czy jest w niej jeszcze miejsce. Jeśli jest miejsce, po prostu dodajemy element na końcu tablicy. Koniec nie oznacza ostatniej komórki w tablicy, ale komórkę odpowiadającą wartości size
. Do tablicy dodaliśmy pierwszy element, który umieszczamy w komórce o indeksie [0]. Wartość pola size
wzrosła o jeden i = 1. Dodajemy kolejny element: widzimy, że size = 1
, odpowiednio umieszczamy element w komórce o indeksie [1] i tak dalej. Istnieje przeciążona wersja metody z dwoma parametrami:
public void add(int index, E element)
Możemy określić pozycję (indeks) komórki, w której chcemy dodać element. W pierwszej kolejności sprawdzana jest poprawność podanej wartości indeksu, gdyż istnieje możliwość podania nieprawidłowego indeksu, który wskaże komórkę, w której nic nie ma, lub która po prostu nie istnieje. Sprawdzanie indeksów: index > size || index < 0
– jeżeli podany indeks jest większy od aktualnego rozmiaru tablicy lub jest mniejszy od 0, to zgłaszany jest wyjątek IndexOutOfBoundsException
. Następnie, jeśli to konieczne, zwiększa się rozmiar tablicy, podobnie jak w powyższym przykładzie. Prawdopodobnie słyszałeś, że podczas operacji dodawania/usuwania tablicy coś zostaje gdzieś przesunięte (w prawo lub w lewo). Zatem przesunięcie odbywa się poprzez skopiowanie tablicy: System.arraycopy(elementData, index, elementData, index + 1, s - index);
Wszystkie elementy znajdujące się na prawo od podanego indeksu zostaną przesunięte o jedną pozycję w prawo (indeks+1). I dopiero potem do wewnętrznej tablicy dodawany jest nowy element o określonym indeksie. Ponieważ przesunęliśmy część tablicy o jeden w prawo (nowa tablica nie jest tworzona), potrzebna nam komórka będzie wolna do zapisu. Link do starej tablicy zostanie usunięty i w przyszłości zostanie przejęty przez moduł zbierający śmieci. Wklej „maserati” do komórki [3], która jest już zajęta:
System.arraycopy()
nastąpi dwukrotnie: pierwsze w grow()
, drugie w samej metodzie add(index, value)
, co wyraźnie wpłynie na szybkość całej operacji dodawania. W rezultacie, gdy trzeba zapisać kolejny element do tablicy wewnętrznej, ale nie ma tam miejsca, wówczas wewnątrz tablicy ArrayList dzieje się tak:
- Tworzona jest nowa tablica o rozmiarze 1,5 razy większym niż oryginalna, plus jeden element.
- Wszystkie elementy ze starej tablicy zostaną skopiowane do nowej tablicy
- Nowa tablica jest przechowywana w wewnętrznej zmiennej obiektu ArrayList, a stara tablica jest uznawana za śmieci.
public void ensureCapacity(int minCapacity)
Zwiększając wcześniej pojemność macierzy, można uniknąć późniejszej redystrybucji pamięci RAM. Metoda zwiększa rozmiar tablicy wewnętrznej, aby pomieścić liczbę elementów przekazywanych do minCapacity
. Metoda ensureCapacity()
nie wpływa na pole size
, wpływa na capacity
(rozmiar) tablicy wewnętrznej. Jeszcze raz podkreślam, że size
to dwie capacity
różne rzeczy i bardzo ważne jest, aby ich nie mylić! Jeśli chcesz zmniejszyć rozmiar podstawowej tablicy, z której zbudowana jest ArrayList, do bieżącej liczby faktycznie przechowywanych elementów, powinieneś wywołać metodę trimToSize()
. Po usunięciu elementów z kolekcji size()
wyświetli się liczba faktycznie istniejących elementów i capacity
nie będzie się zmniejszać! Załóżmy, że wprowadziliśmy 100 elementów, usunęliśmy pierwsze 50, size
wyjdzie 50 i tak capacity
pozostanie 100. Aby zredukować i capacity
musimy zastosować metodę trimToSize()
, która dopasuje całą naszą pojemność do aktualnego rozmiaru. Jak to leży? Kopiuje naszą tablicę tak, aby nie pozostały już puste komórki (długość nowej tablicy jest po prostu równa polu rozmiaru).
addAll
.
public boolean addAll(Collection< ? extends E> c)
public boolean addAll(int index, Collection< ? extends E> collection);
Pierwsza opcja pozwala na dodanie wszystkich elementów z kolekcji określonej w parametrze metody (np. innego arkusza) do oryginalnej kolekcji (wstaw na końcu), dla której wykonano wywołanie metody. Przekazana kolekcja (może to być również zestaw) jest konwertowana na tablicę za pomocą metody toArray()
. Naturalnie operacja dodawania odbywa się również poprzez kopiowanie. Drugim jest dodanie wszystkich elementów collection
do listy zaczynając od indeksu index
. W takim przypadku wszystkie elementy zostaną przesunięte w prawo o liczbę elementów na liście collection
. Usuwanie elementów Najpierw przyjrzyjmy się klasycznym opcjom usuwania elementów z listy ArrayList.
public E remove(int index)
Wykonuje usuwanie według indeksu i przesuwa wszystkie kolejne (po elemencie o określonym indeksie) elementy w lewo, zamykając w ten sposób „dziury”. Zwraca także usunięty element (E), który przed usunięciem został wcześniej zapisany do dodatkowej zmiennej, której wartość uzyskujemy w wyniku wywołania metody. Aby zrozumieć, czym jest E, musisz zapoznać się z tak zwanymi typami ogólnymi. Notacja E wskazuje, że metoda zwraca typ danych, który został określony podczas tworzenia obiektu ArrayList (pamiętajcie: List <String> list
odpowiednio w tym przypadku E zostanie „podstawione” String
). Dla ogólnego zrozumienia zdecydowanie zalecam zapoznanie się z typami ogólnymi. Sprawdzana jest poprawność wprowadzonego indeksu, po czym wewnątrz metody element nie jest całkowicie usuwany, lecz wywoływana jest metoda prywatna fastRemove(Object[] es, int i)
, w której usunięcie już nastąpiło. Jako dane wejściowe przekazujemy naszą tablicę i określony indeks do metody. Elementy kopiujemy za pomocą System.arraycopy()
, zmniejszamy rozmiar tablicy, a następnie do ostatniego elementu przypisujemy wartość null. Warto zaznaczyć, że nowa tablica nie jest tworzona: System.arraycopy(es, i + 1, es, i, size - 1 - i);
Część znajdująca się na prawo od pozycji pod podanym indeksem (i+1) jest kopiowana do naszej oryginalnej tablicy (es) i lokowana zaczynając od tej samej pozycji (i) gdzie znajdował się element, który miał zostać usunięty. W ten sposób wykonaliśmy przesunięcie w lewo i usunęliśmy nasz element.
public boolean remove(Object o)
Metoda usuwa przekazany element z listy o
, a dokładniej obiekt znajdujący się pod wskazanym łączem. Jeżeli element znajduje się na liście, zostaje on usunięty, a wszystkie elementy przesunięte w lewo. Jeśli element istnieje na liście i został pomyślnie usunięty, metoda zwraca wartość true; w przeciwnym razie false. Podobnie jak w przypadku usuwania według indeksu, metoda nazywa się fastRemove()
, gdzie zachodzą dokładnie te same działania. Różnica polega na tym, że metoda remove(Object o)
dodatkowo wyszukuje żądany obiekt poprzez metodę equals()
klasy Object. Podczas usuwania według wartości pętla przechodzi przez wszystkie elementy listy, aż do znalezienia dopasowania. Tylko pierwszy znaleziony element zostanie usunięty. Podsumujmy: przy usuwaniu elementów z tablicy dynamicznej nie pozostają żadne dziury jak w zwykłej tablicy (usunięta komórka nie będzie pusta). Wszystkie kolejne elementy (które znajdowały się na prawo od indeksu) zostają przesunięte o jedną pozycję w lewo. Istnieje kilka dodatkowych metod, które można zastosować do usuwania elementów z listy w różnym stopniu. Przyjrzyjmy się im krótko. Czyszczenie naszej kolekcji:
public void clear()
Prosta pętla for
iteruje po wszystkich elementach tablicy, przypisując wartość null każdemu elementowi. Możesz usunąć te elementy z naszej kolekcji, które znajdują się w innej przeniesionej kolekcji, w ten sposób:
public boolean removeAll(Collection< ?> c)
Jeśli chcesz usunąć kilka elementów, prawdopodobnie nie powinieneś tego robić w pętli warunkowej: wygodniej i bezpieczniej jest użyć metody removeAll()
. Akceptuje zbiór elementów, które zostaną usunięte z listy. Kolekcja musi zawierać elementy tego samego typu, które przechowuje lista docelowa. W przeciwnym razie zostanie wyrzucony ClassCastException
. Metoda zwróci wartość true, jeśli lista została zmieniona w wyniku wywołania metody.
public boolean retainAll(Collection< ?> c)
List< String> listFirst = new ArrayList<>();
listFirst.add("White");
listFirst.add("Black");
listFirst.add("Red");
I drugi:
List< String> listSecond = new ArrayList<>();
listSecond.add("Green");
listSecond.add("Red");
listSecond.add("White");
Następnie po listSecond.retainAll(listFirst)
wejściu listSecond
pozostanie:
"White"
"Red"
Ponieważ usunięto „zielony”, którego nie ma w listFirst
. Ale potem listSecond.removeAll(listFirst)
pozostanie listSecond
:
"Green"
УдалLubсь все элементы, которые есть в listFirst.
Nienależący do przekazanej kolekcji - oznacza, że jeśli w przekazanej kolekcji znajdują się elementy, których nie ma, to należy je usunąć z pierwszego (do którego zastosowano metodę). Przynależność do przeniesionej kolekcji - odpowiednio, jeśli element znajduje się zarówno w pierwszej, jak i drugiej (przeniesionej) kolekcji, to duplikat z pierwszej ulega zniszczeniu.
protected void removeRange(int fromIndex, int toIndex)
Usuwa z listy wszystkie elementy znajdujące się pomiędzy początkowym określonym indeksem (włącznie) a końcowym określonym indeksem (niewłącznie). Warto zaznaczyć, że metody nie można wywołać bezpośrednio na obiekcie ArrayList. Aby z niego skorzystać, musisz dziedziczyć z AbstractList/ArrayList
. Metodę tę wykorzystuje także inna metoda (subList, która zostanie omówiona później).
public boolean removeIf(Predicate< ? super E> filter)
Usuwa elementy z kolekcji na podstawie danego predykatu. Sam predykat jest pewną funkcją/algorytmem/warunkiem, na podstawie którego zostanie usunięty jeden lub więcej elementów odpowiadających danemu warunkowi. Predicate
— interfejs funkcjonalny (zawiera tylko jedną metodę, więc można go wykorzystać jako lambda), działa na zasadzie „otrzymano jeden parametr – zwrócono wartość boolowską”. Zasadniczo metoda nadpisuje implementację z interfejsu Collection
i implementuje następującą „strategię”: iteruje po elementach i zaznacza te, które pasują do naszej Predicate
; następnie jest uruchamiany drugi raz, aby usunąć (i przesunąć) elementy zaznaczone w pierwszej iteracji. Zaimplementujmy interfejs Predicate
, który zwróci wartość true, jeśli dwa obiekty będą równe:
class SamplePredicate< T> implements Predicate< T>{
T varc1;
public boolean test(T varc){
if(varc1.equals(varc)){
return true;
}
return false;
}
}
W innej klasie utwórzmy ArrayList String
i obiekt naszej klasy, który implementuje Predicate
:
ArrayList< String> color_list = new ArrayList<> ();
SamplePredicate< String> filter = new SamplePredicate<> ();
Zapiszmy do zmiennej varc1
wartość „White” :
filter.varc1 = "White";
Dodajmy kilka linijek do listy:
color_list.add("White");
color_list.add("Black");
color_list.add("Red");
color_list.add("White");
color_list.add("Yellow");
color_list.add("White");
Wykonajmy metodę z listy removeIf
, do której przekażemy nasz obiekt z warunkiem:
color_list.removeIf(filter);
W rezultacie wszystkie wiersze z wartością „Biały” zostaną usunięte z listy, ponieważ nasz „predykat” porównuje je pod kątem równości. Ostateczna lista: [czarny, czerwony, żółty].
public E set(int index, E element)
Zastępuje element w określonej pozycji index
przekazanym element
. Indeks musi być również większy od zera i mniejszy od indeksu ostatniego elementu, w przeciwnym razie zostanie zgłoszony wyjątek IndexOutOfBoundsException
. Nie występują żadne kopie tablicy wewnętrznej. Po prostu zamiast elementu o określonym indeksie wstawiany jest nowy element, tj. nadpisz wartość.
public void replaceAll(UnaryOperator<e> operator)
Zmienia wszystkie elementy kolekcji (możliwe pod warunkiem). Najczęściej używany w połączeniu z lambdami lub klasą anonimową (ale dla przejrzystości w przykładzie użyjemy po prostu klasy implementującej interfejs), która implementuje interfejs UnaryOperator
i definiuje jego metody. Zaimplementujmy interfejs:
class MyOperator< T> implements UnaryOperator< T>{
T varc1;
public T apply(T varc){
return varc1;
}
}
W innej klasie utwórzmy ArrayList String
i obiekt naszej klasy, który implementuje UnaryOperator
:
ArrayList< String> color_list = new ArrayList<> ();
MyOperator< String> operator = new MyOperator<> ();
Zapiszmy do zmiennej varc1
wartość „White” :
operator.varc1 = "White";
Dodajmy kilka linijek do listy:
color_list.add("White");
color_list.add("Black");
color_list.add("Red");
color_list.add("White");
color_list.add("Yellow");
color_list.add("White");
Wykonajmy na liście metodę, replaceAll
do której przekażemy nasz obiekt operator
:
color_list.replaceAll(operator);
W rezultacie wszystkie wartości na liście zostały zastąpione „Białym”: [Biały, Biały, Biały, Biały, Biały, Biały]. I w ten sposób możesz na przykład usunąć wszystkie spacje z ciągów znajdujących się w kolekcji:
ArrayList< String> list = new ArrayList<>(Arrays.asList("A ", " B ", "C"));
list.replaceAll(String::trim);
Inne metody: Możesz przekonwertować ArrayList na zwykłą tablicę, używając metody:
public Object[] toArray()
Lub
public < T> T[] toArray(T[] a)
- tutaj określa się typ zwracanej tablicy. runtime
Metoda ta pozwoli na:
- przyspieszyć niektóre operacje;
- przekazać tablicę jako parametr do metody, która nie jest przeciążona, aby bezpośrednio zaakceptować kolekcję;
- Integracja nowego kodu opartego na kolekcjach ze starszym kodem, który nie rozpoznaje kolekcji.
public Object clone()
Należy pamiętać, że metoda clone()
zwraca typ obiektu, więc po jej wywołaniu konieczne będzie rzutowanie na wymaganą klasę. Klonowanie tworzy nowy niezależny obiekt. Sprawdź kolekcję pod kątem obecności obiektu:
public boolean contains(Object o)
Sprawdza obecność obiektu na liście (wewnętrznie przy pomocy metody równości klasy Object, czyli porównuje referencje), w zależności od wyniku zwraca wartość true/false. Oprócz zwykłych pętli możesz iterować po kolekcji (uzyskiwać dostęp do każdego elementu i wykonywać pewne czynności) za pomocą:
public void forEach(Consumer< ? super E> action)
Oto jak możemy wyświetlić naszą listę:
List< Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 50, 100, -5));
numbers.forEach((number)-> System.out.println(number));
Bez użycia lambd musisz użyć anonimowej klasy i zastąpić metodę accept
interfejsu Consumer
:
numbers.forEach(new Consumer< Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
Pobierz element według jego indeksu:
public E get(int index)
Służy do losowego dostępu do elementów kolekcji. Zwraca element znajdujący się na liście pod określonym indeksem. Jeśli index < 0
lub jest index >=
maksymalną liczbą elementów na liście, zostanie zgłoszony wyjątek IndexOutOfBoundsException
. Jest to podstawowa metoda pobierania elementu z listy, a czas pobrania elementu według indeksu będzie zawsze taki sam, niezależnie od rozmiaru ArrayList, ponieważ uzyskuje on dostęp do określonej komórki tablicy. Znajdowanie indeksów dla określonych obiektów:
public int indexOf(Object o);
public int lastIndexOf(Object o);
Metody zwracają indeks pierwszego (przy pierwszym napotkaniu danego obiektu) lub ostatniego wystąpienia (przy ostatnim napotkaniu danego obiektu) elementu na liście. Jeśli elementu nie ma na liście, metody zwrócą -1.
public boolean isEmpty();
Metoda zwraca wartość true, jeśli lista jest pusta (sprawdza, czy pole jest równe size 0
), w przeciwnym razie false. Jeśli lista zawiera tylko elementy null, metoda zwróci wartość false. Innymi słowy, w tej metodzie uwzględniane są również elementy zerowe. Sprawdź liczbę elementów na liście:
public int size();
Zwraca liczbę elementów na liście (wartości pola rozmiaru). Liczba elementów może różnić się od pojemności listy (pojemności). Uzyskaj iterator dla listy:
public Iterator< E> iterator();
Zwraca iterator listy do późniejszego wykorzystania w pętli lub innym przetwarzaniu. Iterator implementuje zachowanie odporne na awarie. Jeśli przegląda kolekcję i zauważy w niej pewne modyfikacje (które nie zostały uzyskane przy użyciu metod iteratora), natychmiast zgłasza wyjątek ConcurrentModificationException
. Iterator ma coś, co nazywa się modification count
. Kiedy iterator wykonuje iterację po kolekcji po każdym z nich next/hasNext/remove
, sprawdza ten licznik. Jeśli nie pasuje do tego, co spodziewał się zobaczyć iterator, zgłasza wyjątek. Nie będę tutaj szczegółowo omawiał iteratorów.
public ListIterator< E> listIterator() и public ListIterator< E> listIterator(int index)
Zwraca iterator listy do późniejszego wykorzystania w pętli lub innym przetwarzaniu. Interfejs ListIterator
rozszerza interfejs Iterator
o dwukierunkowe poruszanie się po liście i modyfikację jej elementów. W wersji przeciążonej można przekazać indeks, od którego rozpocznie się „przechodzenie”. Indeks w tym przypadku oznacza pierwszy element, od którego metoda zacznie działać next()
, a gdy metoda zostanie wywołana, previous()
przechodzenie rozpocznie się od elementu znajdującego się pod indeksem „przekazany indeks - 1”.
public Spliterator <E> spliterator()
W Javie 8 wprowadzono nowy typ iteratora późnego wiązania i niezawodnego, zwany iteratorem ograniczników. Iteratory separatorów umożliwiają iterację po sekwencji elementów, ale używa się ich w inny sposób. Najważniejszą cechą interfejsu Spliteratora jest możliwość obsługi równoległej iteracji poszczególnych części ciągu elementów, a co za tym idzie programowania równoległego.
GO TO FULL VERSION