Języki i Techniki Programowania II Wykład 4 Kolekcje
Klasy Uogólnione (Generics) List<Cat> l = new ArrayList<Cat>(); l.add(new Cat());//OK l.add(new Dog());//Błąd
Klasy Uogólnione (Generics) Type erasure Pełna kompatybilność wstecz (raw types) Zachowanie compile-time niedoskonałe (np. przy przekazywaniu parametrów, rzutowaniu do bibliotek...) - infering Set<String> s = new HashSet<String>(); Set<String> s = Collections.checkedSet(new HashSet<String>(), String.class);
Klasy Uogólnione (Generics) List<String> ls = new ArrayList<String>(); List<Object> lo = ls;//nielegalne List<String> l1 = new ArrayList<String>(); List<Object> l2 = new ArrayList<Object>(); true!!! -> l1.getclass() == l2.getclass()
Wildcards (Generics) void printcollection(collection<?> c) { for (Object e:c) System.out.println(e); public void drawall( Collection <? extends Shape> c)... TreeSet(Comparator<? super E> c)
Metody parametryzowane //nielegalne void arraytocollection(object a[], Collection<?> c) //legalne void <T> arraytocollection(t a[], Collection<T> c)
Metody i Klasy parametryzowane public class Entry<K, V> { private final K key; private final V value; public Entry(K k,v v) { key = k; value = v; public K getkey() { return key; public V getvalue() { return value; public String tostring() { return "(" + key + ", " + value + ")";
Metody i Klasy parametryzowane public static <T> Entry<T,T> twice(t value) { return new SimpleImmutableEntry<T,T>(value, value);
Klasy Uogólnione (Generics) Bez klas uogólnionych static void expurgate(collection c) { for (Iterator i = c.iterator(); i.hasnext(); ) if (((String) i.next()).length() == 4) i.remove(); Z klasami uogólnionymi static void expurgate(collection<string> c) { for (Iterator<String> i = c.iterator(); i.hasnext(); ) if (i.next().length() == 4) i.remove();
Idiom Class Token public <T> Collection<T> select(class<t> c, String query) { Collection<T> res = new ArrayList<T>(); while(... jakiś warunek... ) { T item = c.getinstance();... // jakiś kod res.add(item); return res; // nie mozna: item = new T(); przez type erasure
Klasa Collections Kategorie statycznych metod: Sortowanie (elementy implementujące iface Comparable) sort(list l), sort(list l, Comparator c) Przetwarzanie list reverse, fill, copy, swap, addall Przeszukiwanie binarysearch Generowanie kolekcji opakowywujących ( wrapper ) synchronizedset, synchronizedlist, etc... unmodifiablelist, unmodifiableset, etc... checkedset, checkedlist, etc...
Klasa Collections Kategorie statycznych metod: Sortowanie (elementy implementujące iface Comparable) sort(list l), sort(list l, Comparator c) Przetwarzanie list reverse, fill, copy, swap, addall Przeszukiwanie binarysearch Generowanie kolekcji opakowywujących ( wrapper ) synchronizedset, synchronizedlist, etc... unmodifiablelist, unmodifiableset, etc... checkedset, checkedlist, etc...
Wzorzec Decorator
Wzorzec Decorator Inna nazwa: Wrapper Zastosowania: Zmienne w czasie zadania dla klas Gdy dziedziczenie jest niepraktyczne (np. w przypadku zagrożenia eksponencjalnym wzrostem ilości typów) Zalety: Dynamiczny charakter zachowania Uproszczona hierarchia, korzeń struktury odciążony Wady: Brak kontroli typów, system bardziej złożony wiele obiektów o bardziej zróżnicowanym zachowaniu
Standardowe Wejście String s; BufferedReader br= new BufferedReader( new InputStreamReader(System.in)); while ( (s = br.readline())!= null ) { System.out.println(s);
Decorator Set<String> s = Collections.checkedSet( new HashSet<String>(), String.class);
Sortowanie Collections.sort(list); public interface Comparable<T> { public int compareto(t o); Collections.sort(list,comparator); public interface Comparator<T> { public int compareto(t o1, T o2); equals (Object obj); -1: o1 < o2 0: o1 = o2 +1: o1 > o2
Typy Kopertowe Typy prymitywne mają swoje odpowiedniki obiektowe w pakiecie java.lang.*: boolean -> Boolean byte -> Byte char -> Character double -> Double float -> Float int -> Integer long -> Long short -> Short void -> Void
Typy Kopertowe Liczbowe typy kopertowe dziedziczą z java.lang.number, z którego interfejsu korzystamy przy pobieraniu wartości (zawiera mechanizmy obcinania i zaokrąglania) int intvalue() long longvalue() short shortvalue() byte bytevalue() double doublevalue() float floatvalue()
Typy Kopertowe String s = 123 ; int i = 0; try { i = (new Integer(s)).intValue(); catch(numberformatexception e) { e.printstacktrace(system.err);
Autoboxing, automatic unboxing Map<String, Integer> m = new TreeMap<String,Integer>(); for (String word : args) { Integer freq = m.get(word); m.put(word, (freq == null? 1 : freq + 1)); Zamiast: m.put(word,(freq==null?new Integer(1) : new Integer(freq.intValue()+1)
Kolekcje Biblioteka kolekcji (collection framework) dostarcza obiektów pozwalających tworzyć, przeszukiwać i zarządzać strukturami danych. Biblioteka kolekcji taka jak STL (C++) czy Java Collections (java.util) składa się zazwyczaj z takich elementów jak: Interfejsy Implementacje Algorytmy
Kolekcje Zalety biblioteki: zmniejsza wysiłek konieczny do osiągnięcia celu pozwala na lepszą optymalizację pozwala na lepsze interfejsowanie niezależnych bibliotek pozwala na lepsze ponowne wykorzystanie kodu dzięki standaryzacji
Interfejsy Klasyczna zasada: Programuj do Interfejsu, nie do implementacji. Wnioski: Interfejsujemy do bibliotek poprzez interfejsy a nie klasy. Nie stosujemy pól publicznych Nie rzutujemy w dół etc...
Interfejsy Interfejs Collection potomkowie: Queue Set potomek: SortedSet List Interfejs Map potomkowie: SortedMap
Interfejsy Ilość interfejsów jest ograniczona implementacje ze szczególnymi niezmiennikami (unmodifiable, synchronized, immutable, type checked) nie powodują rozbudowy hierarchii, tylko ewentualnie rzucają wyjątkiem: UnsupportedOperationException. Implementacje dostarczają różnych realizacji wewnętrznych interfejsów np. LinkedList oraz ArrayList Operacje (sortowanie, wyszukiwanie, etc. etc.) są zaimplementowane w sposób niezależny od implementacji jako metody statyczne klasy Collections.
Interfejs Collection Zastosowanie w tzw. conversion constructor do inicjalizacji kolekcji elementami innej kolekcji. Set<String> c; List<String> list = new ArrayList<String>(c); Bulk operations: containsall addall removeall retainall Clear Przykład: c.removeall(collections.singleton(e))
Interfejs Collection Zastosowane iteratorów: static void filter(collection c) { for (Iterator i = c.iterator(); i.hasnext(); ) if (!cond(i.next())) i.remove(); Rzutowanie na tablicę: Object [] a = c.toarray(); String [] a = c.toarray(new String[0]);
Interfejs List Metody: Object get(index i) Object set(int index,object e) boolean add(object e) int indexof(object e) ListIterator listiterator() ListIterator: previous() hasprevious()
Interfejs List Implementacje: Vector LinkedList ArrayList
Interfejs Set Metody: contains(object e) add(object e) Implementacje: HashSet (wyszukanie O(1), brak porządku) TreeSet (wyszukanie O(ln(n)), porz.naturalny) LinkedHashSet (wyszukanie O(1), porz. wg. kolejności)
Interfejs Queue Interfejs z wyjątkami: add(e) remove() element() Interfejs z wartościami pustymi (null) offer(e) poll() seek() Istnieje wersja z ograniczoną pojemnością.
Interfejs Map<K,V> Metody: V put(k key, V value); V get(object key); boolean containskey(object key); boolean containsvalue(object value); Rzutowanie na kolekcję public Set<K> keyset(); public Collection<V> values(); public Set<Map.Entry<K,V>> entryset();
Interfejs Map<K,V> Implementacje: HashMap TreeMap LinkedHashMap HashTable Przestarzała metoda przeszukiwania: for (Enumeration e = v.elements() ; e.hasmoreelements() ;) { System.out.println(e.nextElement());
Interfejs SortedSet<E> Metody: SortedSet<E> subset(e fromelement, E toelement); SortedSet<E> headset(e toelement); SortedSet<E> tailset(e fromelement); E first(); E last(); Comparator<? super E> comparator();
Interfejs SortedMap<K,V> Metody Comparator<? super K>comparator(); SortedMap<K, V> submap(k fromkey, K tokey); SortedMap<K, V> headmap(k tokey); SortedMap<K, V> tailmap(k fromkey); K firstkey(); K lastkey();
Dodatkowe narzędzia Klasa Arrays: Arrays.asList Implementacje: EnumSet, EnumMap Implementacje: CopyOnWriteArraySet, CopyOnWriteArrayList Collections.nCopies Collections.singleton Collections.emptySet, Collection.emptyList etc...
Wzorzec Iterator Nazwa: Iterator (czasem: cursor) Problem: Potrzeba jednolitego interfejsu do iterowania po kolekcji Konsekwencja: otrzymujemy obiekt o semantyce wskaźnika kroczącego po tablicy w C możemy mieć różne strategie przejścia po kolekcji możemy mieć kilka równoczesnych iteracji po kolekcji Wady: nie można być pewny cyklu życia nie można modyfikować, jeśli jest kilka iteratorów
Wzorzec Iterator Iterator it=c.iterator(); while (it.hasnext()) { this.add((string)it.next()); hasnext(): true next() next() next() iterator() hasnext(): false
Wzorzec Iterator Iterator<String> it=c.iterator(); while (it.hasnext()) { this.add(it.next()); hasnext(): true next() next() next() iterator() hasnext(): false
For Each Stary for void cancelall(collection<timertask> c) { for (Iterator<TimerTask> i = c.iterator();; i.hasnext()) i.next().cancel(); Nowy for void cancelall(collection<timertask> c) { for (TimerTask t : c) t.cancel();
Abstract Collections Interfejs List: add(e e), add(int index, E element), addall(collection<? extends E> c),addall(int index, Collection<? extends E> c, Clear(), contains(object o), containsall(collection<? >c), equals(object o), get(int index), indexof(object o), IsEmpty(), iterator(), lastindexof(object o), listiterator(), listiterator(int index), remove(int index), remove(object o), removeall(collection<?> c), retainall(collection<?> c), set(int index, E element), size(), sublist(int fromindex, int toindex), toarray(), toarray(t[] a)
Abstract Collections Klasa AbstrackList: Minimum: get(int), size() Modyfikowalne: set(int,e) Zmienna długość: add(int, E), remove(int)