Techniki Zaawansowane
8 godz. 35 min · Java · Full-stack i Programowanie
Rafał SolarskiW poczatkowych lekcjach przyjrzymy sie pokladowi, na jakim bedziemy uruchamiali nasze programy. Wykorzystamy VisualVM do podgladania parametrów JVM. Zobaczymy równiez jakie zasoby sa tam dostepne oraz dowiesz sie jak monitorowac to, czy dobrze z nich korzystamy. Opowiemy Ci tez miedzy innymi o tym, jak zrobic heap i thread dump, oraz jak wlaczyc logi GC.
Kolejne lekcje kursu zostaly poswiecone wyrazeniom regularnym. Wyrazenia regularne mozemy wykorzystac nie tylko do walidacji danych wprowadzania przez uzytkownika, ale równiez do dzielenia tekstu oraz wyluskiwania wystapien wzorców w duzym tekscie. W tym rozdziale dowiemy sie miedzy innymi tego, jak mozemy wykorzystac ten potencjal z poziomu Javy.
Dzieki typom generycznym jestesmy w stanie osiagnac bezpieczenstwo typów w trakcie kompilacji przy zachowaniu elastycznosci pisanego kodu. W nastepnym rozdziale kursu przyjrzymy sie temu, jak mozemy je wykorzystac, oraz w jaki sposób czasami nalezy z tego bezpieczenstwa zrezygnowac.
Interfejsy funkcyjne to sposób na przeniesienie odrobiny swiata programowania funkcyjnego do Javy. Gdy polaczymy je z wyrazeniami lambda oraz API strumieni pozwola nam pisac te sama logike w duzo bardziej przejrzysty sposób.
Kolekcje, czyli listy, mapy, zbiory i kolejki to jedne z najczesciej wykorzystywanych klas w codziennej pracy. To jak dobrze poznamy ich mozliwosci ma ogromny wplyw na to, w jaki sposób bedziemy podchodzili do rozwiazywania wyzwan na naszej drodze.
System plików to zasób bez którego ciezko sobie poradzic. Pozwalaja nam na dostarczanie konfiguracji, danych wejsciowych i wyjsciowych, a przez to równiez integrowanie ze soba calych systemów.W tym rozdziale nauczymy sie korzystac z tych dobrodziejstw w bezpieczny sposób wykorzystujac m.in. IO Streams.
Trzymanie daty w String to niekoniecznie najwygodniejszy sposób. Juz od pewnego czasu Java dysponuje bardzo wygodnym Date&Time API - zobaczymy, co mozemy w nim znalezc.
Wielowatkowosc nie jest prosta... i dlugo tak jeszcze pozostanie. Nawet jesli korzystamy z frameworków, które próbuja ja przed nami ukryc, to ciagle musimy byc swiadomi problemów jakie sie z nia wiaza. W tym rozdziale poznamy glówne problemy na jakie mozna natrafic programujac wielowatkowo w Javie. Poznamy równiez klasy, które zdecydowanie pomoga nam zapanowac nad ta zlozonoscia.
JDBC to najbardziej podstawowy sposób laczenia sie z baza SQL z poziomu Javy. W wielu systemach/aplikacjach stosuje sie rozwiazania ORM takie jak JPA/Hibernate. Mimo wszystko warto wiedziec jak to pod spodem dziala oraz umiec poradzic sobie w aplikacjach, gdzie wybrano bardziej "lekkie" podejscie niz Hibernate.
Na koniec kursu wykorzystamy zdobyta wiedze, aby stworzyc prosta aplikacje pozwalajaca na przechowywanie danych o wydatkach. Po stworzeniu coreu aplikacji, mozesz spróbowac uzupelnic go za pomoca GUI.
Ten kurs stworzony zostal przede wszystkim z mysla o osobach, które juz poznaly podstawy jezyka, takie jak zmienne, mechanizmy kontroli wykonania, klasy, typy generyczne.Jezeli chcesz poczuc sie swobodnie nie tylko jesli chodzi o mechanizmy jezyka, ale równiez pod wzgledem znajomosci standardowej biblioteki Javy - to kurs w sam raz dla Ciebie. Materialy beda przydatne dla studentów, którzy znaja juz podstawowa skladnie Javy; programistów Javy chcacych poszerzyc lub uporzadkowac swoja wiedze; programistów innych jezyków, którzy chca poznac inny stack technologiczny.
Cześć w tej lekcji pokażę ci jak na takim podstawowym poziomie
są komponować future'y przyjmijmy sobie
taki przykład powiedzmy że teraz już nie chcemy tylko na
przykład wysłać maila albo tylko pobierać dane o użytkowniku na przykład jego nazwę
tak powiedzmy sobie że teraz chcemy pobrać jego nazwę oraz
wysłać maila z jakimś powiedzmy tekstem właśnie z tą jego nazwą tak no
i teraz chcemy to wszystko zrobić i chcemy to zrobić asynchronicznie powiedzmy tutaj jest
ten get tak jest operacja która służy send mail
to user with id no i mamy tutaj tego geta tylko po
to żeby nam wcześniej ten executor service nie został zamknięty prawda okej
i tutaj powiedzmy sobie robimy jakiś jakąś naszą logikę tak
czyli teoretycznie gdyby nie było tego geta to po prostu ta operacja wydarzyła
by się gdzieś w tle i nawet byśmy nie czekali prawda od razu byłby zwrot do
użytkownika dobrze zobaczmy sobie
teraz jak można zaimplementować tą metodę to możemy sobie ukryć tak
no i tutaj w takiej podstawowej swojej wersji jeżeli używamy sobie tylko i
wyłącznie future na to wygląda to trochę strasznie i jest dość niewydajne
to jest zauważmy sobie stworzyliśmy sobie oba serwisiki podaliśmy
je tutaj jako parametry i teraz abym mógł zrobić coś z tą nazwą
która jest zwracana w get username no to my sobie musimy
zaczekać najpierw na tego future'a tak czyli musimy zrobić geta z jakim timeout'em
no możemy sobie wyobrazić jaki jaki to będzie timeout może nam się przyśni
no i tutaj później możemy z tym zrobić send mail no i
tutaj jeżeli chcemy mieć gwarancję że w momencie kiedy ten future który czekał
na ten pierwszy powiedzmy ta czy ten future
jeżeli on się skończy to już to jest też wysłane no
to tutaj też znowu musimy zwrócić geta albo zwrócić future który
tutaj był wykonany prawda więc tutaj też
potrzebuję właśnie ten trzeci future który jeszcze odpowiada za to że zeschedule'uje jeden
a później jak ten się skończy to schedule'uje powiedzmy drugi jeszcze czeka powiedzmy
na zakończenie prawda no nie
da się w ten sposób pisać po prostu jest to ciężkie tak na
szczęście jeszcze poza future'm tak future który wchodził
w 1 5 powiedzmy był przełomem tak bo ułatwia trochę powiedzmy przekazywanie tych
zmiennych tych wartości zwracanych z innych threadów tak był
pewnego rodzaju dopełnieniem do executor service no to tutaj w javie 1 8 jeszcze
doszło coś co się nazywa completable future i to jest coś co
umożliwia nam jeszcze stosowanie pewnych kombinatorów między
wywołaniami poszczególnych future'ów czyli moglibyśmy powiedzieć
na futurze stąd tak na tym że jak ty się zakończysz to
jeszcze z tym wynikiem który ty zwracasz to wywołaj na przykład taką metodę tak
albo jeszcze zrób coś z tym future'em zwrócisz tą wartością wewnątrz
tak i na przykład powiedzmy nie wiem dodaj do niej zamień ją na integer
tak policz jaka jest długość tego tego stringa tak no i są
takie możliwości czyli potrzebujemy właśnie tego completable future no
więc możemy tego future'a co tutaj zwraca przez get username i przez
send mail możemy zamienić na completable future tak i teraz completable future
też powiedzmy dziedziczy po future więc wszyscy poprzedni klienci
tych metod ciągle tak jakby no mogą wywołać te swoje gety
joiny i tak dalej prawda tak tylko teraz stworzenie po prostu tego future'a
z wykorzystaniem executor service trochę się zmienia teraz wystarczy że wywołam
sobie completable future tak i tutaj wykorzystujemy w przypadku kiedy
mamy jakąś jakąś funkcję jakiś powiedzmy kawałek
kodu który coś zwraca to wykorzystujemy supply async tak
tutaj i tutaj podajemy po prostu ten fragment który wcześniej podawaliśmy do naszego
egzekutora i teraz jeżeli chcemy mieć możliwość
odpalenia tego na tym wskazanym egzekutorze który tutaj mieliśmy tak z jakiegoś powodu ponieważ
tutaj są na przykład wątki które chcemy wykorzystywać właśnie w ten sposób tak
na przykład one są io bound no to mamy też możliwość
tutaj wyspecyfikowania na jakim egzekutorze ma być to odpalane domyślnie
jak tego nie podamy to najprawdopodobniej ten future kod
jest wykonywany na common pool jest takie jedno pole powiedzmy
ono jest w fork join pool to jest coś takiego jak common
common pool prawda i w momencie kiedy nie pokażemy tego egzekutora
tutaj nie wskażemy jawnie no to on w tym momencie właśnie weźmie ten
domyślny prawda też jeżeli mamy równe 1
no to wtedy on po prostu sam stworzy pojedynczego thread'a tak analogicznie
wygląda implementacja mail sendera tutaj tej metody send mail
z taką różnicą że tutaj wykorzystujemy run async już nie supply
async z tego względu że to co tutaj podstawialiśmy nie zwracało żadnej wartości prawda okej
wróćmy do naszej metody send mail to user with id tutaj
od kiedy get username zwraca nam completable future możemy wykorzystać
then compose then compose przyjmuje funkcję w którym możemy wyspecyfikować
co ma się stać w momencie kiedy ten pierwszy future jest zakończony tak czyli
kiedy mam już w ręku username tutaj dostajemy nawet tego stringa tak
no i możemy zwrócić wtedy innego future'a który
zostanie scalony tak jakby dołożony do tego obliczenia okej
i tutaj możemy właśnie podać nasze wywołanie tutaj w tym miejscu dostajemy tak na prawdę username
no i z nim możemy wykonać na mail senderze send mail prawda
teraz możemy usunąć całą resztę tego kodu który tutaj był oraz
możemy usunąć w ogóle wywołanie tego submita dookoła wywołanie then
compose zwracam nam kolejnego future'a który tak jakby sygnalizuje wynik
tego działania które tutaj do tej pory mieliśmy prawda więc możemy od razu tu coś zwrócić
widzimy że to nam zadziała możemy to sobie przetestować jeszcze kod
się skompilował i też widzimy że działanie jest pożądane okej tutaj dostaliśmy user1
tak user1 zostało zwrócone po prostu stąd to w tym momencie
po prostu skleja id z prefiksem user okej teraz chwilę
prześledźmy to jak to się tutaj działo tak i na jakich wątkach
których thread pooli były wywołane te akcje poszczególne tutaj jak
mamy get username tak z user service to user service już został
tutaj sparametryzowany tym egzekutorem który my chcieliśmy prawda
tak tutaj tutaj zwrócą ten sam egzekutor no okej
czyli ta metoda tak ten kod który tu jest dostarczany w środku wywołuje
się na tym executor service który jest dostarczany w konstruktorze po prostu tak ponieważ
wykorzystujemy supply async tutaj jeszcze go wrzucamy okej no
dobra i później mamy ten compose i tak ten
fragment tutaj dostarczony prawda no to jest wywołanie po prostu
jakiegoś obiektu który musi być thread saved tak który
jest dostarczony i on jest w środku też ma executora prawda tak
ten run async jest wywołany po prostu na tym executor service to tak samo
jest dostarczany w konstruktorze teraz najlepsze pytanie gdzie to jest wywoływane
tak ponieważ tutaj ten compose jeszcze ma
wersje swoją async w której możemy sprecyzować na jakim egzekutorze
to jest wywołane to możemy wymusić ale było też wywołane też na tym executorze
tak po prostu zrobimy coś takiego prawda w momencie kiedy zrobimy
tak jest then compose async to jest wywołane w tym momencie na common poolu prawda
lub na oddzielnym powiedzmy wątku w momencie kiedy jest
ustawiony na 1 za to w momencie kiedy jest zrobione coś takiego to
najprawdopodobniej cała ta funkcja która tu jest dostarczona zostanie wywołana
na tym wątku na którym zostało wywołane to a
dokładnie ten fragment jest to pewne takie ułatwienie a
właściwie optymalizacja żeby nie zmieniać wątków w momencie kiedy doklejamy jakąś
akcję możemy to sobie sprawdzić w momencie kiedy dodamy tutaj logowanie prawda
teraz dodałem logowanie do każdej z tych metod możemy coś zobaczyć jakie
są id threadów a właściwie nazwy w poszczególnych wywołaniach jak widzimy
get username i then compose tak dostały tego samego thread'a
send mail dostał za to następnego threada z pooli prawda poza
ten compose możemy też wykorzystać metodę then apply o ile ten compose
przyjmował wynik poprzedniego obliczenia czyli na przykład zwrócenie
nazwy użytkownika i zwracał wynik kolejnego obliczenia
tylko we wrapperze czyli tutaj zwraca future'a tak
czyli kolejne obliczanie to ten apply przyjmuje element tak robi
na nim obliczenie i zwraca wynik jest to tak jakbyśmy sobie wywołali właśnie map na
streamie w kolekcji prawda na przykład jeżeli chcemy teraz dokleić do username
jakiś na przykład postfiks czyli tak
czyli powiedzmy możemy dokleić małpa example com tak to to możemy
coś zrobić w tym miejscu tak prawda w ten sposób no i dzięki temu
to będziemy mieli przyklejone tak jakby do tej operacji w tym momencie no i nie potrzebujemy
tutaj tak naprawdę wywołać kolejnego wątku bo to jest tylko dodanie jakiegoś powiedzmy
postfiksu to tak to nie jest jakaś ciężka operacja żeby ją wykonywać na oddzielnym
wątku i jeszcze to zrównoleglać prawda no okej jak spojrzysz co jeszcze
jest completable future to jest to cała masa innych metod które powiedzmy
pozwalają nam kombinować nasze operację w taki sposób jak byśmy tego
chcieli jest to duża przewaga nad zwykłym interfejsem future'a w którym też
completable future dziedziczy tak w ten sposób możemy jakoś spinać tak sensownie
te operacje biznesowe w naszym kodzie tak bez używania ciągłego
geta tak i wykorzystywania kolejnego wątku który
jest tak naprawdę tutaj nie potrzebny tak jak wcześniej wykorzystywaliśmy na
przykład właśnie robiliśmy request po jedną rzecz tak dostawaliśmy
future robiliśmy na tym geta to mieliśmy ciągle jeden wątek za dużo
używany tak którego mogliśmy się pozbyć wtedy kiedy nasze powiedzmy wątki
mieliły tam zwracały username'a czy tam powiedzmy wysyłały jakiegoś
maila tak to poza tym że czekaliśmy w main tutaj z tym getem to
jeszcze niepotrzebnie czekaliśmy tutaj getem tak i ten powiedzmy to wywołanie
geta było już niepotrzebne tak nadmiarowy jeden wątek był tu trzymany wykorzystując
właśnie completable future jesteśmy sobie w stanie to jakoś zchainować
tak żeby to oszczędzić okej to wszystko co chciałem ci pokazać w tej lekcji dzięki
wielkie i do usłyszenia