Programowanie w środowisku graficznym- wykład 7 Kolekcje (listy, zbiory)

Podobne dokumenty
Programowanie w Javie- wykład 12 Kolekcje (zbiory)

Programowanie w Javie- wykład 11 Kolekcje (listy)

Aplikacje w Javie wykład 7 Kolekcje (listy, zbiory)

Programowanie w języku Java. Kolekcje

Kolekcje mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Kolekcje - pakiet Java Collections Framework

java.util.* :Kolekcje Tomasz Borzyszkowski

Kolekcje - pakiet Java Collections Framework

Kolekcje. Na podstawie:

Programowanie Obiektowe (Java)

Programowanie obiektowe

Kolekcja (kontener) to po prostu obiekt, który grupuje wiele elementów w jeden twór.

Realizacja ekstensji klasy. Paulina Strzelecka, Tomasz Roszkowski

Java Collections Framework

Dawid Gierszewski Adam Hanasko

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

import java.util.*; public class ListExample { public static void main(string args[]) { List<String> lista1= new ArrayList<String> ();

Java niezbędnik programisty spotkanie nr 8. Kolekcje c.d.

Podstawy otwartych języków programowania Przechowywanie danych

Programowanie i projektowanie obiektowe

Kurs programowania. Wykład 9. Wojciech Macyna

Lista, Stos, Kolejka, Tablica Asocjacyjna

Wydział Fizyki i Informatyki Stosowanej, Uniwersytetu Łódzkiego Łódź. Java podstawy języka, wykład 4 1

Język JAVA podstawy. Wykład 4, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Tworzenie aplikacji w języku Java

KOLEKCJE JAVY API: NAJPROSTSZE PODSTAWY

Platformy Programistyczne Podstawy języka Java

Kolekcje w Javie cz. 1

Dokumentacja do API Javy.

Algorytmy i Struktury Danych. Anna Paszyńska

Java SE Laboratorium nr 7. Temat: Kolekcje

Wykład 4. Klasa List Kolejki Stosy Słowniki

dr inż. Piotr Czapiewski Tworzenie aplikacji w języku Java Laboratorium 1

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Aplikacje w Javie- wykład 11 Wątki-podstawy

Języki i metody programowania Java INF302W Wykład 3 (część 2)

Wykład 8: Obsługa Wyjątków

Aplikacje w Javie wykład 8 Kolekcje c.d. (komparatory, kolejki, mapy)

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Programowanie w Javie - wykład 13 Kolekcje c.d. ( mapy)

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

jlabel: void setalignment(label.center/left/right) - wyrównanie String gettext() pobiera aktualny tekst napisu void settext(string text) ustawia

Klasy i obiekty cz II

Laboratorium z przedmiotu Programowanie obiektowe - zestaw 04

Java niezbędnik programisty spotkanie nr 9. Java 2 Platform, Standard Edition 5.0

Programowanie obiektowe

Rozdział 4 KLASY, OBIEKTY, METODY

Wykład 3 Składnia języka C# (cz. 2)

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

GUI - projektowanie interfejsów cz. II

Języki i techniki programowania Ćwiczenia 4 Wzorce

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Podstawy i języki programowania

Podstawy obiektowości

Języki i techniki programowania Ćwiczenia 2

Kolekcje. object that groups multiple elements into a single unit

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne


Podstawy programowania. Podstawy C# Tablice

Interfejsy i klasy wewnętrzne

Kolekcje obiektów. Wyj tki.

PHP: bloki kodu, tablice, obiekty i formularze

API STREAM WYRAŻENIA LAMBDA

Programowanie obiektowe

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

TYPY GENERYCZNE (GENERICS)

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Wykład 5 Wybrane zagadnienia programowania w C++ (c.d.)

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Comparable<Klasa_uzytkownika>

Kompletna dokumentacja kontenera C++ vector w -

Programowanie i struktury danych

Typy sparametryzowane

Aplikacje Internetowe. Najprostsza aplikacja. Komponenty Javy. Podstawy języka Java

Szablony funkcji i klas (templates)

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Aplikacje w Javie wykład 8 Kolekcje c.d. (komparatory, kolejki, mapy)

Java Zadanie 1. Aby poprawnie uruchomić aplikację desktopową, należy zaimplementować główną metodę zapewniającą punkt wejścia do programu.

Kiedy potrzebne. Struktura (rekord) Struktura w języku C# Tablice struktur. struktura, kolekcja

2. Tablice. Tablice jednowymiarowe - wektory. Algorytmy i Struktury Danych

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Kontenery i iteratory. Wykorzystanie kontenerów w praktyce.

Wybrane algorytmy tablicowe

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Projektowanie aplikacji internetowych laboratorium

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Laboratorium z przedmiotu: Inżynieria Oprogramowania INEK Instrukcja 7

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Technologie i usługi internetowe cz. 2

Wykład 8: klasy cz. 4

Dziedziczenie. Tomasz Borzyszkowski

Instrukcja 2 Laboratorium z Podstaw Inżynierii Oprogramowania

Aplikacje w środowisku Java

Zadanie polega na stworzeniu bazy danych w pamięci zapewniającej efektywny dostęp do danych baza osób.

Język JAVA podstawy. wykład 2, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Java: otwórz okienko. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Transkrypt:

1 Programowanie w środowisku graficznym- wykład 7 Kolekcje (listy, zbiory) Treści prezentowane w wykładzie zostały oparte o: Barteczko, JAVA Programowanie praktyczne od podstaw, PWN, 2014 Barteczko, JAVA Uniwersalne techniki programowania, PWN, 2017 http://docs.oracle.com/javase/8/docs/ http://docs.oracle.com/javase/9/docs/ C. S. Horstmann, G. Cornell, Java. Podstawy, Helion, Gliwice 2013

KOLEKCJE 2 Kolekcja jest obiektem, który grupuje elementy danych (inne obiekty) i pozwala traktować je jak jeden zestaw danych, umożliwiając jednocześnie wykonywanie operacji na zestawie danych np. dodawania i usuwania oraz przeglądania elementów zestawu. Uwaga: W niektórych językach programowania kolekcje są nazywane kontenerami. W Javie kontenery są specjalnymi kolekcjami, które grupują komponenty graficznego interfejsu użytkownika (GUI). Naturalną realizacją koncepcji kolekcji są tablice. W języku Java tablice nie są jednak wygodnym sposobem tworzenia kolekcji ponieważ: nie posiadają dedykowanych metod do obsługi kolekcji, rozmiar tablicy jest stały. Dlatego w Javie, w pakiecie java.util, zdefiniowano narzędzia, służące do tworzenia i posługiwania się różnymi rodzajami kolekcji.

3 Architektura kolekcji (Collections Framework) Abstrakcyjne właściwości struktur danych opisywane są przez interfejsy kolekcyjne, a konkretne realizacje - inaczej implementacje kolekcji - tych właściwości znajdujemy w konkretnych klasach. Zunifikowana architektura, służąca do reprezentacji kolekcji i operowania na nich, składa się z: interfejsów, implementacji, algorytmów. Architektura kolekcji w Javie to: Java Collections Framework (JCF). Mamy tam do dyspozycji wiele gotowych, efektywnych klas i metod, pozwalających łatwo rozwiązywać wiele problemów związanych z reprezentacją w programie bardziej zaawansowanych struktur danych i operowaniem na nich. Klasy JCF dostarczają środków do posługiwania się następującymi rodzajami kolekcji: listy i ich szczególne przypadki: stosy, kolejki, kolejki podwójne. zbiory i zbiory uporządkowane, mapy tablice asocjacyjne (słowniki).

JCF- hierarchia interfejsów 4

Podstawowe interfejsy JCF Collection - dowolna kolekcja nie będącą mapą List - zestaw elementów, z których każdy znajduje się na określonej pozycji; do listy można wielokrotnie dodać ten sam element i można sięgnąć po element na dowolnej pozycji. Queue - kolejka, czyli sekwencja elementów, do której dodawanie i sięganie po elementy odbywa się na pozycjach, określonych przez zadany porządek (najczęsciej FIFO - first in first out). Nie ma bezpośredniego dostępu do dowolnej pozycji. Deque - rozszerza Queue: kolejka podwójna, do której dodawanie i sięganie może odbywać się na obu końcach (np. dodaj na początku, dodaj na końcu, usuń z początku, usuń z końca). Set - zestaw niepowtarzających się elementów, pozycje elementów są nieokreślone. SortedSet - rozszerza Set: zbiór uporządkowany NavigableSet - rozszerza SortedSet: zbiór uporządkowany, dla którego możliwe są operacje uzyskiwania elementów "bliskich" danemu. Map mapa (tablica asocjacyjna, słownik) - zestaw par: klucz-wartość, przy czym odwzorowanie kluczy w wartości jest jednoznaczne SortedMap - mapa z uporządkowanymi kluczami (typu SortedSet) NavigableMap - mapa, w której klucze są typu NavigableSet 5

Wybrane podstawowe konkretne implementacje Implementowany interfejs Implementujące klasy Sposób realizacji właściwości określanych przez interfejs List ArrayList Dynamicznie rozszerzalna tablica (szybki bezpośredni dostęp po indeksach) List, Queue, Deque LinkedList Lista liniowa z podwójnymi dowiązaniami (szybkie wpisywanie i usuwanie elementów poza końcem listy; wolny dostęp bezpośredni; implementacja operacji na kolejkach) Queue, Deque ArrayDeque Kolejka podwójna (zrealizowana jako rozszerzalna tablica; szybki dostęp do obu końców, brak dostępu do dowolnej pozycji) Queue PriorityQueue Kolejka z priorytetami (kolejka, w której pierwszy i ostatni elment jest określany na podstawie ustalonego porządku (porównania elmentów wg kryteriów) ) Set HashSet Tablica haszująca (mieszania) (szybkie wpisywanie (add) i odnajdywanie elementów(contains); kolejność elementów nieokreślona) Set, SortedSet, NavigableSet TreeSet Drzewo czerwono-czarne, szybkie wstawianie, (uporządkowanie elementów; dostęp i wyszukiwanie wolniejsze niż w implementacji mieszającej) Set LinkedHashSet Tablica mieszania i lista liniowa (jak w implememntacji mieszającej, z zachowaniem porządku wpisywania elementów) 6

Ogólne operacje na kolekcjach- interfejs Collection Interfejs Collection definiuje wspólne właściwości i funkcjonalność wszystkich kolekcji (tzn. list, zbiorów i innych) poza mapami. Typ Collection jest zatem swoistym "najmniejszym wspólnym mianownikiem" wszystkich rodzajów kolekcji i używamy go (szczególnie przy przekazywaniu argumentów) wtedy, gdy potrzebna jest największa ogólność działań. Podstawowe operacje na kolekcjach: int size() - zwraca liczbę elementów zawartych w kolekcji boolean isempty() - sprawdza, czy kolekcja jest pusta boolean contains(object o) - sprawdza, czy kolekcja zawiera podany obiekt. boolean add(object o) - dodaje obiekt o do kolekcji. (Uwaga: operacja opcjonalna nie jest dozwolona dla kolekcji niemodyfikowalnych) boolean remove(object o) - usuwa obiekt o z kolekcji. (Uwaga: operacja opcjonalna nie jest dozwolona dla kolekcji niemodyfikowalnych) Kolekcja jest modyfikowalna, jeśli można dodawać do niej elementy, usuwać z niej elementy oraz zmieniać wartości elementów. Niemodyfikowalne kolekcje nie pozwalają na dodawanie, usuwanie i zmianę wartości elementów. 7

Ogólne operacje na kolekcjach Operacje opcjonalne. Konkretne klasy kolekcyjne mogą dopuszczać lub nie wykonanie takich operacji. Np. klasa definiująca jakąś kolekcję niemodyfikowalną nie może pozwolić na wykonanie operacji dodawania i usuwania elementów. Ale ponieważ każda klasa kolekcyjna musi implementować interfejs Collection, to musi też zdefiniować metody add i remove. Przyjęto zasadę, że jeśli operacja opcjonalna dla danej implementacji nie jest dopuszczalna, to odpowiednia metoda zglasza wyjątek UnsupportedOperationException: public boolean add(t o) { throw new UnsupportedOperationException(); public boolean remove(t o) { throw new UnsupportedOperationException(); Uwaga: ponieważ kolekcje są sparametryzowane, T oznacza parametr typu. Przy dodawaniu elementów do kolekcji mogą powstać i inne wyjątki, zależne od implementacji kolekcji. Implementacje, które nie dopuszczają dodawania elementów o pewnych właściwościach (np. elementów null) będą zgłaszać wyjątek IllegalArgumentException. Te zaś, które np. czasowo nie dopuszczają dodania elementu (np. w tym momecie jest przekroczony maksymalny limit wielkości kolekcji) zgłaszają wyjątek IllegalStateException. 8

Operacje grupowe na kolekcjach Operacje grupowe na kolekcjach polegają na wykonywaniu za jednym razem pewnych operacji na całych kolekcjach. Należą do nich metody: boolean addall(collection<? extends E> c) - dodanie do dowolnej kolekcji wszystkich elementów kolekcji przekazanej przez parametr c boolean removeall(collection<?> c) - usunięcie z kolekcji wszystkich elementów, które są zawarte w kolekcji przekazanej przez parametr c boolean retainall(collection<?> c)- pozostawienie w kolekcji tylko tych elementów, które są zawarte w kolekcji przekazanej przez parametr c void clear()- usunięcie wszystkich elementów kolekcji. Object [] toarray()- zwraca tablicę obiektów zawartych w kolekcji. Ponieważ niektóre z tych operacji mogą modyfikować kolekcje (a o tym czy naprawdę nastąpiła modyfikacja - świadczą wyniki zwracane przez metody - true albo false), to - oczywiście - są one operacjami opcjonalnymi. UWAGA! Operacje, które wymagają porównywania elementów np. contains(jakis_obiekt), containsall(collection, removeall(..), retainall(...) używają do tego metody equals() zdefiniowanej w klasach obiektów. 9

Przekształcanie kolekcji w inne kolekcje 10 Niejako kontynuacją operacji grupowych jest możliwość przekształcenia kolekcji danego rodzaju w dowolną inną kolekcję dowolnego innego rodzaju. Np. listy w zbiór uporządkowany. We wszystkich konkretnych implementacjach kolekcji dostarczono konstruktorów, mających jako parametr dowolną inną kolekcję (czyli parametr typu Collection). Jeśli zatem mamy listę, a chcemy z niej zrobić zbiór uporządkowany (w konkretnej implementacji - np. drzewa zrównoważonego), to wystarczy użyć konstruktora odpowiedniej klasy (tu: TreeSet): List lista; //utworzenie listy w konkretnej implementacji //np.arraylist lub LinkedList Set tset = new TreeSet(lista); W ten sposób uzyskamy zbiór (a więc bez powtórzeń elementów), uporządkowany (w naturalnym porządku elementów), którego elementy będą pobrane z dostarczonej listy. Oczywiście, jeśli nie stosujemy typów surowych (jak wyżej), ale kolekcje sparametryzowane, kompilator zabroni nam dokonywania pewnych przekształceń (np. uzyskania listy napisów List<String> ze zbioru liczb Set<Integer>).

Iteratory Bardzo ważną metodą interfejsu Collection (tak naprawdę dziedziczoną z interfejsu Iterable) jest metoda iterator(), która zwraca iterator. Iterator jest obiektem klasy implementującej interfejs Iterator<T> i służy do przeglądania elementów kolekcji oraz ew. usuwania ich przy przeglądaniu Metody interfejsu Iterator<T>: T next() - zwraca kolejny element kolekcji lub sygnalizuje wyjątek NoSuchElementException, jeśli osiągnięto koniec kolekcji. T jest typem elementów kolekcji. void remove() - usuwa element kolekcji, zwrócony przez ostatnie odwołanie do next(). Operacja opcjonalna. boolean hasnext()- zwraca true, jeśli możliwe jest odwołanie do next() zwracające kolejny element kolekcji. Klasy iteratorów są definiowane w klasach kolekcyjnych jako klasy wewnętrzne, implementujące interfejs Iterator<T>. Implementacja metody iterator() z interfejsu Collection zwraca obiekt takiej klasy. Dzięki temu od każdej kolekcji możemy uzyskać iterator za pomocą odwołania: Iterator<T> iter = c.iterator(); gdzie: c - dowolna klasa implementująca interfejs Collection, T - typ elmentów kolekcji. 11

12 Iteratory Dla tych kolekcji, w których elementy nie zajmują ściśle określonych pozycji iteratory są jedynym sposobem na "przebieganie" po kolekcji. Dla kolekcji listowych iteratory są efektywniejszym narzędziem iterowania od pętli iteracyjnych pobierających elementy z pozycji wyznaczanych przez podane indeksy. O iteratorze należy myśleć jako o wskaźniku ustawianym nie na elemencie kolekcji, ale pomiędzy elementami. Na początku iterator ustawiony jest przed pierwszym elementem. Odwołanie next() jednocześnie przesuwa iterator za element i zwraca ten element. Metoda iteratora remove() najczęściej stosowana jest do usuwania z kolekcji elementów, które spełniają (nie spełniają) jakichś warunków. Szablon użycia remove() w trakcie iteracji: Iterator<T> iter = c.iterator(); // c - dowolna kolekcja //typu Collection, T - typ elementów kolekcji while (iter.hasnext()) { T element = iter.next(); if (warunek_usunięcia(element)) iter.remove(); Metoda remove() może usunąć tylko element zwrócony przez next() i wobec tego może być zastosowana tylko raz dla każdego next(). W trakcie iteracji za pomocą iteratora nie wolno modyfikować kolekcji innymi sposobami niż użycie metody remove() na rzecz iteratora!

Listy (interfejs List) LISTA - zestaw elementów, z których każdy znajduje się na określonej pozycji w zestawie. Różne elementy listy mogą zawierać takie same dane. JDK posiada kilka implementacji interfejsu List, różniących się sposobem przechowywania elementów. W klasie ArrayList stosuje się tablicę, która jest dynamicznie zwiększana w momencie przekroczenia jej maksymalnego rozmiaru. Elementy listy są zapisywane jako elementy takiej tablicy. Ponieważ tablice w Javie mają określone (niezmienne po utworzeniu) rozmiary utworzenie listy tablicowej wymaga alokacji tablicy z jakimś zadanym rozmiarem. Jest on specyfikowany przez initialcapacity (domyślnie 10), który to parametr możemy podać w konstruktorze ArrayList. Przy dodawaniu elementów do listy sprawdzane jest czy pojemność tablicy jest wystarczająca, jeśli nie to rozmiar tablicy jest zwiększany. Służy temu metoda ensurecapacity(mincapacity), którą zresztą możemy wywołać sami, aby w trakcie działania programu zapewnić podaną jako mincapacity pojemność listy. 13

Listy 14 Klasa LinkedList jest klasyczną listą łączoną, w której każdy element posiada referencję do poprzedniego i następnego elementu listy. Zatem elementy listy, które z punktu widzenia programisty są elementami umieszczanych danych (np. nazwisk lub jakichś innych obiektów), technicznie są "linkami", zawierającymi nie tylko dane, ale również wskaźniki na następny i poprzedni element na liście. Początek listy dowiązaniowej, zwany głową lub wartownikiem zawiera wskazanie na pierwszy element listy (null, jeśli lista jest pusta). Klasa Vector jest przepisaną na nowo wersją znaną z JDK 1.0. Jest obecna w bibliotece Java Collections tylko ze względu na potrzebę wstecznej zgodności.

Listy porównanie klas Te dwie implementacje charakteryzują się różną wydajnością, ale można stosować je zamiennie: LinkedList powinniśmy wybierać wtedy, gdy na liście będą wykonywane częste operacje wstawiania i/lub usuwania elementów w środku listy (poza końcem listy). Istotnie na liście typu LinkedList takie operacje polegają na zmianie dwóch dowiązań (prowadzącego do poprzedniego i do następnego elementu) - są więc bardzo szybkie, zaś w implementacji tablicowej (ArrayList) wiążą się z przepisywaniem elementów tablicy, co (zwykle) zabiera więcej czasu. Operacje bezpośredniego dostępu do elementów listy są w implementacji tablicowej ArrayList natychmiastowe (polegają na indeksowaniu tablicy), natomiast w implementacji LinkedList są bardzo nieefektywne, gdyż technicznie wymagają przebiegania po elementach listy od samego jej początku lub od końca w kierunku początku (ten ostatni przypadek jest jedyną optymalizacją dostępu w klasie LinkedList, dokonywaną wtedy, gdy indeks znajduje się "w drugiej połowie" listy). Na listach LinkedList należy unikać operacji get(int index) i set(int index, Object value) Wyszukiwanie elementów na listach (czy to klasy ArrayList czy LinkedList) za pomocą ogólnych metod interfejsu Collection (contains(object)) oraz interfejsu List indexof(object)) nie jest efektywne. Powinniśmy albo zastosować inny rodzaj kolekcji (np. zbiory w implementacji tablic mieszania), albo posortować listę (metoda sort) i zastosować wyszukiwanie binarne (metoda binarysearch) (są to metody klasy Collections). 15

16 Operacje na listach wszystkie metody interfejsu Collection boolean add(int p, T elt) - dodaje element typu T na pozycji p. Zwraca true jeśli lista została zmodyfikowana. boolean addall(int p, Collection c)- dodaje wszystkie elementy kolekcji c do listy poczynając od pozycji p. Zwraca true jeśli lista została zmodyfikwoana. T get(int p)- zwraca element na pozycji p (T jest typem elementu) int indexof(t elt)- zwraca pozycję (indeks) pierwszego wystąpienia elementu elt int lastindexof(t elt)- zwraca indeks ostatniego wystąpienia elementu elt ListIterator<T> listiterator()- zwraca iterator listowy, ustawiony na początku listy (przed pierwszym elementem). ListIterator<T> listiterator(int p)- zwraca iterator listowy ustawiony przed elementem o indeksie p. boolean remove(int p)- usuwa element na pozycji p. Zwraca true jeśli lista została zmodyfikowana. T set(int p, T elt)- zastępuje element na pozycji p podanym elementem elt. Zwraca poprzednio znajdujący się na liście element. List<T> sublist(int f, int l) - zwraca podlistę zawierającą elementy listy od pozycji f włącznie do pozycji l (wyłącznie).

17 ListIterator Operacje na liście rozszerzają możliwości operowania na kolekcjach o operacje pozycyjne - takie, które uwzględniają pozycję elementów. Ze względu na znajomość pozycji elementów w kolekcji możliwe staje się iterowanie po kolekcji w obie strony: od początku i od końca. Można też ustawić iterator w taki sposób, by iteracje rozpoczynały się od podanej pozycji, a znając pozycję elementu zwracanego przez iterator można nie tylko go usunąć, ale zamienić lub dodać nowy element na pozycji wyznaczanej przez stan iteratora. Dlatego właśnie oprócz zwykłego (ogólnego dla wszystkich kolekcji) iteratora, listy udostępniają iteratory listowe, które są obiektami klas implementujących interfejs ListIterator. Ten ostatni jest rozszerzeniem interfejsu Iterator Metody iteratora listowego : boolean hasnext(), boolean hasprevious(), Object next(), Object previous(), int nextindex(), int previousindex(), void add(t o), void remove(), void set(t o)

ArrayList przykład-listy surowe Przykład: Rozważmy program, który tworzy listę firm, dodaje do niej dowolną liczbę elementów (nazw firm zapisanych w kolejnych wierszach pliku), po czym wyprowadza zawartość listy na konsolę. W programie możemy przedstawić ją jako tablicę, ale nie wiadomo jaki ma mieć rozmiar, dlatego skorzystamy z listy. import java.util.*; import java.io.*; class Intro1 { public static void main(string args[]) throws IOException { Scanner scan = new Scanner(new File("firms.txt")); // Utworzenie obiektu klasy ArrayList ArrayList list = new ArrayList(); while (scan.hasnextline()) { String firm = scan.nextline(); // dodanie kolejnego elementu do listy list.add(firm); // wyprowadzenie zawartości listy for (int i = 0; i < list.size(); i++) System.out.println(list.get(i)); 18

Listy Iterator 19 Lepszym sposobem przeglądania elementów listy jest skorzystanie z iteratora. W naszym przykładzie listy firm użycie iteratora może wyglądać następująco: for (Iterator iter = list.iterator();iter.hasnext(); ) System.out.println(iter.next()); Najlepiej jednak jest używać rozszerzonego for (for-each): for (Typ id : kol) instr co oznacza, że w każdym kroku iteracji z kolekcji kol pobierany jest (za pomocą jej iteratora) następny element i podstawiany pod zmienną id, która może być następnie użyta w instrukcji instr. Typ natomiast zależy od tego czy używamy kolekcji sparametryzowanych typami czy też kolekcji surowych. Surowe kolekcje mogą zawierać referencje do dowolnych obiektów (ich elementy są formalnie typu Object). Metoda next() iteratorów takich kolekcji ma typ wyniku Object. W przedstawionym przykładzie listy mamy właśnie do czynienia z taką surową kolekcją. Zarówno iterator, jak i metoda get() zwracają wyniki typu Object.

Listy - bez parametryzacji 20 Powinniśmy więc napisać: for (Object elt : list) System.out.println(elt); Zauważmy, że przekazanie metodzie println argumentu typu Object powoduje wyprowadzenie napisu zwróconego przez metodę tostring() z klasy argumentu. Nie mieliśmy więc kłopotu z faktycznym typem (którym był String). Jednak gdyby w powyższym przykładzie chcieć wywołać na rzecz zmiennej elt np. metodę length() z klasy String, to kompilator zgłosiłby błąd (statyczna ścisła kontrola typów: istotnie w klasie Object - a takiego typu jest elt - nie ma metody length()!). Musielibyśmy więc dokonywać referencyjnej konwersji zawężającej : // Wypisuje długości napisów z kolekcji list for (Object elt : list) System.out.println( ((String) elt).length());

Listy sparametryzowane 21 Użycie kolekcji sparametryzowanych polega na podaniu typu jej elementów w nawiasach kątowych np. ArrayList<String> list = new ArrayList<>(); Do tak zdefiniowanej kolekcji, korzystając ze zmiennej list, nie będzie można dodać elementu innego typu niż String, a także wszelkie metody zwracające elementy tej kolekcji (m.in. get() oraz next() iteratora) będą miały typ wyniku String. W tym przypadku typ zmiennej w rozszerzonym for może być String i wobec tego możemy pisać tak: ArrayList<String> list = new ArrayList<>(); //... // Wypisuje długości napisów z kolekcji list for (String elt : list) System.out.println(elt.length());

Listy sparametryzowane 22 Uwaga. Z powodu słabości typów generycznych, dla sparametryzowanej kolekcji: List<String> list = new ArrayList<>(); dokonując przypisania List hackedlist = list; możemy do powyższej listy obiektów typu String dodawać obiekty również innych typów, np.: hackedlist.add(10); //Integer hackedlist.add(new Date()); //Date gdyż metoda add na hackedlist oczekuje parametru typu Object, a nie String (wynika to z wewnętrznej reprezentacji RAW typów generycznych). Wówczas użycie obiektu z takiej kolekcji zgodnie z jej typem, np. String s = list.get(0); skompiluje się, ale podczas uruchomienia wyrzuci wyjątek ClassCastException informując, że próbuje się rzutować Integer na String.

Listy sparametryzowane 23 Aby zabezpieczyć kolekcję przed dopisywaniem "nieuprawnionych" obiektów możemy wykorzystać specjalnie do tego celu stworzone klasy opakowujące, których instancje otrzymujemy poprzez uruchomienie wybranych metod klasy Collections. Np. dla listy: List<String> list = Collections.checkedList( new ArrayList<>(), String.class); Metoda checkedlist bierze dwa parametry opakowywaną listę oraz klasę elementów tej listy, a zwraca nowy obiekt listę opakowującą (view), która sprawdza każdy dopisywany do niej obiekt (czyli właściwie do wyjściowej listy) pod kątem jego typu. W klasie Collections są zdefiniowane również analogiczne metody dotyczące innych typów kolekcji.

ArrayList przykład poprawiony 24 import java.util.*; import java.io.*; class Intro1Param { public static void main(string args[]) throws IOException { Scanner scan = new Scanner(new File("firms.txt")); // Utworzenie obiektu klasy ArrayList ArrayList<String> list = new ArrayList<>(); while (scan.hasnextline()) { String firm = scan.nextline(); // dodanie kolejnego elementu do listy list.add(firm); // wyprowadzenie zawartości listy for (String el : list) System.out.println(el);

Zbiory (interfejs Set) 26 Zbiór jest kolekcją, reprezentującą zestaw niepowtarzających się elementów. W zbiorze elementy nie mają pozycji. Nie jest możliwy dostęp do elementów zbioru po indeksach. O elemencie zbioru można zatem powiedzieć jedynie, czy należy do zbioru (w jednym egzemplarzu), czy nie. Zatem zbiór posiada, odmienną niż lista, semantykę: nie zachowuje kolejności elementów, natomiast wyklucza istnienie duplikatów. Interfejs Set nie definiuje żadnych nowych metod w porównaniu do interfejsu Collection. Jedyne uszczegółowienie polega na tym, że w przypadku zbiorów, metody dodające elementy do zbiorów zwracają wartość false, jeśli dodawane elementy już w zbiorze występują. Podobnie, jak w przypadku listy, zbiór posiada w JDK kilka gotowych implementacji. Jedną z nich jest HashSet, w którym unikatowość elementów jest zapewniona przez zastosowanie tablicy haszującej (mieszającej); natomiast w przypadku klasy TreeSet poprzez wyszukiwanie binarne z użyciem drzewa czerwono-czarnego (drzewo dwukolorowe).

Zbiory - HashSet 27 Przykład. Zauważmy, że jeśli w pliku firm dwa razy powtórzono tę samą nazwę, to co zrobić, jeśli chcemy mieć wynikowy zestaw firm bez powtórzeń nazw? Oczywiście, można własnoręcznie oprogramować sprawdzanie elementów zestawu i usuwać z niego duplikaty. Ale po co, jeśli istnieje prostszy sposób - zastosowanie kolekcji typu zbiór. Możemy np. użyć konkretnej klasy realizującej koncepcję zbioru nieuporządkowanego - klasy HashSet. Zwróćmy uwagę, że: w zbiorze elementy nie mają pozycji. Przy przeglądaniu możemy zatem zastosować wyłącznie iterator (dostęp "po indeksach" nie jest możliwy). porządek iterowania (przeglądania) zbioru nie jest określony (kolejność wyprowadzonych wyników może być inna niż kolejność firm w pliku).

Zbiory - HashSet - przykład 28 class Intro2 { public static void main(string args[]) throws IOException { Scanner scan = new Scanner(new File("firms.txt")); // Utworzenie obiektu klasy HashSet // z parametrem typu <String> HashSet<String> set = new HashSet<>(); while (scan.hasnextline()) { String firm = scan.nextline(); // dodanie kolejnego elementu do zbioru set.add(firm); // wyprowadzenie zawartości zbioru for (String elt : set) System.out.println(elt);

Zbiory - TreeSet Przykład. Co zrobić, jeśli od naszego programu wymagane jest wyprowadzenie uporządkowanego zestawu firm np. w alfabetycznym porządku? Możemy zastosować kolekcję stanowiącą zbiór uporządkowany. W zbiorze uporządkowanym kolejność przeglądania jego elementów za pomocą iteratora jest określona (np. w rosnącym porządku alfabetycznym nazw firm, będących elementami zbioru). Konkretną realizacją zbioru uporządkowanego jest w Javie klasa TreeSet. import java.util.*; import java.io.*; class Intro3 { public static void main(string args[]) throws IOException { Scanner scan = new Scanner(new File("firms.txt")); TreeSet<String> set = new TreeSet<>(); while (scan.hasnextline()){ set.add(scan.nextline()); for (String elt : set) System.out.println(elt); 29

Zbiory - HashSet Tablica mieszająca (haszująca - ang. hashtable) jest strukturą danych specjalnie przystosowaną do szybkiego odnajdywania elementów. Dla każdego elementu danych wyliczany jest kod numeryczny (liczba całkowita) nazywany kodem mieszania (hashcode), na podstawie którego obliczany jest indeks w tablicy, pod którym będzie umieszczony dany element. Może się zdarzyć, że kilka elementów otrzyma ten sam indeks, zatem elementy tablicy mieszającej stanowią listy, na których znajdują się elementy danych o takim samym indeksie, wyliczonym na podstawie ich kodów mieszania. Każda lista - element tablicy mieszania nazywa się kubełkiem (bucket). Aby umieścić nowy element w tablicy mieszania, wyliczany jest jego hashcode, po czym na podstawie jego wartości obliczany jest indeks w tablicy mieszania. Indeks taki stanowi resztę z dzielenia wartości kodu mieszania przez liczbę kubełków. Element umieszczany jest w kubełku pod tym indeksem. Istotne jest w tej procedurze, by: wyliczanie kodu mieszania było szybkie, kody mieszania dla rożnych elementów zależały tylko od ich wartości i były (możliwie) różne dla różnych wartości elementów, wynikowe indeksy dawały możliwie równomierną dystrybucję elementów danych po elementach tablicy mieszania. 30

Zbiory - hashtable W Javie można wyliczyć kod mieszania dla każdego obiektu za pomocą zastosowania metody hashcode(). Metoda ta, zdefiniowana w klasie Object, daje - ogólnie - jako wynik adresy obiektów. To, oczywiście, nie jest zbyt użyteczne, bowiem nie bierze pod uwagę zawartości obiektów (wszystkie obiekty mają rożne kody mieszania). Ale w standardowych klasach Javy metoda hashcode() została przedefiniowana, tak, by zwracała kod na podstawie "treści" obiektu, np. napisu stanowiącego "zawartość" obiektu klasy String. Dwa takie same napisy będą miały te same kody mieszania. Wyszukanie elementu w tablicy mieszania jest bardzo efektywne. Wystarczy obliczyć indeks tablicy na podstawie kodu mieszania szukanego elementu i jeżeli w danym kubełku jest tylko jeden element, to - nawet nie wykonując żadnych porównań - zwrócić ten element (lub wartość true - że jest). Jeżeli w kubełku jest kilka elementów, to musimy wykonać ich porównanie z szukanym elementem (equals(...)), ale i tak liczba porównań będzie zwykle bardzo niewielka w stosunku do liniowego czy nawet binarnego wyszukiwania. Klasa HashSet wykonuje to np. przy wywołaniu metod add(obiekt), remove(obiekt). Oprócz wyliczania kodów mieszania do prawidłowego dodawania i odnajdywania elementów potrzebne jest odpowiednie zdefiniowanie metody equals(), porównującej "treść" dwóch obiektów. 31

Zbiory HashSet Jeżeli prawdziwe jest a.equals(b), to musi być spełniony warunek a.hashcode() == b.hashcode(). Zarówno hashcode() jak i equals() są dobrze zdefiniowane w standardowych klasach Javy, natomiast tworząc własne klasy musimy sami zadbać o właściwe ich zdefiniowanie. Należy pamiętać, że przedefiniowujemy metodę equals z klasy Object. A tam jej parametrem jest Object. Użycie innego typu parametru prowadzi do przeciążenia (a nie przedefiniowania) metody i uniemożliwia polimorficzne do niej odwołania. Metodę hashcode definiujemy w klasie jako: public int hashcode() { //obliczenie kodu mieszania na podstawie wartości pól klasy //dla pól obiektowych użyjemy metody hashcode() z ich klas Środowiska uruchomieniowe IDE (m.in. NetBeans) dają możliwość automatycznej generacji kodów metod hashcode() i equals() poprzez wybór opcji z menu. Porządek elementów kolekcji HashSet nie jest określony. Klasa LinkedHashSet, dziedzicząc klasę HashSet udostępnia wygodną często właściwość: zachowania porządku, w jakim elementy dodane były do zbioru. 32

Zbiory TreeSet Inna podstawowa implementacja koncepcji zbioru - klasa TreeSet, opiera się na strukturze danych zwanej drzewem czerwono-czarnym. Dla potrzeb korzystania z klasy TreeSet wystarczy wiedzieć, że zapewnia ona szczególne uporządkowanie elementów zbioru, które pozwala szybko odnajdywać w nim podany element. Klasa TreeSet realizuje nie tylko koncepcję zbioru "w ogóle", ale również zbioru uporządkowanego, implementując interfejs SortedSet (ściślej NavigableSet), który rozszerza interfejs Set. Widzieliśmy już jak iterowanie po TreeSet zwraca elementy w porządku rosnącym. Np. poniższy fragment: String[] s = {"ala", "pies", "kot"; Set<String> set = new TreeSet<>(); for (int i=0; i < s.length; i++) set.add(s[i]); System.out.println(set.toString()); wypisze: [ala, kot, pies] Do zbiorów należy dodawać tylko referencje do obiektów niemodyfikowalnych, w przeciwnym razie zbiór może stracić spójność po ewentualnej zmianie zawartości obiektu (może zawierać identyczne obiekty) 33

Kolekcje przykład proste sortowanie TreeSet zapewnia uporządkowanie elementów kolekcji, ale usuwa duplikaty. Co zrobić, jeśli chcemy duplikaty zachować i posortować kolekcję? Zachowanie duplikatów zapewnia lista (np. ArrayList). Możemy wobec niej zastosowac gotowy algorytm sortowania zapisany w postaci statycznej metody klasy Collections (klasa ta zawiera metody realizujące rózne algorytmy działania na kolekcjach). import java.util.*; import java.io.*; class Intro4 { public static void main(string args[]) throws IOException { Scanner scan = new Scanner(new File("firms.txt")); ArrayList<String> list = new ArrayList<>(); while (scan.hasnextline()){ list.add(scan.nextline()); Collections.sort(list); for (String firm : list) { System.out.println(firm); //wyprowadzi firmy w rosnącym alfabetycznym porządku ich nazw 34

Porównywanie obiektów 35 Dodawanie elementów do zbiorów uporządkowanych (np. TreeSet), iterowanie po kolekcjach uporządkowanych, pobieranie elementów z kolejek z priorytetami, a także sortowanie kolekcji i tablic algorytmami kolekcyjnymi odbywa się w oparciu o: naturalny porządek obiektów, lub reguły porównywania obiektów określane przez komparator - obiekt klasy implementującej interfejs Comparator. Naturalny porządek określany jest przez implementację interfejsu Comparable<T> w klasie obiektów i dostarczenie definicji metody compareto tego interfejsu, porównującej dwa obiekty typu T. Metoda compareto ma następującą sygnaturę: public int compareto(t otherobject) gdzie T jest typem obiektu, i zwraca: liczbę < 0, jeżeli ten obiekt (this) znajduje się (w porządku) przed obiektem otherobject, liczbę > 0, jeżeli ten obiekt (this) znajduje się (w porządku) po obiekcie otherobject, 0, jeśli obiekty są takie same.

Porównywanie obiektów Wiele standardowych klas Javy implementuje interfejs Comparable (np. klasa String, Date, klasy opakowujące typy proste). We własnych klasach musimy o to zadbać sami. Zatem, każda nasza klasa, której obiekty mogą być elementami kolekcji uporządkowanych powinna określać naturalny porządek swoich obiektów. Np. w klasie Worker moglibyśmy ustalić, że naturalną kolejnością obiektów jest alfabetyczna kolejność nazwisk w porządku rosnącym poprzez dostarczenie definicji metody compareto: class Worker implements Comparable<Worker> { private String lname; private String fname; private int salary; //... public int compareto(worker other) { int res = lname.compareto(other.lname); if(res==0) res = fname.compareto(other.fname) return res; public String tostring() { return fname + " " + lname + " " + salary; 36

Porównywanie obiektów Po wykorzystaniu powyższej klasy w poniższym fragmencie: Worker[] p = { new Worker("Jan", "Kowalski", 1000), new Worker("Jan", "Malinowski", 1200), new Worker("Jan", "Kowalski", 1400), new Worker("Jan", "Kowalewski", 2000), ; Set<Osoba> set = new TreeSet<>(); for (Worker w : p) set.add(w); System.out.println(set); otrzymamy (naturalnie) uporządkowany wynik: [Jan Kowalewski 2000, Jan Kowalski 1000, Jan Malinowski 1200] 37

Porównywanie obiektów - komparator 38 Aby uzyskać zbiory uporządkowane według różnych kryteriów, np. według nazwisk lub według pensji, albo porządek odwrotny (np. w malejącym alfabetycznym porządku nazwisk) należy skorzystać z komparatora. Komparator jest obiektem porównującym inne obiekty. Komparatory w Javie są realizowane jako obiekty klas implementujących interfejs Comparator<T>, gdzie T jest typem porównywanych obiektów Interfejs ten zawiera metodę: int compare(t o1, T o2) której implementacja winna porównywać dwa swoje argumenty i zwracać: wynik 0 jeśli oba obiekty są równe, liczbę mniejszą od 0, jeśli o1 jest "mniejszy" od o2 liczbę większą od 0, jeśli o1 jest "większy" od o2. Obiekt komparator może być podany jako argument konstruktora klasy TreeSet (wtedy to on, a nie naturalny porządek, decyduje o sposobie wpisywania elementów do zbioru), może rownież występować jako argument metod sortowania z klasy Collections i Arrays, konstruktorów klasy PriorityQueue oraz konstruktorów innych kolekcji uporządkowanych (np. TreeMap). Specjalny komparator, odwracający naturalny porządek, uzyskiwany jest za pomocą statycznej metody klasy Collections - Collections.reverseOrder().

Porównywanie obiektów - przykład 39 import java.util.*; class Worker implements Comparable<Worker> { private String lname; private String fname; private int salary; public Worker(String fn, String ln, int sal) { lname = ln; fname = fn; salary = sal; public int getsalary() { return salary; public int compareto(worker other) { int res = lname.compareto(other.lname); if(res==0) res = fname.compareto(other.fname); return res; public String tostring() { return fname + " " + lname + " " + salary;

Porównywanie obiektów - przykład 40 public class TestKomparator { public static void main(string args[]) { Worker[] workers = { new Worker("Jan", "Kowalski", 1000), new Worker("Jan", "Malinowski", 1200), new Worker("Jan", "Kowalski", 1400), new Worker("Jan", "Kowalewski", 2000), new Worker("Stefan", "Zwierz", 2000), ; // Zbiór uporządkowany wg porządku naturalnego //(rosnąca kolejność nazwisk) Set<Worker> set = new TreeSet<>(); for (Worker w : workers) set.add(w); System.out.println(set); //[Jan Kowalewski 2000, Jan Kowalski 1000, // Jan Malinowski 1200, Stefan Zwierz 2000]

Porównywanie obiektów - przykład 41 // Zbiór uporządkowany wg rosnących pensji Set<Worker> set2 = new TreeSet<>( new Comparator<Worker>() { public int compare(worker o1, Worker o2) { // różnica pensji wystarczy do porownania: return o1.getsalary() - o2.getsalary(); ); for (Worker w : workers) set2.add(w); System.out.println(set2); //[Jan Kowalski 1000, Jan Malinowski 1200, // Jan Kowalski 1400, Jan Kowalewski 2000] // Zbiór uporządkowany w malejącym porządku naturalnym //(malejące nazwiska) Set<Worker> set3 = new TreeSet<>(Collections.reverseOrder()); for (Worker w : workers) set3.add(w); System.out.println(set3); //[Stefan Zwierz 2000, Jan Malinowski 1200, //Jan Kowalski 1000, Jan Kowalewski 2000]

Porównywanie obiektów 42 W powyższym przykładzie w klasie Worker nie definiowaliśmy metody equals() ani hashcode(), gdyż TreeSet ich nie potrzebuje. Zwróćmy uwagę, że komparator przesądza nie tylko o kolejności iterowania po zbiorze, ale również o tym, czy obiekty uznawane są za różne i czy wobec tego mogą stanowić elementy zbioru (przykład z powtórzeniem nazwiska Jan Kowalski i utrata Stefana Zwierza, gdy komparator porównywał pensje), Należy pamiętać, że: Operacje na zbiorze HashSet używają (i wymagają) metod hashcode() i equals(), a dodawanie i wyszukiwanie elementów odbywa się w oparciu o wyniki metody equals(). Operacje na zbiorze TreeSet odbywają się w oparciu o wyniki metody compareto() lub metody compare() komparatora. Oczywiście, nasze klasy powinny być przygotowane do tego, że ich obiekty mogą znaleźć się w zbiorach typu HashSet albo TreeSet, zatem powinny definiować wszystkie wspomniane metody. A do tego w sposob spójny: jeśli equals zwraca true, to compareto winno zwracać zero, a hashcode te same wartości dla obu porównywanych obiektów.

Porównywanie obiektów Warto zauważyć, że dla zbiorów uporządkowanych (naturalnie lub za pomocą komparatora) dostępna jest możliwość uzyskiwania "pierwszego" lub "ostatniego" (w zdefiniowanym porządku) elementu, a także podzbiorów, które zawierają elementy "od" - "do" (w zdefiniowanym porządku). Służą temu metody interfejsu SortedSet (pośrednio implementowanego przez TreeSet) m.in. headset(), tailset() i subset(), Interfejs NavigableSet bezpośrednio implementowany przez TreeSet dostarcza dodatkowych metod m.in. higher(e e), lower(e e), ceiling(e e), floor(e e), które pozwalają uzyskiwać elmenty "bliskie" względem danego porządku. Uwaga. Implementacja metody compareto w klasie String nie uwzględnia właściwego porządku napisów w różnych językach. Aby właściwie sortować napisy należy użyć kolatora (pobieramy go statyczną metodą Collator.getInstance()), który implementuje interfejs Comparator i jest specjalnym komparatorem uwzględniającym lokalizację (regionalne ustawienia językowe). List<String> polskie = Arrays.asList("z", "ę", "ź", "a", "ą"); Collections.sort(polskie, Collator.getInstance(new Locale("pl"))); // od Javy 8 mamy metodę sort również w interfejsie List : //list.sort(new Comparator<T>() {..) 43

Przetwarzanie list i zbiorów - przykłady Zmiana wartości elementów listy. Do każdego elementu listy firm (zmienna list), dodać przyrostek "-Polska". ArrayList<String> list = new ArrayList<>( Arrays.asList(new String[]{"Opel", "Fiat", "Audi")); for (int i=0; i<list.size(); i++) list.set(i, list.get(i) + " - Polska"); System.out.println(list); lub za pomocą iteratora listowego for (ListIterator<String> it = list.listiterator(); it.hasnext(); ) it.set(it.next() + " - Polska"); System.out.println(list); Usunięcie podanego obiektu z kolekcji. Usuniemy Opel z listy firm list. System.out.println("Przed: " + list); list.remove("opel"); System.out.println("Po: " + list); remove(ref) usuwa tylko pierwszy element, który został znaleziony ten sposób działa dla dowolnych modyfikowalnych kolekcji Można też usuwać element o podanym indeksie np. list.remove(3); W przypadku błędnego indeksu - IndexOutOfBoundsException 44

Przetwarzanie list i zbiorów - przykłady 45 Usuwanie za pomocą metody remove() iteratora System.out.println("Przed: " + list); for (Iterator<String> it = list.iterator(); it.hasnext();){ if(it.next().equals("opel")) it.remove(); System.out.println("Po: " + list); Ten sposób działa dla dowolnych modyfikowalnych kolekcji Operacje grupowe (bulk-operations) Metody addall(), removeall(), retainall(), to operacje grupowe (jednocześnie są wykonywane działania, które musielibyśmy programować za pomocą iteracji i metod contains(), remove(), add()). Zmienna list1 zawiera listę firm wczytanych z pliku, a list2 listę firm z innego pliku. Należy zmienić listę list1 tak, by zawierała dodatkowo, wszystkie te firmy z drugiego pliku, których nie było w pierwszym pliku. Przykładowe rozwiązanie:

Przetwarzanie list i zbiorów - przykłady 46 System.out.println("Na poczatku list1 : " + list1); System.out.println("Na poczatku list2 : " + list2); System.out.println("Usuwamy z list2, te które są na list1"); list2.removeall(list1); System.out.println("Teraz list2 : " + list2); System.out.println("Dodamy list2 do list1" ); list1.addall(list2); System.out.println("Na koncu list1 : " + list1); Gdyby chodziło tylko o podanie nazw firm bez powtórzeń: System.out.println("Dane z dwóch plików: "); System.out.println("list1 : " + list1); System.out.println("list2 : " + list2); HashSet<String> set = new HashSet<>(list1); set.addall(list2); System.out.println("Wynikowy zbiór : " + set);

Przetwarzanie list i zbiorów - przykłady W klasie Collections dostępne są metody statyczne, ułatwiające wykonywanie różnych operacji na kolekcjach. Oprócz wspomnianych wcześniej metod dostępne są dodatkowo metody odwracania list Collections.reverse(lista), wypełniania kolekcji i wiele innych. W trakcie przeglądania kolekcji za pomocą iteratora nie wolno jej modyfikować innymi środkami niż metody stosowanego właśnie do iterowania. Zatem // coll dowolna kolekcja napisów Iterator<String> it1=coll.iterator(); Iterator<String> it2=coll.iterator(); while(it1.hasnext()){ it1.next(); it2.next(); it2.remove(); // BŁĄD FAZY WYKONANIA wyjątek // ConcurrentModificationException Dotyczy to również pętli for-each dla kolekcji (stosowany jest w niej "pod spodem" iterator) for (String e : coll) coll.add(e+"1");//spowoduje ConcurrentModificationException 47