Cześć ;)
Uległem pokusie i ściągnąłem JDK Javy 1.8 :) chciałem potestować, zobaczyć na własne oczy co nowego dodali, pierwszy problem jaki się pojawił – Oracle nie wspiera już Win XP – smutek ogólnie, gdyż ja nadal mam Win XP SP3.. StackOverFlow pomogło to obejść, wystarczy ściągnąć JDK normalnie, 7zipem rozpakować ten plik exe i wrzucić zawartość sobie gdzieś w sensowny folder i uruchomić:
1 | FOR /R %%f IN (*.pack) DO "%JAVA_HOME%\bin\unpack200.exe" -r -v "%%f" "%%~pf%%~nf.jar" |
oczywiście przed tym warto zmienić zmienną JAVA_HOME na odpowiednią dla tego JDK, czyli na folder gdzie skopiowało się to JDK.
Jeśli masz system Win 7 lub wyżej to zainstaluje się normalnie ;)
Następny problem to zmuszenie Eclipse’a do kompilowania kodu używając nowego JDK, aby to zrobić trzeba uruchomić „Install New Software” w menu Help i po prawej na górze kliknąć Add i tam w location wpisać
1 | http://download.eclipse.org/eclipse/updates/4.3-P-builds/ |
a to co wpiszemy w nazwę nie ma znaczenia ;) gdy klikniecie OK to pojawi się
1 | Eclipse Java 8 Support (for Kepler SR2) |
zaznaczamy to i instalujemy.
Tworzymy nowy projekt i prawym klikamy na niego, na dole mamy Properties, po lewej stronie odnajmujemy Java Compiler i upewniamy się że wygląda to tak jak tu:
A skoro działa to możemy przejść do szybkiego review ;)
Zacznijmy od strumieni. Nie są to strumienie takie jak otwieramy do, np. plików. Te strumienie pracują na kolekcjach. Każda kolekcja ma teraz metodę stream() oraz parallelStream(), obie zwracają strumień, z tym że druga robi wszystko żeby przetwarzanie było równoległe – ma to swoje plusy i minusy, przetwarzanie, używające parallelStream() będzie szybsze, ale pewnie będzie to realizowane tak że podzieli kolekcję, przemieli jej części osobno i na koniec połączy i warto o tym pamiętać. Strumień udostępnia nam kilkanaście przydatnych funkcji, np:
oczywiście, jest ich więcej.
Pierwsza metoda to dobrze znana z innych języków np. Pythona, funkcja map :) czyli wykonanie pewnej czynności dla każdego elementu tablicy. Użyjmy jej może, nie? Ale pierw przygotujmy sobie dane do testów:
1 2 3 4 5 6 7 | ArrayList<Double> ints = new ArrayList<Double>(); for(int i=0;i<100000;i++) ints.add(i*Math.random()); FileOutputStream fos = new FileOutputStream("s"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(ints); oos.close(); |
Czyli sporo liczb typu double ;)
Skoro zrobiliśmy swoisty persist danych, to wczytajmy je:
1 2 3 4 5 | ArrayList<Double> numbers; FileInputStream fos = new FileInputStream("s"); ObjectInputStream oos = new ObjectInputStream(fos); numbers = (ArrayList<Double>) oos.readObject(); oos.close(); |
i możemy przystąpić do funkcji map:
1 2 3 4 5 6 7 | numbers = (ArrayList<Double>) numbers.stream().map(new Function<Double, Double>() { @Override public Double apply(Double arg0) { return arg0%400; } }).collect(Collectors.toList()); |
lub korzystając z przetwarzania równoległego:
1 2 3 4 5 6 7 | numbers = (ArrayList<Double>) numbers.parallelStream().map(new Function<Double, Double>() { @Override public Double apply(Double arg0) { return arg0%400; } }).collect(Collectors.toList()); |
Zmierzyłem czas obu rozwiązań :)
stream – 93ms
parallelStream – 47ms
Java udostępnia wyrażenia lambda, a więc powyższy kod możemy skrócić do:
1 | t = (ArrayList<Double>) numbers.stream().map((d) -> (d%400)).collect(Collectors.toList()); |
Co raczej nie wypływa na zmianę wydajności a sam interfejs pełni rolę funkcji anonimowych.
Podobnie możemy użyć metody filter:
1 | t = (ArrayList<Double>) numbers.stream().filter(n -> (n>500)).collect(Collectors.toList()); |
Tutaj używamy interfejsu Predicate, czyli testujemy elementy listy i te które spełniają „zbieramy” metodą collect (była też użyta w przykładzie wcześniej) i zwracamy jako listę, używając do tego Kolektora.
A więc teraz wątek możemy stworzyć np. tak:
1 2 3 4 5 6 7 | new Thread(()-> { int a=6; if(a%2==0) System.out.println("jestem 2 watkiem ;) "); }).start(); |
korzystając dokładnie z tego samego mechanizmu co wcześniej – wyrażeń lambda. Możemy zamienić każdy interfejs który ma dokładnie jedną metodę, dodając mu adnotację:
1 | @java.lang.FunctionalInterface |
na interfejs którego możemy używać w wyrażeniach lambda.
Na koniec kilka przykładów kodu z Java 8:
1 2 3 4 5 6 7 8 9 10 11 12 | public static void test1(ArrayList<Double> numbers){ ArrayList<Double> t; long start = System.currentTimeMillis(); t = (ArrayList<Double>) numbers.stream().distinct().filter(n -> (n<30)).collect(Collectors.toList()); long diff = System.currentTimeMillis()-start; System.out.println(diff+"ms"); start = System.currentTimeMillis(); t = (ArrayList<Double>) numbers.parallelStream().distinct().filter(n -> (n<30)).collect(Collectors.toList()); diff = System.currentTimeMillis()-start; System.out.println(diff+"ms"); } |
Jak sadzicie, co wypisze ten kawałek kodu? Użycie w tym przypadku parallelStream() okaże się zgubne – gdyż distinict() wywala duplikaty co ciężko zrównoleglić a do czasu przeliczania dodaje się wtedy czas przełączania kontekstu, co w efekcie zwiększa czas potrzebny do przeliczenia całości.
Czasy:
Dla stream() – 125ms
Dla parallelStream() – 187ms
Jeśli usuniemy distinict(), czasy przedstawiają się następująca:
stream() – 94ms
parallelStream() – 31ms
Bardzo fajny przykład wykorzystnia możemy tutaj zobaczyć:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class Calculator { interface IntegerMath { int operation(int a, int b); } public int operateBinary(int a, int b, IntegerMath op) { return op.operation(a, b); } public static void main(String... args) { Calculator myApp = new Calculator(); IntegerMath addition = (a, b) -> a + b; IntegerMath subtraction = (a, b) -> a - b; System.out.println("40 + 2 = " + myApp.operateBinary(40, 2, addition)); System.out.println("20 - 10 = " + myApp.operateBinary(20, 10, subtraction)); } } |
jeżeli chcielibyśmy podać jako definicję interfejsu coś więcej niż jedną linijkę to robimy to tak:
1 2 3 | IntegerMath soComplicated = (a,b) -> { return a/2 + b/2; }; |
Podsumowując, Java 8 to krok w stronę języków typu Python. Warto nad nim chwilkę czasu spędzić :)
Cześć. Dziś luźny artykuł, bo dziś pobawimy się jedną z pierwszy wersji Pythona. Skompilujemy go i zobaczymy co tam w… Read More
Nowy rok czas zacząć! Więc lećmy z podsumowaniem. Nowy artykuł Nie uwierzycie, ale pojawił się na blogu nowy artykuł! Piszę… Read More
Cześć! W Pythonie 3.13 dodano JITa! JIT, czyli just-in-time compiler to optymalizacja na która Python naprawdę długo czekał. Na nasze… Read More
Cześć! Zapraszam na podsumowanie roku 2024. Książki W sumie rok 2024 był pod względem ilości książek nieco podobny do roku… Read More
Podtrzymując tradycję, prawie regularnych podsumowań, zapraszam na wpis! Nie mogło obyć się bez Karkonoszy We wrześniu odwiedziłem z kolegą Karkonosze,… Read More
Oj daaawnoo mnie tu nie było. Ale wakacje to był czas dużej liczby intensywnych wyjazdów i tak naprawdę, dopiero jakoś… Read More