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.
Jak wspominałem w jednej z pierwszych lekcji w tym rozdziale pliki
możemy czytać w sposób sekwencyjny i wtedy wykorzystujemy poznane już strumienie
lub możemy je też czytać z dostępem swobodnym random access
tak takie pliki zazwyczaj mają jakąś narzuconą scheme tak schemat
mają i może nie zawsze chcemy czytać je od początku do końca albo chcemy
na przykład przeczytać jakiś kawałek później wrócić się i przeczytać jakiś inny
kawałek lub coś możemy chcieć na przykład przeczytać jakiś fragment i podmienić go już
w tym pliku tak przy dostępie takim sekwencyjnym nie za bardzo
mamy takie możliwości zobaczymy jednak możemy sobie poradzić z takimi
wymaganiami wykorzystując właśnie random access tutaj jako zdanie w tym
przykładzie postawy sobie tak mamy tutaj path do skompilowanej
wersji tej klasy którą właśnie piszemy to jest ciekawa rzecz w sumie ta klasa
w postaci skomplikowanej znajduje się na przykład w katalogu out
u mnie się znajduje u was może być w trochę innym katalogu musisz sobie znaleźć i on tutaj
intellij jak otworzę sobie tej klasę on tu podpowiada twierdzi że to jest
powiedzmy właśnie pokazuje javę ale mówi że to jest po prostu zdekompletowana
wersja tego pliku i w rzeczywistości ten plik jest binarny w tym momencie okej
tutaj mamy path do niego spróbujemy sobie otworzyć taki plik właśnie w tym
random access oraz odczytaj z niego nagłówek między innymi ten nagłówek
składa się tutaj jest taki początek tego tego pliku skopiowany
z wikipedii i on zawiera magic number który zawsze jest w postaci cafebabe
i później jest minor version in major version to jest wersja
javy na jaką został skompilowany ten kod i chcemy sobie odczytać te dane
w tym momencie okej jak się do tego zabrać w tym trybie random access
służy do tego klasa random access file i tworząc tę klasę
podajemy tutaj właśnie file path może być w postaci stringa
ale też podajemy jeszcze mode z tego względu że random access file
możemy wykorzystywać do odczytu do zapisu albo
do jednego i drugiego na raz więc na razie sobie dajemy że tu jest read i też tak
samo jak w przypadku otwierania strumienia on może powiedzieć że nie ma takiego pliku więc
to teraz sobie opakujemy w try with resources okej tak to wygląda ten
obiekt nazwałem raf czyli od random access file i teraz zobaczymy co w nim jest ciekawego
tutaj są write read wszystkie elementy które powiedzmy
są takim mergem tego file writer file reader oraz
też ich wersje binarne tak i teraz spróbujmy sobie odczytać
właśnie najpierw magic number w tym celu jeszcze utworzymy sobie bufor
i teraz mógłbym tutaj wykorzystywać przy metodzie read też bufor
był w postaci jakiegoś arraya tak ale żeby wygodniej
się trochę pracowało i nie tworzyć dużo powiedzmy tych arrays to możemy sobie też
wykorzystać obiekt klasy byte buffer tworząc byte buffer podajemy
na jakiego rozmiaru ma być ten bufor na razie skoro chcemy odczytać magic
number który tutaj to u4 oznacza że on jest 4 bajtowy
na razie zaalokujmy sobie po prostu 4 zapiszmy też sobie że to
jest buffer na 4 bajty tak w ten sposób okej
i teraz jak bierzemy sobie read to po prostu podajemy ten buffer ale robimy na nim
jeszcze array w tym momencie on się normalnie jest byte bufferem
ale jak wywołamy na nim array to pokazuje nam znajdujący się pod spodem array
tak przedstawia się tą tablicą teraz nie podajemy offsetu
limitu z tego względu zostanie to dopasowane do tego jakiej wielkości
jest ten array dokładnie cztery bajty chcemy odczytać w tym momencie ok i teraz sobie
wyprintujmy co co było w tym w tym buferze w tym celu wykorzystajmy sobie get int
z tego względu że integer javowy jest 32-bitowy
tak czyli to są dokładnie 4 bajty wyprintujmy to sobie w tym momencie okej
i dostaliśmy jakąś taką tajemniczą liczbę jeszcze na minusie i teraz aby
dostać powiedzmy zobaczyć sobie jak wygląda ten magic number to powinniśmy
sobie jeszcze wyprintować to w postaci heksadecymalnej w tym celu możemy
wykorzystać integer oraz metodę to hex string i ona podaje dostaje po prostu
integera oraz wyprintuje nam go w postaci właśnie heksadecymalnej no i tutaj mamy cafebabe
tak czyli właśnie ten magic number i analogicznie pozostałe pola możemy
wyprintować tutaj jest tylko jedną ważną rzeczą to że jeżeli wykorzystamy array
i później na nim zrobimy get to przesuwa nam się offset tutaj
tego nie widzimy ale jak sobie znajdziemy implementację no
to on będzie teraz przesuwał nam ten offset tak i tutaj
ustawie teraz position właśnie od jakiego następnym razem zacznie
pytanie więc jeżeli chcemy przeczytać kolejny element powiedzmy
jeszcze raz został ten bufor powiedzmy wykorzystany to możemy wcześniej wywołać
sobie clear tutaj i on zeruje powiedzmy te position albo
możemy po prostu robić geta poszczególne get tutaj jeszcze z indeksem
od którego chcemy czytać tak to będzie wyglądało tutaj
stworzymy sobie bufor który będzie zawierał 2 bajty z tego względu że nie chce żeby nam się tutaj mieszało
to i drugą rzeczą jest to że wykorzystuje get short z tego względu że
minor i major version to są tylko 2 bajty więc short
tutej odpowiada i teraz jak to sobie odpalimy to dostajemy oczywiście magic
code tak magic number i później jest minor version
zero w tym momencie tak dla tej klasy oraz 54 54
to jest major version java 10 tak z tego względu że ja mam
takie jdk obecnie ustawione to tak mi się to skompilowało na przykład dla
javy 9 by było 53 52 dla 8
i tak dalej prawda okej i teraz już pomijając to jak wygląda class
file tak to ważną rzeczą tak na prawdę tą dla której
tutaj przyszliśmy do tego random access file'a jest to że
w random access file możemy się cofać to jest jedna rzecz tutaj możemy zrobić seek
tutaj możemy podać offset do którego mamy się cofnąć do którego mamy skoczyć
i jeżeli wykorzystamy sobie właśnie czytanie z tym seek'iem to
możemy sobie spokojnie wyekstraktować czytanie na przykład magic code
magic number'a oraz poszczególnych tych pól do metod i po prostu wewnątrz
nich jeżeli chcemy przeczytać to możemy zrobić seek on skoczy do tego offsetu
przeczyta ten fragment i tyle i teraz będziemy mogli wywoływać
te metody w dowolnej kolejności tak jak mieliśmy strumień to musieliśmy lecieć po kolei
i powiedzmy jeszcze jeżeli był jakiś fragment który nas interesował
i chcielibyśmy go na później to musieliśmy go albo zapisać sobie na
boku gdzieś albo na heap albo do innego pliku albo musielibyśmy
zamknąć ten plik i go otworzyć jeszcze raz tak i jeszcze raz
go wczytać do tego fragmentu tutaj nie ma tego problemu spróbujmy sobie to wydzielić teraz na oddzielne
metodu okej tak to by mogło wyglądać tutaj ma odpowiednio metody get
magic number and get minor version major version i każda z nich sama
wie w które miejsce tego pliku ma skoczyć prawda odpowiednio tutaj 0 4 6
tak i tutaj sobie wyświetlam te dane tak to w ten sposób działa i nie ma
problemu jeżeli na przykład zrobię to w odwrotnej kolejności tak tutaj po prostu w odpowiednim
momencie kiedy chcemy mieć magic number tak no to on
po prostu skoczy do zera poza tym że możemy robić tego seek'a to też tak jak na początku widziałeś
ten offset też wewnątrz tego pliku się przesuwa możemy też podejrzeć
w którym miejscu jesteśmy obecnie na tym offsecie możemy do tego wykorzystać metodę
get file pointer tak ją możemy debugować oraz możemy też
śledzić w którym miejscu jesteśmy dokładnie tak pisząc na przykład jakieś
parset czy coś takiego tutaj widzimy że tutaj byliśmy
w numer 4 później byliśmy w szóstce tak
po przeczytaniu tego byliśmy w ósemce ale później jako że get magic number
skoczył do zera tak i odczytał 4 bytes to byliśmy w czwórce i
tutaj widzimy że faktycznie jest 4 tak tu w zależności od tego jak napiszemy
nasz program możemy się opierać na tym automatycznym przesuwaniu bo ono jest
wygodne a dla części rzeczy możemy na przykład po prostu tam skakać w odpowiednie
miejsca które nas interesują teraz taką ciekawą właściwością tego pliku jest
to że z tej poza tym że czytamy możemy też zapisywać wystarczy zmienić tutaj mode
i możemy na przykład podmienić magic number albo możemy podmienić
major version na przykład tak na możemy zmienić go na niższy nie
ma to większego sensu nawet w niektórych przypadkach taka
klasa a może zadziałać o ile nie wykorzystywaliśmy wewnątrz
jakiś powiedzmy elementów które powiedzmy łamią tą kompatybilność
tak abstrahując od tego czy to ma większy sens spróbujmy sobie podmienić
odpowiednio byte szósty i byte siódmy licząc od zera okej
tak by to wyglądało stworzyłem metodę set major version która po prostu
dostaje major version w postaci shorta którego ma ustawić
skacze pod 6 offset no i ustawia tak tu robię write short tu
już buffera nie potrzebujemy no i w ten sposób możemy sobie zmienić tylko te 2 bajty
tak na przykład później dalej czytać pozostałe jakieś pola tego
pliku podmieniać tak no i teraz to sobie uruchommy okej podmieniło
nam się 54 widzimy że było na początek później było 53
i teraz jak uruchomimy to jeszcze raz to jest 53 53 to jest taka ciekawostka
że nawet udało się załadować tę klasę tak bo teraz nie
robiąc żadnej rekompilacji po prostu intellij wciągnął tę klasę
i uruchomił na niej ten program tak czyli powiedzmy sami sobie podmieniliśmy
trochę oczywiście pomiędzy dwoma uruchomieniami z tego względu że
za pierwszym razem jak zmienialiśmy tego kod
tej klasy tak zawartość tego pliku to i tak zanim
jest uruchomiona ta klasa to ona jest wczytywana do pamięci tak więc nie ma
z tym problemu że my w runtime sobie podmieniamy coś ale jak widzimy nawet da się tak uruchomić
teraz jak sobie ustawimy na przykład jakąś dziwną wartość na przykład 20
za pierwszym razem uruchomienie nam się uda tak zmieniliśmy z 54
na 20 tutaj w tym momencie jak to zmienialiśmy to ta klasa
tak ten plik był w ramie tak w pamięci więc czemu to
nie szkodziło ale jak spróbujemy jeszcze raz uruchomić tę klasę to dostajemy
taki fajny exception unsupported class version error no
to taka ciekawostka w tym momencie musielibyśmy zrobić recompile tak rebuild
project no i teraz jak uruchomimy to już wszystko będzie dobrze okej to jest
wszystko jeżeli o random access file to jest taka klasa którą całkiem
wygodnie można użyć do współpracy z niskopoziomowymi plikami
binarnymi które wiemy że mają jakiś format tak i chcemy powiedzmy coś tam pokręcić
się po tym pliku i zobaczyć co tam się dzieje jeżeli chcesz to możesz też
znaleźć na wikipedii resztę tego co się znajduje w tym pliku tak
tutaj czytając dalsze elementy musiałbyś napisać trochę kodu który interpretuje
tablice też nie jest z góry powiedziane jednak jakiej wielkości
jest ta tablica w bajtach więc nie do końca wiadomo jak tam skoczyć ale jeżeli
jesteś ciekawy to bardzo polecam rozwiązanie takiego zadania tak
więc na tę lekcję to wszystko dzięki wielkie i do zobaczenia