Programowanie w języku Java WYKŁAD

Podobne dokumenty
Strumienie i serializacja

Biblioteki wejścia/wyjścia. Strumienie we/wy (I/O)

Wykład 4: Wejście/wyjście: strumienie Java

Języki i Techniki Programowania II. Wykład 6. Wejście/Wyjście

Kurs programowania. Wykład 10. Wojciech Macyna. 05 maja 2016

dr Krzysztof Podlaski

STRUMIENIE DANYCH, SERIALIZACJA OBIEKTÓW

Programowanie Obiektowe (Java)

Wstęp do Java. Operacje Wejścia-Wyjścia Programowanie Wielowątkowe. dr Krzysztof Podlaski. Wydział Fizyki i Informatyki Stosowanej

Podstawy otwartych języków programowania Wyjątki i strumienie I/O

JAVA. Strumienie wejścia i wyjścia. Pliki - zapis i odczyt

Język JAVA podstawy. Wykład 6, część 2. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Rozdział 7 Strumienie, operacje wejścia-wyjścia

STRUMIENIE TEKSTOWE WEJŚCIOWE WPROWADZANIE DANYCH STRUMIENIE BAJTOWE, STRUMIENIE TEKSTOWE

Java niezbędnik programisty spotkanie nr 11. Importy statyczne, wejście/wyjście, wyrażenia regularne, serializacja

Przygotował: Jacek Sroka 1. Java SE. Strumienie

Strumienie, pliki. Sortowanie. Wyjątki.

Java Zadanie 1. Aby poprawnie uruchomić aplikację desktopową, należy zaimplementować główną metodę zapewniającą punkt wejścia do programu.

Wykład 10: Wejście i Wyjście

KOMUNIKACJA MIĘDZYPROCESOWA O B S Ł U G A WEJŚCIA/WYJŚCIA

I/O (STRUMIENIE, PLIKI,...)

Programowanie obiektowe

K O M U N I K A C J A MIĘDZYPROCESOWA O B S Ł U G A WEJŚCIA/WYJŚCIA

Strumienie, pliki. Sortowanie. Wyjątki.

Podstawy i języki programowania

Platformy Programistyczne Zagadnienia sieciowe i wątki

1 Klasa File. 2 Writer. Programowanie w j zyku Java - Adam Krechowicz. Klasa File zapewnia podstawowe operacje na plikach

Programowanie obiektowe

Języki i metody programowania Java INF302W Wykład 4

Programowanie Obiektowe Java

Programowanie obiektowe

Programowane refleksyjne i serializacja

Programowanie obiektowe

JAVA I SIECI. MATERIAŁY:

Inynieria oprogramowania Lecture XXX. Java TM cz IV: IO. Bartosz Walter

Wykład 2. Strumienie tekstowe (wprowadzanie danych z klawiatury) i bajtowe, otwieranie strumieni poprzez sieć - obiekty URL

Programowanie Obiektowe Java

Java. Programowanie Obiektowe Mateusz Cicheński

Strumienie tekstowe (wprowadzanie danych z klawiatury) i bajtowe, otwieranie strumieni przez sieć - obiekty URL

Programowanie obiektowe zastosowanie języka Java SE

Aplikacje RMI. Budowa aplikacji rozproszonych. Część 2.

Wykład 6 Dziedziczenie cd., pliki

Java w 21 dni / Rogers Cadenhead. Gliwice, cop Spis treści. O autorze 11. Wprowadzenie 13 TYDZIEŃ I JĘZYK JAVA

Aplikacje w Javie wykład 9 Strumienie

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Wykład 2: Podstawy Języka

Sposoby tworzenia projektu zawierającego aplet w środowisku NetBeans. Metody zabezpieczenia komputera użytkownika przed działaniem apletu.

Język JAVA podstawy. Wykład 6, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Programowanie rozproszone w języku Java

Programowanie obiektowe

Dokumentacja do API Javy.

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

Bezpieczne uruchamianie apletów wg

System obsªugi wej±cia i wyj±cia.

Java: Graficzne interfejsy użytkownika

Informatyka I. Typy danych. Operacje arytmetyczne. Konwersje typów. Zmienne. Wczytywanie danych z klawiatury. dr hab. inż. Andrzej Czerepicki

1 Atrybuty i metody klasowe

Programowanie współbieżne i rozproszone

Komunikacja z użyciem gniazd aplikacje klient-serwer

Zaawansowane techniki programowania C#

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Korzystanie z bibliotek standardowych

Aplikacja wielowątkowa prosty komunikator

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Programowanie w Internecie. Java

Biblioteka standardowa - operacje wejścia/wyjścia

WSNHiD, Programowanie 2, Lab. 3. Trwałość danych

Kurs programowania. Wykład 7. Wojciech Macyna. 25 kwietnia 2017

Programowanie obiektowe

Język JAVA podstawy. wykład 2, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Programy typu klient serwer. Programowanie w środowisku rozproszonym. Wykład 5.

Wprowadzenie do języka Java

Apilkacje w środowisku Java - wykład 10 Strumienie

MATERIAŁY POMOCNICZE DO ĆWICZENIA 3 Klasy i obiekty; atrybuty i metody

Programowanie w języku Java (OCA+OCP)

Java. Michał Wójcik.

Programowanie w Javie Lista nr 1. Wybieramy kategorię Java, a wśród Projektów Java Application i [NEXT]

Projektowanie aplikacji internetowych laboratorium

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

Programowanie proceduralne INP001210WL rok akademicki 2018/19 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

Architektura rozproszonych magazynów danych

Prototype (prototyp) Cel: Przykład: Określenie rodzaju tworzonych obiektów poprzez wskazanie ich prototypu. Nowe instancje tworzymy kopiując prototyp.

Java. Wykład. Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

Programowanie obiektowe

Programowanie w języku Java

Języki i metody programowania Java INF302W Wykład 3 (część 1)

Obiektowe programowanie rozproszone Java RMI. Krzysztof Banaś Systemy rozproszone 1

Sun Certified Java Programmer. Harmonogram szkolenia

Aplikacje w Javie- wykład 11 Wątki-podstawy

Funkcje zawarte w bibliotece < io.h >

Java - wprowadzenie. Programowanie Obiektowe Mateusz Cicheński

Języki i metody programowania Java. Wykład 2 (część 2)

WPROWADZENIE DO JĘZYKA JAVA

akademia androida Składowanie danych część VI

Aplikacja wielow tkowa prosty komunikator

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.

Praktyczne aspekty programowania w Javie wydajność programu w zakresie automatycznego zarządzania zasobami

KLASY, INTERFEJSY, ITP

Funkcje zawarte w bibliotece < io.h >

Wprowadzenie. Narzędzia i środowiska programistyczne. Laboratorium 1. Prowadzący: Kierunek: Semestr: Rok: Tomasz Gądek Informatyka Zimowy 2

Transkrypt:

Programowanie w języku Java WYKŁAD dr inż. Piotr Zabawa Certyfikowany Konsultant IBM/Rational e-mail: pzabawa@pk.edu.pl www: http://www.pk.edu.pl/~pzabawa 31.03.2014

WYKŁAD 6 Operacje we/wy

Operacje we/wy Biblioteki standardowe ze strumieniami: java.io java.nio oraz zmiany wprowadzone w ramach Java 8.

Operacje we/wy Ze względu na dużą różnorodność klas w bibliotekach we/wy intensywnie wykorzystywany jest wzorzec projektowy Dekorator. Pozwala on na składanie obiektów tej biblioteki w ogromnej ilości kombinacji. Zostanie to zilustrowane przykładami.

Operacje we/wy Strumień jest pojęciem abstrakcyjnym mającym następujące cechy: strumień związany jest ze źródłem lub odbiornikiem danych źródło lub odbiornik mogą być dowolne: plik, pamięć, URL, gniazdo, potok... strumień służy do zapisywania-odczytywania informacji - dowolnych danych program: kojarzy strumień z zewnętrznym źródłem/odbiornikiem, otwiera strumień, dodaje lub pobiera dane ze strumienia, zamyka strumień. przy czytaniu lub zapisie danych z/do strumienia mogą być wykonywane dodatkowe operacje (np. buforowanie, kodowanie-dekodowanie, kompresjadekompresja) w Javie dostarczono klas, reprezentujących strumienie. Hierarchia tych klas pozwala na programowanie w sposób abstrahujący od konkretnych źródeł i odbiorników.

Operacje we/wy Wprowadzono w bibliotece we/wy różne rodzaje klas i interfejsów: Strumieniowe Dodatkowe

Operacje we/wy Kierunki operacji strumieniowych: Wejściowe Wyjściowe Rodzaje strumieni: Bajtowe (1 bajt) Znakowe (2 bajty, bo Unicode) Dodatkowe zagadnienia: Serializacja Operacje na plikach

Operacje we/wy Wierzchołek hierarchii klas strumieniowych przedstawiono w tabelce poniżej. Wejście Wyjście Strumienie bajtowe InputStream OutputStream Strumienie znakowe Reader Writer Te abstrakcyjne klasy oferują podstawowe funkcjonalności: read() write() skip(), mark(), reset() close()

Operacje we/wy Strumienie: Bajtowe: (Stream) Wejściowe (InputStream, FilterInputStream,...) Wyjściowe (OutputStream, FilterOutputStream,...) Znakowe (Reader, Writer) Wejściowe (InputStreamReader,...) Wyjściowe (OutputStreamReader,...)

Operacje we/wy - klasy przedmiotowe Strumieniom trzeba prędzej czy później wskazać konkretne źródło lub odbiornik. Można je sklasyfikować następująco klasy przedmiotowe: Pamięć Potok Źródło/odbiornik Strumienie bajtowe Strumienie znakowe FileReader, FileWriter ByteArrayInputStream, ByteArrayOutputStream StringBufferInputStream PipedInputStream, PipedOutputStream CharArrayReader, CharArrayWriter StringReader, StringWriter PipedReader, PipedWriter - FileInputStream, FileOutputStream Klasy przedmiotowe mogą dotyczyć innych zasobów są dostępne w innych pakietach, np. sieciowych.

Operacje we/wy - klasy przetwarzające W czasie wykonywania operacji na strumieniach mogą być wykonywane dodatkowe operacje wzbogacające funkcjonalność dotychczasowych klas o dodatkowe zobowiązania.

Rodzaj przetwarzania Strumienie bajtowe Strumienie znakowe Buforowanie Filtrowanie Konwersja: bajty-znaki Konkatenacja Serializacja obiektów Konwersje danych BufferedInputStream, BufferedOutputStream FilterInputStream, FilterOutputStream SequenceInputStream ObjectInputStream, ObjectOutputStream DataInputStream, DataOutputStream BufferedReader, BufferedWriter FilterReader, FilterWriter InputStreamReader, OutputStreamWriter Zliczanie wierszy LineNumberInputStream LineNumberReader Podglądanie PushbackInputStream PushbackReader Drukowanie PrintStream PrintWriter

Operacje we/wy strumienie bajtowe Strumienie bajtowe traktują dane jak zbiór ośmiobitowych bajtów. Wszystke strumienie bajtowe dziedziczą z klas: InputStream (dane przychodzące do programu) lub OutputStream (dane wychodzące z programu). Strumienie zawsze należy zamykać! Strumienie bajtowe reprezentują niskopoziomowy dostęp do danych.

Operacje we/wy strumienie bajtowe Szczególnym rodzajem strumieni bajtowych są strumienie binarne - koniec strumienia rozpoznaje się jako wyjątek EOFException. Klasyfikacja strumieni binarnych: strumienie danych (zapis/odczyt surowych danych) DataInputStream DataOutputStream strumienie obiektowe (serializacja/deserializacja obiektów) ObjectInputStream ObjectOutputStream

Operacje we/wy strumienie bajtowe Strumienie bajtowe wejściowe InputStream przodek hierarchii, istotne metody: int read(), int read(byte[]), int read(byte[], int, int) PipedInputStream służy do komunikacji wewnątrz programu ByteArrayInputStream strumień czytający z tablicy FilterInputStream przodek strumieni wprowadzających dodatkową funkcjonalność DataInputStream operujące na typach prymitywnych BufferedInputStream strumień buforowany GZIPInputStream strumień dekompresujący w locie dane przez niego przechodzące SequenceInputStream skleja kolejne strumienie

Operacje we/wy strumienie bajtowe Strumienie bajtowe wyjściowe OutputStream przodek hierarchii, istotne metody: write(int), write(byte[]), write(byte[],int,int) PipedOutputStream służy do komunikacji wewnątrz programu ByteArrayOutputStream strumień piszący do tablicy FilterOutputStream przodek strumieni wprowadzających dodatkową funkcjonalność DataOutputStream operujące na typach prymitywnych BufferedOutputStream strumień buforowany GZIPOutputStream strumień kompresujący w locie dane przez niego przechodzące FileOutputStream strumień piszący do pliku

Operacje we/wy strumienie bajtowe Klasy buforowanych strumieni bajtowych: BufferedInputStream BufferedOutputStream Pozwalają one na zapis/odczyt całymi liniami (buforowanie).

Operacje we/wy - strumienie znakowe Strumienie znakowe automatycznie konwertują dane tekstowe do stosowanego natywnie w Java formatu Unicode. Konwersja jest dokonywana w oparciu o ustawienia regionalne komputera, na którym uruchomiono JVM (Wirtualną Maszynę Javy) lub jest oprogramowana przez programistę. Strumienie znakowe dziedziczą z klas: Reader (dane przychodzące do programu) lub Writer (dane wychodzące z programu).

Operacje we/wy - strumienie znakowe Strumienie znakowe wejściowe Reader przodek hierarchii; istotne metody: write(int), write(byte[]), write(byte[],int,int) BufferedReader buforowany strumień znakowy: podstawowa metoda String readline() LineNumberReader strumień zliczający numery linii CharArrayReader strumień piszący do tablicy znaków PipedReader analogiczny do PipedOutputStream InputStreamReader połączenie strumienie znakowych i bajtowych FileReader strumień skierowany do pliku

Operacje we/wy - strumienie znakowe Strumienie znakowe wyjściowe Writer przodek hierarchii; istotne metody: write(int), write(char[]), write(string) BufferedWriter buforowany strumień znakowy CharArrayWriter strumień piszący do tablicy znaków PipedWriter analogiczny do PipedOutputStream OutputStreamWriter połączenie strumienie znakowych i bajtowych FileWriter strumień skierowany do pliku PrintWriter podobny do PrintOutputStream, ale nie dysponuje metodami do obsługi byte[]

Operacje we/wy - strumienie znakowe Klasy buforowanych strumieni znakowych: BufferedReader BufferedWriter Pozwalają one na zapis/odczyt całymi liniami (buforowanie).

Operacje we/wy - strumienie znakowe Przykłady: Stdin String s; BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); while ( (s = br.readline())!= null ) { } System.out.println(s); Strumienie znakowe buforowane umożliwiają odczytywanie tekstu wierszami.

Operacje we/wy - strumienie znakowe Stdout String fname = "c:\\data\\output.txt"; Writer writer = new OutputStreamWriter(new FileOutputStream(fname)); writer.write("hello World"); writer.close();

Operacje we/wy - strumienie znakowe Przykład dekorowania: String s; BufferedReader br = new BufferedReader( new InputStreamReader( new GZIPInputStream( new FileInputStream( new File( data.txt.gz ))))); while ( (s = br.readline())!= null ) { } System.out.println(s);

Operacje we/wy Strumienie działające na plikach: FileInputStream FileOutputStream FileReader FileWriter

Operacje we/wy Znaczenie klasy File operacje na plikach i na katalogach. Problem rekurencyjnego nawigowania po systemie plików.

Operacje we/wy Pliki o dostępie swobodnym: RandomAccessFile Nie są one strumieniami i nie należą do omawianej hierarchii.

Operacje we/wy Zastosowania serializacji: komunikacja pomiędzy obiektami/aplikacjami poprzez gniazdka (sockets), zachowanie obiektu (jego stanu i właściwości) do późniejszego odtworzenia i wykorzystania przez tę samą lub inną aplikację. Ma zastosowanie w aplikacjach korporacyjnych. W czasie serializacji zapisywany jest rekurencyjnie stan obiektów składowych, jednak pod warunkiem, że implementują one interfejs Serializable.

Operacje we/wy Serializacja związana jest ze strumieniami obiektowymi. Klasa serializowana musi implementować interfejs Serializable. Jeśli w trakcie serializacji/deserializacji trzeba wykonać nietypowe operacje, to należy zaimplementować metody: private void writeobject(java.io.objectoutputstream out) throws IOException; private void readobject(java.io.objectinputstream in) throws IOException, ClassNotFoundException;

Operacje we/wy przy serializacji nie są zapisywane pola statyczne oraz pola deklarowane ze specyfikatorem transient; specyfikatora transient używamy więc wobec elementów informacji o obiekcie, których nie chcemy poddawać utrwaleniu. pełniejszą kontrolę nad sposobem serializacji możemy zyskać definiując odpowiednie metody w klasie obiektu serializowanegoo, metody te winny mieć następujące sygnatury: całkowitą kontrolę nad formatem i sposobem serializacji zyskujemy poprzez implementację w klasie interfejsu Externalizable i dostarczenie metod writeexternal i readexternal

Operacje we/wy Serializacja i deserializacja // serializacja class X implements Serializable { int i; } ObjectOutputStream s = new ObjectOutputStream( new FileOutputStream("data.dat")); s.writeobject("today"); s.writeobject(new Date()); s.writeobject(new X()); s.flush();

Operacje we/wy // deserializacja ObjectInputStream s = new ObjectInputStream( new FileInputStream("data.dat")); String today = (String)s.readObject(); Date date = (Date)s.readObject(); X x = (X) s.readobject();

Operacje we/wy Dla obiektów typu JavaBeans istnieje także możliwość serializacji tekstowej (do plików w formacie XML) z wykorzystaniem klas XMLEncoder i XMLDecoder.

Operacje we/wy Potoki. Służą one do przesyłania danych pomiędzy równolegle działającymi wątkami. O wielowątkowości w Java będziemy mówili na jednym z dalszych wykładów. Na następnych dwóch slajdach przykład komunikacji między dwoma obiektami-wątkami.

Operacje we/wy class DataPutter extends Thread { OutputStream out; public DataPutter(OutputStream o) { out = o; } public void run() { try { for (char c = 'a'; c <= 'z'; c++) out.write(c); out.close(); } catch(ioexception exc) { return; } } }

Operacje we/wy class DataGetter extends Thread { InputStream in; public DataGetter(InputStream i) { in = i; } public void run() { try { int c; while ((c = in.read())!= -1) System.out.println((char) c); } catch(ioexception exc) { return; } } }

Operacje we/wy Dodatkowe usługi związane ze strumieniami w pakiecie: java.util Obejmują one: java.util.scanner java.util.formatter java.util.locale java.util.resourcebundle

Operacje we/wy Nowa biblioteka (od Java 1.7) we/wy: java.nio Wprowadzono w niej nieblokujące operacje we/wy. Operacje oferowane przez tę bibliotekę są znacznie szybsze niż przez java.io. Zawiera ona następujące elementy: Buffers kontenery danych (także: mapowane do pamięci) Channels mechanizmy operowania na danych Selectors mechanizmy wybierania kanałów dostępnych (gotowych do operacji we/wy)

Operacje we/wy Działania na plikach: Pakiet java.nio.file Interfejs Path reprezentuje pliki i katalogi Klasa Files operacje na plikach Obsługuje: Strumienie bajtowe Kanały Swobodny dostęp do plików za pomocą kanałów i interfejsu SeekableByteChannel Mapowanie kanałów na pamięć błyskawiczne operacje na plikach

Operacje we/wy Archiwa JAR możliwość kompresji, umieszczania w nich klas, cyfrowego podpisywania, : JarOutputStream JarInputStream Sposób tworzenia archiwum z linii komend: jar cf archiwum.jar klasa1.class klasa2.class... c tworzenie pliku (create), f zawartość archiwum zostanie zapisana do pliku archiwum.jar m do archiwum zostanie dołączony plik manifest z określonej lokalizacji, np: jar cmf plik_manifest archiwum.jar *,

Operacje we/wy W archiwum jar znajduje się katalog META-INF a w nim plik MANIFEST.MF zawierający dodatkowe informacje o archiwum. Przykładowa zawartość: Manifest-Version: 1.0 Created-By: 1.5.0-b64 (Sun Microsystems Inc.) Ant-Version: Apache Ant 1.6.5 Main-Class: pl.edu.pk.jp.runnerclass mówi, że po uruchomieniu archiwum wykonana zostanie metoda main(string[] args) zawarta w klasie RunnerClass znajdującej się w pakiecie pl.edu.pk.jp. Uruchomienie pliku jar: java -jar archiwum.jar

Java 8

Java 8 Stream API Ze względu na wzrost znaczenia możliwości sprzętowych oferowanych przez współczesne mikroprocesory postanowiono położyć nacisk na równoległość przetwarzania: Pracowano nad opartym na Javie systemie operacyjnym czasu rzeczywistego Wprowadzano w Java implementację wielowątkowości Fork Join Framework (FJF) Implementowano biblioteki standardowe Java opierając je o FJF Przykładem takiej biblioteki jest właśnie Java 8 Stream API. Skoncentrowano się w niej na przetwarzaniu danych w sposób abstrakcyjny zwalniając tym samym programistę od konieczności oprogramowania niskopoziomowej logiki wielowątkowej.

Java 8 Stream API Kolekcje a strumienie: Kolekcje predefiniowane struktury danych w pamięci zawierające elementy wyliczane przed umieszczeniem ich w kolekcji Strumienie ustalone struktury danych wyliczające elementy na żądanie Strumienie w Java 8 można postrzegać jako leniwie konstruowane kolekcje, w których wartości elementów wyznaczane są na żądanie użytkownika. Odwrotnie niż w Java 8-.

Java 8 Stream API Strumienie w Java 8 zostały zdefiniowane w pakiecie: java.util.stream Kolekcje Java 8 mają dodane metody zwracające Stream. Z punktu widzenia strumieni źródłem danych dla nich mogą być: Kolekcje Operacje we/wy Tablice Podobnie jak w przypadku funkcyjnych języków programowania Strumienie wspierają operacje agregowania przykłady: filter, map, reduce, find, match, sort Operacje te mogą być wykonywane sekwencyjnie lub równolegle.

Java 8 Stream API Dodatkowo strumienie w Java 8 wspierają: Pipelining (operacje na strumieniach zwracają strumienie możliwość składania operacji) Iteracje wewnętrzne

Java 8 Stream API Przykład wyszukanie spośród studentów takich dziesięciu, których nazwiska zaczynają się od A : List<String> names = students.stream().map(student::getname).filter(name->name.startswith("a")).limit(10).collect(collectors.tolist()); Operacje: Pośrednie (intermediate) powyżej map, filter, limit Końcowe (terminal)

Java 8 Stream API W Java 8 wprowadzono możliwość wykorzystania wyrażeń lambda. Przykład stare API. List<Block> blocks = /*... */; int sumofweights = 0; for (Block block : blocks) { if (block.getcolor() == Color.RED) { sumofweights += block.getweight(); } }

Java 8 Stream API Przykład nowe API. List<Block> blocks = /*... */; int sumofweights = blocks.stream().filter(b -> b.getcolor() == Color.RED).map(b -> b.getweight()).sum(); Można spotkać się ze słowami krytyki dotyczącymi braku bezstanowych wyrażeń lambda w Java 8 negatywnie rzutującymi na możliwą do uzyskania efektywność operacji strumieniowych.

Operacje we/wy Używanie standardowej biblioteki we/wy w każdej z postaci wymaga przechwytywania i obsługi wyjątków po stronie klienta. Dlatego na kolejnym wykładzie poznamy wyjątki. W czasie wykorzystywania operacji we/wy na zajęciach polegaliśmy na mechanizmie generowania obsługi wyjątków oferowanym przez środowisko deweloperskie.

Koniec