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 poprzedniej lekcji przypomnieliśmy
sobie podstawową składnię związaną z typami generycznymi a w tej
lekcji zauważymy że pojawiają się pewne problemy w momencie kiedy chcemy przechowywać
w kontenerach typy które po sobie dziedziczą nauczymy się również
jak sobie radzić z tymi ograniczeniami mamy tutaj listę integerów
pod spodem jest typ array list czyli implementacja listy teraz
stwórzmy sobie jeszcze listę numberów utworzyłem listę
numberów też jako array list i teraz między integerem
a numberem jest zależność taka że integer dziedziczy po number tu
możemy sobie sprawdzić tak extends number i po number jeszcze dziedziczą
takie klasy między innymi jak double float tak dalej no
więc teraz skoro mamy listę integerów integer
dziedziczy po number dość takim logicznym było
to że możemy wpisać listę integerów jako listę numberów
czyli w ten sposób tak jednak zobaczymy że kompilator nam
na to nie pozwoli o tutaj mamy incompatible types
no i wynika to z tego że w javie jeżeli nawet
integer liczy po numberze to już lista integerów po liście
numberów już niekoniecznie to by było prawdziwe dla tablic
tablice są tak zwane kowariantne ale
niestety dla typów generycznych jak na przykład lista która
jest wrapperem na integery no to już nie i teraz co
jeżeli byśmy chcieli mieć jednak dziś w kodzie jakieś miejsce do którego
dostajemy możemy mieć zmienną która przechowuje właśnie
listę numberów albo listę raczej wszystkiego co dziedziczy
po number to możemy też to zrobić wykorzystując
tak zwany wildcard to jest jeden z typów wildcard
znak zapytania extends number i
to znaczy dokładnie tyle że w tej zmiennej może
być trzymane wszystko co jest listą czegoś co dziedziczy
po number czyli z number włącznie no i teraz skoro lista
integerów zawiera integery a integery dziedziczą po number no to
możemy to jak najbardziej tutaj przypisać okej teraz to
był taki dość abstrakcyjny przykład ale załóżmy
sobie że chcemy stworzyć pewną klasę utilsową czyli
taką klasę pomocniczą która będzie dostarczała pewne metody pozwalające
na dodatkowe działania na listach nazwijmy ją sobie list
util okej i tutaj mam deklaracje
tej klasy jak ona wygląda okej i chcemy żeby ta
klasa miała jakieś metody swoje statyczne
tak nie chcemy dodatkowo aby było możliwe utworzenie instancji
tej klasy na co komu instancja list util ponieważ ona
będzie zawierała tylko metody i tak statyczne więc aby to osiągnąć utwórzmy
sobie prywatny konstruktor dzięki temu nie będziemy mogli
zrobić new na tej klasie tak nie możemy zrobić list util na tym teraz okej
zaimplementujmy teraz pierwszą z naszych metod pierwszą metodą będzie
metoda add która pozwala na dodawanie dwóch list do siebie oraz
zwracaniu nowej listy która jest wynikiem tego dodawania okej
tak będzie wyglądała na początku sygnatura tej metody ona
przyjmuje parametr generyczny taki sparametryzowany typem v
zwraca listę v oraz przyjmuje jako
dwa parametry odpowiednio listę pierwszą i drugą i teraz
zaimplementujmy sobie jak będzie działała ta metoda okej i zaimplementowałem
tę metodę ona na początku tworzy sobie listę od tej
możemy zmienić żeby to było list jest lepiej jest kodować do interfejsu
list niż do konkretnej implementacji oraz następnie dodaje
odpowiednio elementy pierwszej lisy i drugiej a następnie zwraca tę nowo utworzoną
listę teraz zobaczmy sobie jak będzie wyglądało wykorzystanie
tej metody z poziomu main'a okej utworzyłem sobie
jedną listę integerów drugą listę integerów oraz tutaj
wykonałem tą metodę add na razie nie dodawałem żadnych elementów bo
na razie operujemy tylko na typach więc nie interesuje nas samo dodawanie
sobie zauważmy że na razie to się wszystko kompiluje i
kompiluje się to dlatego że na razie dodajemy integery do integerów tak tu
podstawiamy listę integer 1 później
drugą listę integerów oraz zapisujemy też do listy która jest integerami tak
i teraz co jeśli chcemy dodać sobie listę integerów
oraz listę double jako wyjściowy typ byśmy chcieli mieć listę
numberów bo to jest logiczne ponieważ obie te integery i double
dziedziczą po number więc moglibyśmy mieć listę właśnie
numberów a nawet moglibyśmy mieć listę objectów tylko po co
lista numberów wydaje się być całkiem logiczna zmienimy
sobie teraz te adnotacje tutaj te typy okej
zmieniłem tu jak widzimy już niekoniecznie to się chce kompilować tutaj mamy
jakieś powiadomienie zostawimy błąd okej
tutaj możemy sobie spróbować wymusić który typ
ma zwracać tą metodę to znaczy jaki jest dokładnie typ którym jest ona parametryzowana
tu będzie number tak i tutaj widzimy że już parametry
są niewłaściwe tak powinniśmy dostać number number na wejściu
a dostajemy integera i double i to jest dokładnie ten sam problem
który widzieliśmy wcześniej jak pokazywałem to po prostu na wrzucaniu
listy integerów do pola do
zmiennej która jest listą numberów tutaj mamy dokładnie taką samą sytuację
ponieważ te listy które podajemy one muszą wylądować
jako zmienne będące parametrami tutaj i
tutaj on znowu nie chce wrzucić integera na przykład do numbera
który jest pod tym v no i tutaj musimy wykorzystać ten sam jak wykorzystać
wildcard tak czyli znak zapytania extends a dla
jednego jak też dla drugiego parametru i teraz nam to tutaj zadziała
pięknie okej to się
kompiluje to działa centralnie nic się tu nie dzieje pod
spodem tej nie ma żadnych zmiennych ale typy się zgadzają dobra teraz
załóżmy że chcemy sobie zaimplementować jeszcze drugą metodę ta
druga metoda będzie dostawała jedną listę jakiegoś typu
i musi przekopiować zawartość tej listy do
dwóch liczb które są pozostałymi parametrami tej metody nazwijmy
sobie tę metodę add twitch okej
tak będzie wyglądała sygnatura tej metody ona znowu jest parametryzowana typem
v dostanie nic nie zwraca tak zwraca void'a
ponieważ zawartość pierwszej listy jest przekopiowywana do pozostałych
dwóch parametrów tutaj czyli nie potrzebujemy jakiegoś typu zwracanego okej
i tutaj wszystkie z tych list są na razie typu v jak się domyślamy będziemy
musieli tutaj sobie coś pokombinować tak implementacja jest dosyć prosta tutaj
też do odpowiednio do każdej z tych liczb dodajemy używając add all zawartość
pierwszej listy okej teraz wykorzystajmy sobie tę metodę z maina okej
tutaj stworzyłem sobie listę numberów objectów oraz listę
integerów one są puste ale nie ma to znaczenia na razie oraz
tak próbuję chciałbym aby ta zawartość listy integerów
została przekopiowana odpowiednio do listy numberów oraz listy objectów
jako że każdy integer jest też numberem oraz każdy
integer i number jest również objectem no to powinno
tam się dać prawda jednak widzimy że znowu mamy tutaj jakieś problemy
wynikają one znowu z tego że pomimo dane tylko
sobie dziedziczą to nie możemy ich sobie nawzajem podstawiać
tutaj chcemy dostajemy jako typ wejściowy
możemy go sobie też tutaj wymusić żeby żeby mieć pewność dostajemy integer
tak i później tutaj powinniśmy
dostać również integer tak i wtedy java była
z tego powodu zadowolona tak kompilator nie był zadowolony no
ale tutaj musimy dalej kombinować z parametrami
tych pozostałych typów tutaj o tak te parametry muszą mieć trochę inny
typ i jak tutaj mieliśmy że zawartość tej listy
w tej liście musi być zawarte coś co extenduje v tak
to tutaj trochę inaczej tutaj nam to nie wystarczy tu raczej musimy
mieć listę do której legalne jest zapisanie v
czyli co w przypadku kiedy dostajemy integer'a
tutaj co jest legalną listą do której można zapisać no
właśnie to jest na przykład number oraz lista na
przykład objectów ta którą tutaj podajemy w przykładzie no
i teraz aby coś takiego zaimplementować wykorzystuje się inny wildcard
jest on znak zapytania super no i tutaj
to może być trochę mniej intuicyjne no bo tutaj mieliśmy listy wszelkie
listy które zawierają elementy rozszerzające v a tutaj mamy
wszelkie listy które co no tutaj są wszelkie
listy które mają elementy które są typem nadrzędnym
czyli właśnie number i object to będą takie listy
które które będą w tym miejscu legalne i zobaczymy czy teraz da się to wykorzystać
o widzimy że tutaj już tutaj widzimy że te
integer jest niepotrzebny w tym momencie on sam się tego domyśla okej
czy to się kompiluje kompiluje okej dobra
to mamy już opanowane dwa wildcardy tutaj mamy znak
zapytania extends v oraz mamy znak zapytania super v okej
widzimy że te problemy się pojawiają w momencie kiedy nie wszystkie nasze listy
wszystkie te nasze wrappery są identycznego typu czyli chcemy też korzystać
z tego że te obiekty zawarte w tych wrapperach jakoś po sobie też dziedziczą
tam jest jakiś ten jakiś polimorfizm tak dalej okej i
wtedy musimy właśnie zacząć kombinować na poziomie parametrów
metod oraz też deklaracji zmiennych
lokalnych używając tych wildcard'ów jeżeli będziesz
miał problem z dobraniem odpowiedniego wildcard'u do opisanej przez
ciebie metody to zapamiętaj sobie taką zasadę pecs poducer
extends consumer super znaczy to mniej więcej tyle że
jeżeli mamy powiedzmy jakiś obiekt który ma być producentem najlepiej
jest tu wykorzystać ten wildcard znak zapytania extends i dany
typ jeżeli za to będziemy mieli jakiś powiedzmy obiekt do
którego chcemy legalnie wstawiać obiekty danego typu no to wtedy wykorzystujemy
ten wildcard znak zapytania super i ten dany typ okej
i teraz jest jeszcze jeden wild card w javie zaraz
wam go przedstawię zaprezentuję wam go na przykładzie
metody która będzie miała za zdanie z listy zrobić
stringa który jest ładnie wyświetlany na razie gdybyśmy zrobili to string
na liście oraz próbowali go wyświetlić dostalibyśmy
tylko jego hash code oraz nazwę tego typu chcielibyśmy
żeby był on ładnie wyprintował co się znajduje w tej liście ta metoda będzie
się nazywała pretty to string na razie tak będzie wyglądała sygnatura
tej metody zobacz mój sparametryzowana typem generycznym tutaj zwraca
stringa i nazwa oraz jej parametr który jest jakąś listą tak teraz
zaimplementujmy ją sobie w środku okej
i do jej implemenatcji jako że nie chce wchodzić tutaj w tej implementacji tego
jak ją ładnie wyświetlić samodzielnie tak to chciałem wykorzystać
metodę arrays to list która ładniej już prezentuje
array a że z listy łatwo można zrobić array to po prostu
wykorzystamy sobie ją na potrzeby tego przykładu okej i to
jest metoda która się skompiluje najładniej wyświetlić
tutaj możemy to wykorzystać okej stworzymy jakąś listę wypełniłem
ją możemy zobaczyć co faktycznie tutaj nam się ładnie wyświetli
okej tutaj nie mamy jakiegoś już problemu z tym z jakimś
dziedziczeniem typów generycznych ale z tej listy
można wyciągnąć konkretny typ tak można get
i wyciągamy v i jeszcze wrzucić coś do
tej listy czyli wrzucając coś do metody pretty to string
na poziomie typów nie jesteśmy pewni czy czy ta lista na przykład nie zostanie
zmodyfikowana no jest to trochę taki naciągane ale istnieje
wildcard który pozwala zabezpieczyć się przed tym to jest
znak zapytania po prostu i on nas zabezpiecza przed wepchnięciem czegoś
do tej listy on pozwala na wyciąganiu elementów
z tej listy a właściwie na wywoływaniu metod które nie przyjmują
tego typu generycznego a jako parametr czyli na przykład możemy
robić geta na tym a on nam zwraca coś co idea nam stwierdzi
że jest object i to jest prawda tak w tym miejscu to będzie object
co prawda runtime to będzie coś innego no i możemy z tym zrobić
tyle co możemy zrobić z objectem tak ale na przykład nie jesteśmy upoważnieni do
tego żeby coś dodać bo nie jesteśmy w stanie zmajstrować takiego typu jaki
tutaj powinien zostać podany bez jakiegoś hakowania
tak zauważ że gdyby to była lista od typu v to
ciągle można by było tam wrzucić jakiś element coś z tym robić tak tutaj
na przykład jest pewne wykorzystanie tej tego wildcard'a ono
jest wykorzystane chociażby w collections w collections jest metoda
remove all i ona właśnie przyjmuje inną kolekcję
która jest dowolnego tutaj typu i następnie
sprawdza czy istnieją takie elementy w tej kolekcji z której była wywołana
ta metoda a następnie usuwa te elementy więc i tak jeżeli
jest coś ciągle można iterować po tych elementach z tej kolekcji ciągle
można wywoływać na tych wyciągniętych elementach metody
equals i hash code tak więc można sprawdzać porównywać można te obiekty
tak ale ze względu na to że nic więcej nie robimy z tą kolekcją
oraz nie wstawiamy do nich żadnych elementów no to ten znak zapytania jest tam
uzasadniony nawet jeżeli samodzielnie nie będziesz implementował
kontenerów czy jakichś wrapperów to warto abyś potrafił wykorzystać
te wildcard'y i wiedział jak one działają miał jakąś
taką intuicję abyś mógł łatwiej pracować z istniejącymi już bibliotekami
czy też kontenerami w javie jak zauważymy że wewnątrz
na przykład metody add na tym naszym utilsie mogliśmy zrobić
add all i w ogóle dlaczego mogliśmy zrobić add all
tutaj z czymś co dziedziczy po v ani dokładnie
z v wynika to z tego że add all też przyjmuje właśnie tutaj ma
tego wildcard'a wepchniętego i tak jeżeli chodzi o wildcard'y typach egenerycznych
to wszystko postaraj się trochę poeksperymentować z tym kodem powykorzystywać
wildcard'y i porównać je kiedy możesz użyć jakiegoś wildcard'u
do kiedy wystarczy ci sam typ generyczny bez niczego oraz
jakie metody możesz wywoływać w zależności od tego jak zadeklarowałeś dany
parametr w metodzie dzięki wielkie i do zobaczenia