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.
Do tej pory czytaliśmy z pliku znak po znaku jest
to jednak trochę niewydajne z tego względu że za każdym razem kiedy wywołujemy tutaj
read niezależnie czy to jest file reader czy file input stream
wywołujemy akcję na dysku tak odczytujemy te jeden
bytes bądź więcej bajtów jeżeli to jest powiedzmy jakiś znak który się
składa z kilku bajtów jak w przypadku na przykład w utf8 tak może być no
ale to jest powiedzmy niewydajne tak lepiej by było odczytać na raz powiedzmy
kilka znaków później gdzieś je sobie przechowywać powiedzmy zakładając że będziemy
czytali cały ten plik to prawdopodobnie jeżeli sobie odczytamy naraz na przykład 100 znaków
czy tam 200 to jest duże prawdopodobieństwo że za chwilę będą nam one znowu
potrzebne tutaj jeszcze jedna uwaga zanim w ogóle zaczniemy to robić dlaczego
my używamy tych streamów i dlaczego na przykład w streamie nie możemy się cofnąć
chodzi o to że strumienie przez swoją tak jakby budowę
tą semantykę dostępu do tego strumienia chcą narzucić pewien
design w odczycie tego pliku chodzi o to żeby nie
odczytywać za dużo na przykład nie możemy tutaj wywołać sobie read all tak ponieważ
gdyby ten plik miał na przykład nie wiem 4 czy kilkanaście gigabajtów to
momentalnie byśmy zapełnili cały heap tak w naszym programie więc
właśnie te klasy z readerów writerów tak dalej zostały
tak zadesign'owane aby to trochę utrudnić i trochę narzucić ten styl programowania
na ale mimo wszystko jakieś takie drobne buforowanie powiedzmy żeby
powiedzmy na raz brać 200 400 czy 1000 znaków nie
powinno nam bardziej zaszkodzić więc może nam pmoże pod względem wydajności tego
czytania tak okej więc teraz zaimplementujmy sobie takie wyczytywanie
powiedzmy tych znaków w takich chunk'ach ułatwi nam to tutaj takie
przeciążenie metody read które przyjmuje bufor tak tutaj jest
po prostu jest array okej my sobie utwórzmy taki bufor okej
ja sobie tutaj utworzyłem bufor który ma 256 znaków jeszcze można sobie tą
długość bufor size gdzieś wyekstraktować
tak buffer dobrze i używając tego buforu możemy właśnie sobie
czytać to jeszcze ważną rzeczą jest to że zapisując
do tego bufor podajemy offset od którego ma być zapisywana ta wartość czyli
w naszym przypadku chcemy wykorzystać cały bufor więc będzie to od zera oraz
liczbę znaków które mogą być maksymalnie zapisane do tego buferu po
prostu będzie buffer size w tym momencie i to nam się zapisało tylko teraz jeżeli
powiedzmy używamy tej przeciążonej wersji read tak
to on już nie zwraca teraz znaku odczytanego tylko zwraca liczbę
odczytanych znaków i minus 1 i można było powiedzieć że możemy tutaj dopóki nie
dostaniemy minus jedynki ale ciągle nam potrzebna jest liczba znaków
odczytanych ponieważ bez tego nie jesteśmy w stanie za bardzo
interpretować tego co wpadło do tego buforu ponieważ oczywiście większości przypadków
dostaniemy tutaj po prostu 256 znaków tak ale
na przykład jeżeli dobrniemy do końca pliku i ten rozmiar
tego pliku nie będzie wielokrotnością 256 to dostaniemy nie
pełen bufor więc wtedy warto trzymać tą wartość i czytając tego
bufora po prostu brać sobie od zera do read characters
tak okej z tak otrzymanego buforu możemy sobie stworzyć stringa
tak jakiś łańcuch znaków w tym celu wywołujemy po prostu new string i
on tu w parametrze może dostać właśnie powiedzmy tablice ten
właśnie offset i length który nam się też przyda ponieważ inaczej on by nie wiedział jak
zinterpretować powiedzmy tę wartość którą dostaje powiedzmy że buffer
zero i tutaj podajemy właśnie read characters okej mamy stringa
no i możemy go sobie wyświetlić tak okej tak otrzymany
powiedzmy w ten sposób wyprintowany ten plik on jest dużo
dużo bardziej powiedzmy wydajne w przypadku większych plików nam da to większą wydajność
a też ze względu na to że dostajemy powiedzmy ten bufor i
printujemy to co w nim jest nie doklejamy tego do żadnej zmiennej to niezależnie
jak duży byłby ten plik to nie przepełnimy wtedy heap'a ponieważ
od razu printujemy nigdzie powiedzmy nie akumulujemy tych danych tych danych okej to
i to samo możemy zrobić dla file input stream po prostu tam byśmy mieli
bufor który zawiera nie char tylko zawiera po prostu byte okej
tak sobie zaimplementowaliśmy samodzielnie buforowanie mam nadzieję że czujesz już
teraz tak intuicyjnie o co z tym chodzi jaka jest ta różnica wydajnościowa teraz
możemy też wykorzystać do tego buforowania zaimplementowane
już klasy to są takie dekoratory czyli powiedzmy taki otoczki wrappery które
dodają pewną wartość powiedzmy jakiś dodatkowych właściwości do tych obiektów no
i takie właśnie otoczki istnieją dla readerów writerów inputstream'ów i output
streamów które właśnie załatwiają buforowanie za nas w przypadku readera
będzie do tego służyła klasa buffered reader tego bufferedreader
powiedzmy tworzy się podając readera którego on ma opakować
tak czyli podajemy file readera czy jakiegokolwiek innego readera który on ma buforować
tutaj wewnątrz w konstruktorze no i to po prostu tutaj zadziała tak jeszcze
możemy też podać tutaj jako drugi parametr wielkość tego
buforu tak czyli jak u nas było to 256 to możemy też tutaj podać jeżeli
chcemy mieć dokładnie taki sam bufor ale nawet sam bufferedreader używa
innej domyślnej wielkość bufora to jest 8192
tak no i więc na razie to zostawmy okej jak sobie odpalimy już z tym
buffered readerem to widzimy to nam dalej się buforuje ładnie nam się wyświetla i teraz
jeżeli mam tego buffered readera teoretycznie moglibyśmy się pozbyć
tego ponieważ to buforowanie już jest zapewniony w tej w tym bufferedreaderze
prawda no tak ale ciągle ta tablica tutaj tak ten bufor nam
ułatwia odczytywanie z tego readera bierzemy po jakimś większym chunku a
nie bierzemy po jednym znaku tak więc ciągle nam to się przydaje bufferedreader
możemy też użyć do odczytywania całych linii z danego strumienia
używam do tego metody readline która w odróżnieniu od poprzednich metod nie zwraca mi
minus jedynki tylko null jeżeli skończy się po prostu strumień no i tak uzyskaną
linię zapisujemy do jakiejś jakiegoś uchwytu powiedzmy
na stringa tak do zmiennej lokalnej typu string no i później możemy wyświetlić tutaj
jeszcze jest taki szczegół że ta metoda nie zwraca znaków
końca linii tak więc musimy go sobie dodać tak w jakiś sposób tutaj
taka trochę ciekawostka i podatność metody readline ona może zwrócić
linię która jest większa od tego buforu który jest podany
przy tworzeniu bufferedreadera z tego względu jeżeli użytkownik poda wam
plik który jest bardzo duży i powiedzmy zawiera ten tekst w
jednej linii na przykład ja sobie otworzyłem 4 gb plik
w jednej linii powiedzmy jest wszystko tak znaki no to użytkownik może łatwo wywołać
u was out of memory exception tak jak tutaj na przykład tak a tu w memory error
java spróbuje utworzyć czytać ten plik tak i będzie
wrzucał go na heap'a jako jeden powiedzmy string no i go po prostu przeciąży
więc jeżeli chcecie być tacy powiedzmy bardzo bezpieczni bardzo nie ufacie użytkownikowi
tak w sumie prawidłowo tak warto wtedy nie
używać tej metody i ciągle używać tego poza tym że używacie buffered reader'a bo
to jest dobre ze względu na optymalizację tak to jeszcze z niego
czytać tym takim małym buforem powiedzmy w postaci jakiegoś array'a tak
jeśli jednak czytasz plik tekstowy i masz pewność odnośnie
danych tam znajdujących się na przykład zostały one dostarczone przez ciebie tak
wygenerowane z jakiegoś programu którego ty używasz ty stworzyłeś z jakiegoś innego systemu i
możesz zaufać tym danym nie przejmujesz się obecnie jakimiś problemami z tym na przykład robisz
po prostu analizę tego co tam jest no to możesz spokojnie używać tego readline
tak pewnie to będzie jedna z wygodniejszych metod pracy z takim plikiem tak jak
już mówiłem buffered reader jest dla odczytu tekstowego i istnieje
analogiczna klasa która się po prostu nazywa buffered input stream
tak tutaj ona działa analogicznie istnieją również dekoratory
buforujące na strumienie wyjścia czyli na na przykład na file
output stream czy file writery i wykorzystanie jednak zobaczymy w
lekcji poświęconej zapisowi do pliku to wszystko na te lekcje dzięki wielkie
i do zobaczenia