Java niezbędnik programisty spotkanie nr 9 Java 2 Platform, Standard Edition 5.0 1
Historia 1991 rozpoczyna się the Green Project (to jeszcze era MS DOS) 1992 pojawia się język Oak 1995 zmiana nazwy z Oak na Java 1996 JDK 1.0 1997 JDK 1.1 (JavaOne, z blisko 8000 uczestnikami, staje się największą konferencją programistyczną na świecie) 4 grudzień 1998 JDK promowane pod nazwą nazwą Java 2 Platform, Standard Edition; język w wersji 1.2; duże zmiany w API (mechanizm odzwierciedleń, Swing) 8 Maj 2000 J2SE 1.3 (HotSpot) 13 luty 2002 J2SE 1.4 (asercje, wyrażenia regularne, podczepianie wyjątków, zintegorwany parser XML i procesor XSLT) 29 wrzesień 2004 J2SE 5 (kolejna zmiana nazwy, Tiger); (typy generyczne, anotacje, typy wyliczeniowe, rozszerzone for,...) 2
Plany Kolejne wydania mają się ukazywać co 18-24 miesiące, są opracowywane jako Java Specification Request (JSR) w ramach JCP i mają integrować wyniki pozostałych JSR: Lato 2006 Java, Standard Edition 6 (już nie J2SE) inaczej Mustang; Ujednolicone nazewnictwo obejmie również: Java, Enterprise Edition 5 Java, Micro Edition (nie ma numerka) (trzeba się odzwyczajać od J2EE, J2ME) 3
Źródła http://en.wikipedia.org/wiki/java_programming_language http://www.java.com/en/about/brand/naming.jsp http://www.java.com/en/javahistory/timeline.jsp https://mustang.dev.java.net/ http://jcp.org/en/jsr/all http://java.sun.com/developer/onlinetraining/new2java/programming/learn/unravelingjava.html 4
Przedefiniowywanie typu zwrotnego class Owoc { class Gruszka extends Owoc { class DrzewoOwocowe { Owoc wydajplon() { return new Owoc(); class Wierzba extends DrzewoOwocowe { //przed Javą 5.0 Gruszki nie mogły rosnąć na Wierzbie Owoc wydajplon() { return new Gruszka(); //kontrola typów dopiero w chwili wykonania Gruszka gru = (Gruszka) wierzba.wydajplon(); 5
Przedefiniowywanie typu zwrotnego class Owoc { class Śliwka extends Owoc { class DrzewoOwocowe { Owoc wydajplon() { return new Owoc(); class Sosna extends DrzewoOwocowe { //przykład Śliwek na Sośnie w Javie 5.0 Śliwka wydajplon() { return new Śliwka(); //kontrola typów podczas kompilacji Śliwka śli = sosna.wydajplon(); 6
Kolejki FIFO Queue q = new LinkedList(); //FIFO q.offer("b"); q.add("a");//zapełnienie skutkuje "niepilnowanym" wyjątkiem //wart. zwrotna informuje, czy kolekcja się zmieniła q.offer("c");//zapełnienie to niekoniecznie sytuacja nietypowa //offer() rozróżnia po wartości zwrotnej System.out.print(q.poll());//kolejny element lub null System.out.print(q.remove());//zgłasza "niepilnowany" //ale może zgłosić "niepilnowany" NoSuchElementException System.out.print(q.peek());//podglądamy, ale nie zdejmujemy System.out.print(q.element());//jak peek //ale może zgłosić "niepilnowany" NoSuchElementException System.out.print(q.poll()); Wynik: baccc 7
Klejki priorytetowe PriorityQueue q = new PriorityQueue(12, //domyślny pocz. rozmiar=11 new Comparator() { public int compare(object ii, Object jj) { int i = (Integer) ii;//automatyczne odpakowywanie int j = (Integer) jj;//automatyczne odpakowywanie int wynik = i%2 - j%2;//parzyste < nieparzyste if (wynik == 0) wynik = i-j; return wynik; ); for (int i = 1; i <= 12; i++) q.offer(i);//auto. opakowywanie for (int i = 1; i <= 12; i++) System.out.print(q.poll()+, ); Wynik: 2, 4, 6, 8, 10, 12, 1, 3, 5, 7, 9, 11, 8
Iterowanie po kolejce priorytetowej Iterator jedynie podgląda elementy i nie gwarantuje żadnego porządku. for (int i = 1; i <= 12; i++) q.offer(i);//auto. opakowywanie for (Iterator iter = q.iterator(); iter.hasnext();) { //kontrola typów dopiero w chwili wykonania int el = (Integer) iter.next(); el += 10; System.out.println(el++, ); Przykładowy wynik: 12, 14, 16, 18, 20, 22, 17, 11, 19, 15, 21, 13, 9
Nowy rodzaj pętli for Dla kolekcji i tablic dodano nowy rodzaj pętli for zintegrowanej z iteratorem. for (Object i : q) { int el = (Integer) i; System.out.print(el+10); System.out.print("-"); System.out.print(((Integer) i) + 10);//auto. odpakowywanie System.out.print(", "); Przykładowy wynik: 12-12, 14-14, 16-16, 18-18, 20-20, 22-22, 17-17, 11-11, 19-19, 15-15, 21-21, 13-13, 10
Nowy rodzaj pętli for Jeżeli bardzo nam zależy na użyciu iteratora można sobie poradzić przy pomocy klasy Arrays. Object[] tab = q.toarray(); Arrays.sort(tab, new MójComparator()); for (Object i : tab) { int el = (Integer) i; System.out.print(el+10); System.out.print(", "); Wynik: 12, 14, 16, 18, 20, 22, 11, 13, 15, 17, 19, 21, 11
Typy generyczne Najważniejszym udogodnieniem w Javie 5.0 są typy generyczne. class ComparatorNaInteger implements Comparator<Integer> { public int compare(integer i, Integer j) { int wynik = i%2 - j%2; if (wynik == 0) wynik = i-j; return wynik; Od Javy 5.0 zmieniły się definicje wielu podstawowych klas, np. Interface Comparator<T> int compare(t o1, T o2) 12
Typy generyczne PriorityQueue<Integer> q = new PriorityQueue<Integer>(12, new ComparatorNaInteger()); for (int i = 1; i <= 12; i++) q.offer(i); for (int i = 1; i <= 12; i++) { int el = q.poll()+10;//poll() zwraca Integery, a nie Objecty System.out.print(el+", "); 13
Typy generyczne PriorityQueue<Integer> q = new PriorityQueue<Integer>(12, new ComparatorNaInteger()); //można podać zwykły Comparator, ale pojawią się ostrzeżenia for (int i = 1; i <= 12; i++) q.offer(i);//auto. opakowywanie for (Integer el : q) {//niestety losowa kolejność System.out.print(el+10); System.out.print(", "); 14
Nie trzeba już tyle rzutować //jako klucza mapy często używa się liczb lub napisów Map<Integer, Integer> kwadraty = new HashMap<Integer, Integer>(); for (int i = 0; i < 100; i++) kwadraty.put(i, i*i); for (int i = 0; i < 8; i++) { int n = i * 13; System.out.println(n+" do kwadratu to "+kwadraty.get(n)); //teraz jest też łatwiej dobrać się do dziwnych wartości Map<String, List<List<int[]>>> mapa = getmymap(); int x = map.get(klucz).get(0).get(0)[0]; 15
A co z jawnymi iteratorami? List<String> napisy = new LinkedList<String>(); napisy.add("trele"); napisy.add("morele"); for (Iterator<String> i = napisy.iterator(); i.hasnext(); ) { String s = i.next(); System.out.println(s); //nieparametryzowany iterator działa po staremu (trzeba rzutować) for (Iterator i = napisy.iterator(); i.hasnext(); ) { String s = (String) i.next(); System.out.println(s); 16
Bezpieczny iterator do niebezpiecznej kolekcji Opracował List napisy = new LinkedList(); napisy.add("fiu"); napisy.add("bździu"); //napisy.add(1); for (Iterator<String> i = napisy.iterator(); i.hasnext(); ) { String s = i.next();//ew. błąd dopiero w czasie wykonania System.out.println(s); Sparametryzowane typy można też przekazywać jako parametry lub wynik metody. Tak samo jak powyżej można też oszukiwać. Kompilator wspomaga nas ostrzeżeniami. 17
A co z hierarchią typów? Jest oparta na typach bazowych, a nie na parametrach! LinkedList<Number> numerki = new LinkedList<Number>(); List<Number> jeszczewięcejnumerków = numerki; //numerki = new LinkedList<Float>(); //LinkedList<Object> obiekty = numerki; //oto potencjalne zagrożenia //obiekty.add("pseudo numerek"); 18
Erasure Typy generyczne są brane pod uwagę jedynie w chwili kompilacji. List<String> napisy = new LinkedList<String>(); W trakcie działania programu są wymazywane (ang. erase). List napisy = new LinkedList(); To kolejny powód dlaczego parametry nie są brane pod uwagę przy dziedziczeniu. Z tego powodu typy generyczne dają się oszukiwać (jedyną wskazówką będą ostrzeżenia) List<Integer> ints = new LinkedList<Integer>(); List staralista = ints;//działa ze względu na wsteczną kompatyb. staralista.add("klops");//tu nie ma żadnych problemów Integer i = ints.get(0);//za to będą w chwili wykonania 19
Oszukiwać można też przy pomocy RTTI Opracował class Oszustwo { public static List<Integer> ints = new ArrayList<Integer>(); static void wypisz() { for (Integer i : ints) System.out.println(i); static void test() { ints.add(1); ints.add(2); ints.add(3); try { List list = (List) Oszustwo.class.getDeclaredField("ints").get(null); list.add("niezły numerek");//tu nadal będzie ostrzeżenie catch (Exception e) { e.printstacktrace(); wypisz(); 20
Jak pozbyć się ostrzeżeń? Lepsza jednak taka ochrona typów niż żadna. Trzeba dołożyć wszelkich starań, żeby gotowe programy nie generowały żadnych ostrzeżeń. ostrzeżenia powstają przy przekazywaniu parametrów, a przy pobieraniu wyników nie: static void test2(list list) { for (Iterator i = list.iterator(); i.hasnext(); ) System.out.println(i.next().toString()); Jeżeli potrzebne są kolekcje ogólne, to parametryzujemy typem Object, np. List<Object> (zazwyczaj słaby pomysł ze względu na hierarchię typów) lub używamy? (niestety dostajemy typy read-only): static void test3(list<?> list) { //list.add((object) "napis"); for (Iterator<?> i = list.iterator(); i.hasnext(); ) System.out.println(i.next().toString()); 21
Parametryzowanie własnych typów class Śmietnik<T> { protected List<T> zawartość; public Śmietnik() { zawartość = new ArrayList<T>(); public boolean czypusty() { return zawartość.size() == 0; public int rozmiar() { return zawartość.size(); public void wyrzuć(t o) { zawartość.add(o); public T wygrzeb() { if (!czypusty()) return zawartość.remove(0); else return null; Śmietnik<String> napisy = new Śmietnik<String>(); 22
Uwaga na atrybuty statyczne Parametryzujemy egzemplarze (Śmietnik<Byte>, Śmietnik<Float>,...), a nie klasę więc nie można nic zakładać o składowych statycznych //private static List<T> listastat = new ArrayList<T>(); //static T weźsmiecia(śmietnik<t> r) { return r.wygrzeb(); Oczywiście typy o określonym parametrze działają: static public int max(śmietnik<byte> b, Śmietnik<Float> f) { return Math.max(b.rozmiar(), f.rozmiar()); Można też wskazać parametry dla metody statycznej public static <T, U> int max2(śmietnik<t> t, Śmietnik<U> u) { return Math.max(t.rozmiar(), u.rozmiar()); 23
Parametry można ograniczać class ŚmietnikMatematyka<N extends Number> extends Śmietnik<N> { public ŚmietnikMatematyka() { super(); public double suma() { double suma = 0; for (N n : zawartość) suma += n.doublevalue(); return suma; 24
Podobnie z parametrami metod public static double suma(śmietnik<? extends Number> śm) { double suma = 0; for (Number n : śm.zawartość) suma += n.doublevalue(); return suma; public static <T extends Number> double suma(śmietnik<t> t1, Śmietnik<T> t2) { double suma = 0; for (Number n : t1.zawartość) suma += n.doublevalue(); for (Number n : t2.zawartość) suma += n.doublevalue(); return 0; 25
Zagadka class NieudanyComparatorNaInteger<Integer> implements Comparator<Integer> { public int compare(integer i, Integer j) { int wynik = i%2 - j%2; if (wynik == 0) wynik = i-j; return wynik; 26