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ć :)
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
Cześć! Zapraszam na krótkie podsumowanie kwietnia. Wyjazd do Niemiec A dokładniej pod granicę z Francją. Chrześnica miała pierwszą komunię. Po… Read More
Ostatnio tygodnie były tak bardzo wypełnione, że nie udało mi się napisać nawet krótkiego podsumowanie. Więc dziś zbiorczo podsumuję luty… Read More
Zapraszam na krótkie podsumowanie miesiąca. Książki W styczniu przeczytałem "Homo Deus: Historia jutra". Książka łudząco podoba do wcześniejszej książki tego… Read More
Cześć! Zapraszam na podsumowanie roku 2023. Książki Zacznijmy od książek. W tym roku cel 35 książek nie został osiągnięty. Niemniej… Read More
Zapraszam na krótkie podsumowanie miesiąca. Książki W grudniu skończyłem czytać Mein Kampf. Nudna książka. Ciekawsze fragmenty można by było streścić… Read More