Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
statnice:bakalar:b0b36pjv [2025/05/13 11:58] – saniel | statnice:bakalar:b0b36pjv [2025/06/01 10:19] (current) – [Synchronized, Volatile, Join] zapleka3 | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ==== Programování v jazyce JAVA: vlastnosti a koncepce jazyka. Principy objektového programování. ==== | + | ====== Programování v jazyce JAVA: vlastnosti a koncepce jazyka. Principy objektového programování. |
[[https:// | [[https:// | ||
Line 11: | Line 11: | ||
- | ===== | + | ===== 1. Vývojové prostředí – JDK, JVM, kompilace a běh programu, správa paměti, GC, profilování a optimalizace ===== |
+ | ==== JDK, JRE, JVM ==== | ||
+ | Většinu programovacích jazyků je možné rozdělit do dvou kategorií: | ||
+ | * **kompilované** - program je zkompilovaný do spustitelného souboru, skládá se z nativních procesorových instrukcí, které přímo vykonává procesor a musí být tedy kompilován pro konkrétní architekturu a systém. Mezi tyto jazyky patří například C/C++. | ||
+ | * **interpretované** - program není zkompilovaný, | ||
+ | |||
+ | Javu je možné zařadit do obou kategorií - program se první zkompiluje do **bytecode**, | ||
+ | Pro tento proces je potřeba **JDK** (java development kit). | ||
+ | |||
+ | Tento **bytecode** je možné následně pustit s **JRE** (java runtime environment- subset **JDK**), který **bytecode** za běhu **interpretuje**. | ||
+ | |||
+ | **Proces kompilace a spuštění v Javě:** | ||
+ | * Zdrojový kód se píše do souborů s příponou `.java`. | ||
+ | * Překladač `javac` přeloží `.java` do `.class` souboru s bytecode. | ||
+ | * Bytecode spouští JVM pomocí příkazu `java NázevTřídy`. | ||
+ | |||
+ | Java tedy umožňuje program zkompilovat pouze jednou do **bytecode** a následně spustit na jekékoliv platformě s **JRE** (i když v praxi to obecně tak jednoduché není - compile once, debug everywhere). | ||
+ | Tento přístup vede k rychlosti blížící se kompilovaným jazykům bez nutnosti kompilovat pro každou platformu zvlášť. | ||
+ | |||
+ | **JVM** (java virtual machine) je obsažen v **JRE** i **JDK** a je zodpovědný za překlad **bytecode** do nativních procesorových instrukcí. | ||
+ | |||
+ | ==== JAR ==== | ||
+ | |||
+ | **JAR** (Java ARchive) je archivní formát pro sdružení více tříd (*.class*) a dalších souborů do jednoho balíčku. | ||
+ | Používá se k distribuci a spouštění Java aplikací. | ||
+ | |||
+ | Součástí může být také soubor `MANIFEST.MF`, | ||
+ | * např. `Main-Class: | ||
+ | * Umožňuje poté spustit aplikaci jednoduše: `java -jar program.jar` | ||
+ | |||
+ | ==== Správa paměti ==== | ||
+ | === Stack === | ||
+ | Malý paměťový prostor, ve kterém se typicky ukládají lokální proměnné (což obsahuje i reference, atd). | ||
+ | Funguje na principu **last-in first-out**. Při zavolání funkce se na stacku alokuje místo pro všechny lokální proměnné dané funkce. | ||
+ | Implementováno přes **stack-pointer**, | ||
+ | |||
+ | Pro každé volání metody vzniká tzv. **aktivní záznam**, který obsahuje: | ||
+ | * návratovou adresu, | ||
+ | * parametry metody, | ||
+ | * lokální proměnné. | ||
+ | |||
+ | Po ukončení metody se tento záznam odstraní. | ||
+ | |||
+ | === Heap === | ||
+ | Velký paměťový prostor, dynamicky alokovaná paměť. Typicky se zde ukládají objekty a větší datové struktury. | ||
+ | Alokována pomocí **new**. O dealokaci se nestará programátor, | ||
+ | |||
+ | Heap je sdílený mezi všemi vlákny programu. | ||
+ | Objekty zde zůstávají tak dlouho, dokud na ně existuje reference – poté je odstraní GC. | ||
+ | |||
+ | ==== GC ==== | ||
+ | Garbage Collector běží na pozadí **JVM**. Běží ve vlastním vlákně (nebo i více vláknech), takže neblokuje běh samotného programu (asynchronní). Drží si seznam všech referencí na data na **heap** a jakmile zjistí, že už žádné reference neexistují, | ||
+ | |||
+ | Garbage Collector sice nebude nikdy tak efektivní jako korektní manuální dealokace jako např. v C/C++, ale zjednodušuje psaní programu, jeho udržitelnost a značně snižuje riziko memory leaků kvůli špatným manuálním dealokacím. | ||
+ | |||
+ | ==== Profilování a optimalizace ==== | ||
+ | **JDK** a z části i **JRE** implementuje několik nástrojů pro profiling programu, jako třeba vytížení procesoru a jednotlivých vláken, využití paměti, stav GC. | ||
+ | |||
+ | **JDK** provádí mnoho optimalizací již při kompilaci **bytecode**, | ||
+ | |||
+ | Java nabízí několik nástrojů pro analýzu výkonu: | ||
+ | * `jconsole` – vizualizace běhu JVM (paměť, CPU, vlákna, GC). | ||
+ | * `jvisualvm` – pokročilé grafické rozhraní s možností sledovat heap, GC, threaddump, apod. | ||
+ | * `Java Flight Recorder` – nástroj pro detailní záznam a analýzu výkonu aplikace. | ||
+ | * `javap` – nástroj pro prohlížení bytecode (.class). | ||
+ | |||
+ | Tyto nástroje umožňují najít místa s největším využitím CPU, paměti nebo nejdelším časem běhu. | ||
+ | |||
+ | ===== 2. Objekty, třídy a jejich vztahy ===== | ||
+ | |||
+ | Objektově orientované programování (OOP) je paradigma, ve kterém modelujeme svět pomocí objektů – entit, které kombinují data a chování. | ||
+ | Základními principy OOP jsou: **abstrakce**, | ||
+ | |||
+ | **Třída** – abstraktní popis objektu, definuje jeho strukturu (atributy) a chování (metody). | ||
+ | **Objekt** – konkrétní instance třídy, která nese data a reaguje na operace definované třídou. | ||
+ | |||
+ | Třída je šablona pro vytváření tříd, objekt je konkrétní instance třídy. | ||
+ | |||
+ | Například: | ||
+ | < | ||
+ | ```java | ||
+ | // class definition | ||
+ | public class Person { | ||
+ | private String name; | ||
+ | private int age; | ||
+ | |||
+ | public Person(String name, int age) { | ||
+ | this.name = name; | ||
+ | this.age = age; | ||
+ | } | ||
+ | |||
+ | public String getName() { | ||
+ | return name; | ||
+ | } | ||
+ | |||
+ | public int getAge() { | ||
+ | return age; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // object instantiation | ||
+ | Person person = new Person(" | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | ==== Abstrakce a zapouzdření ==== | ||
+ | **Abstrakce** – organizujeme koncepty do tříd, skrýváme vnitřní implementaci a vystavujeme jen potřebné rozhraní. | ||
+ | **Zapouzdření** – každý objekt chrání svůj stav a komunikuje s okolím přes veřejné metody. | ||
+ | |||
+ | **Modifikátory přístupu v Javě:** | ||
+ | * `private` – přístup pouze uvnitř třídy. | ||
+ | * `protected` – přístup z třídy, dědiců a stejného balíčku. | ||
+ | * `public` – přístup odkudkoliv. | ||
+ | * výchozí (bez modifikátoru) – přístup v rámci balíčku. | ||
+ | |||
+ | ==== Dědičnost a kompozice ==== | ||
+ | **Dědičnost** – třídám lze předat chování a atributy z nadřazené třídy (`extends`), | ||
+ | |||
+ | **Kompozice** – třída obsahuje jiné objekty jako své atributy („has-a“ vztah), vhodná pro sdružování funkcionality. | ||
+ | |||
+ | **Příklad rozdílu: | ||
+ | < | ||
+ | ```java | ||
+ | // dědičnost | ||
+ | class Animal { void speak() { System.out.println(" | ||
+ | class Dog extends Animal { void speak() { System.out.println(" | ||
+ | |||
+ | // kompozice | ||
+ | class Engine { void start() { ... } } | ||
+ | class Car { | ||
+ | private Engine engine = new Engine(); | ||
+ | void start() { engine.start(); | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | ==== Polymorfismus a dynamická vazba ==== | ||
+ | |||
+ | **Polymorfismus** – schopnost objektu zareagovat různě podle svého konkrétního typu, i když je používán přes obecný typ. | ||
+ | |||
+ | Např. metoda `draw()` může mít jinou implementaci ve třídách `Circle`, `Square`, ale lze je volat skrze rozhraní `Shape`. | ||
+ | |||
+ | **Dynamická vazba (late binding)** – konkrétní metoda se určuje až v době běhu na základě typu objektu. | ||
+ | |||
+ | **Rozdíl: | ||
+ | * *Přetížení (overloading)* – metoda se liší počtem nebo typem parametrů (rozhoduje se v čase překladu). | ||
+ | * *Přepisování (overriding)* – metoda se předefinuje v podtřídě (rozhoduje se v době běhu). | ||
+ | |||
+ | ==== Interface a abstraktní třída ==== | ||
+ | |||
+ | **Rozhraní (interface)** definuje sadu metod, které třída musí implementovat (`implements`). Třída může implementovat více rozhraní. | ||
+ | |||
+ | **Abstraktní třída** (`abstract`) může obsahovat jak implementované, | ||
+ | |||
+ | **Rozdíly: | ||
+ | * Rozhraní – bez stavových atributů, vhodné pro vícenásobnou dědičnost. | ||
+ | * Abstraktní třída – umožňuje sdílení částečné implementace a stavu. | ||
+ | |||
+ | ==== Bonus: Vícenásobná dědičnost ==== | ||
+ | |||
+ | Java neumožňuje vícenásobnou dědičnost tříd, aby se předešlo problémům jako je **diamond problem** – tedy situace, kdy by podtřída dědila stejnou metodu z více nadtříd a nebylo by jasné, kterou implementaci použít. | ||
+ | |||
+ | Místo toho umožňuje vícenásobnou dědičnost **rozhraní**: | ||
+ | < | ||
+ | ```java | ||
+ | interface A { void doA(); } | ||
+ | interface B { void doB(); } | ||
+ | |||
+ | class C implements A, B { | ||
+ | public void doA() { System.out.println(" | ||
+ | public void doB() { System.out.println(" | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | ==== Bonus: Single a double dispatch ==== | ||
+ | |||
+ | **Single dispatch** znamená, že metoda, která se má zavolat, se vybírá podle *dynamického typu objektu*, na kterém je metoda volána: | ||
+ | < | ||
+ | ```java | ||
+ | class Animal { void speak() { System.out.println(" | ||
+ | class Dog extends Animal { void speak() { System.out.println(" | ||
+ | |||
+ | Animal a = new Dog(); | ||
+ | a.speak(); // zavolá se Dog.speak() – podle skutečného typu objektu | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | **Double dispatch** znamená, že metoda je vybrána na základě *dynamických typů dvou objektů*. V Javě se běžně simuluje pomocí návrhového vzoru **Visitor**: | ||
+ | < | ||
+ | ```java | ||
+ | interface Visitor { | ||
+ | void visit(Dog d); | ||
+ | void visit(Cat c); | ||
+ | } | ||
+ | |||
+ | interface Animal { | ||
+ | void accept(Visitor v); | ||
+ | } | ||
+ | |||
+ | class Dog implements Animal { | ||
+ | public void accept(Visitor v) { v.visit(this); | ||
+ | } | ||
+ | |||
+ | class Cat implements Animal { | ||
+ | public void accept(Visitor v) { v.visit(this); | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | Zde metoda `visit(...)` závisí jak na typu návštěvníka (`Visitor`), | ||
+ | |||
+ | |||
+ | ===== 3. Výčtové typy, kolekce, iterátor, generické typy ===== | ||
+ | |||
+ | ==== Výčtové typy (enum) ==== | ||
+ | |||
+ | Výčtový typ (angl. enumeration) je datový typ, který může nabývat pouze předem daných hodnot. | ||
+ | Zvyšuje čitelnost a typovou bezpečnost programu – místo čísel nebo řetězců použijeme symbolická jména. | ||
+ | |||
+ | Například: | ||
+ | < | ||
+ | ```java | ||
+ | public enum Day { | ||
+ | MONDAY, | ||
+ | TUESDAY, | ||
+ | WEDNESDAY, | ||
+ | THURSDAY, | ||
+ | FRIDAY, | ||
+ | SATURDAY, | ||
+ | SUNDAY | ||
+ | } | ||
+ | |||
+ | Day today = Day.MONDAY; | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | Výčtové typy jsou ve skutečnosti speciální typ třídy – lze do nich přidat: | ||
+ | - konstruktor, | ||
+ | - metody, | ||
+ | - pole. | ||
+ | |||
+ | < | ||
+ | ```java | ||
+ | public enum Suit { | ||
+ | CLUBS(Color.BLACK), | ||
+ | DIAMONDS(Color.RED), | ||
+ | HEARTS(Color.BLACK), | ||
+ | SPADES(Color.RED); | ||
+ | |||
+ | private Color color; | ||
+ | |||
+ | Suit(Color c) { | ||
+ | this.color = c; | ||
+ | } | ||
+ | |||
+ | public Color getColor() { | ||
+ | return color; | ||
+ | } | ||
+ | |||
+ | public boolean isRed() { | ||
+ | return color == Color.RED; | ||
+ | } | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | ==== Kolekce (Java Collection Framework) ==== | ||
+ | |||
+ | Java Collections Framework (JCF) je sada rozhraní a tříd pro práci s obecnými datovými strukturami. | ||
+ | |||
+ | Základní vlastnosti: | ||
+ | * umožňují efektivní ukládání, | ||
+ | * hierarchicky uspořádané – Collection, List, Set, Map, Queue atd. | ||
+ | |||
+ | Základní typy kolekcí: | ||
+ | * List – uspořádaná kolekce s indexy (ArrayList, LinkedList) | ||
+ | * Set – množina bez duplicit (HashSet, TreeSet) | ||
+ | * Map – páry klíč–hodnota (HashMap, TreeMap) | ||
+ | * Queue – fronta (LinkedList, | ||
+ | |||
+ | Příklad: | ||
+ | < | ||
+ | ```java | ||
+ | List< | ||
+ | names.add(" | ||
+ | names.add(" | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | ==== Iterátor ==== | ||
+ | |||
+ | Iterátor je objekt, který umožňuje bezpečně procházet kolekce bez znalosti jejich vnitřní struktury. | ||
+ | |||
+ | Použití: | ||
+ | < | ||
+ | ```java | ||
+ | Iterator< | ||
+ | while (it.hasNext()) { | ||
+ | System.out.println(it.next()); | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | Zkrácený zápis pomocí for-each: | ||
+ | < | ||
+ | ```java | ||
+ | for (String name : names) { | ||
+ | System.out.println(name); | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | Rozhraní Iterable umožňuje použít kolekci ve for-each smyčce. | ||
+ | |||
+ | Poznámka: Kolekce nelze bezpečně měnit během iterace jinak než metodou it.remove(). | ||
+ | Jinak hrozí ConcurrentModificationException. | ||
+ | |||
+ | ==== Generické typy ==== | ||
+ | |||
+ | Generické typy (generika) umožňují psát obecný, opakovatelný a typově bezpečný kód, který lze aplikovat na různé datové typy bez nutnosti přetypování. | ||
+ | |||
+ | Deklarace: | ||
+ | < | ||
+ | ```java | ||
+ | List< | ||
+ | numbers.add(10); | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | Výhody generik: | ||
+ | - typová bezpečnost, | ||
+ | - žádné přetypování, | ||
+ | - opakovatelnost kódu. | ||
+ | |||
+ | Generická metoda: | ||
+ | < | ||
+ | ```java | ||
+ | public static <T> void printAll(List< | ||
+ | for (T item : list) { | ||
+ | System.out.println(item); | ||
+ | } | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | Poznámka: Generika jsou v Javě implementována pomocí type erasure – typová informace se za běhu ztrácí (např. nelze napsat new T()). | ||
+ | |||
+ | |||
+ | ===== 4. Vnitřní a anonymní třídy, Imutabilita, | ||
+ | |||
+ | ==== Vnitřní třídy ==== | ||
+ | Vnitřní třída (inner class) je třída, která je definovaná uvnitř jiné třídy. Má přístup ke všem členům (včetně privátních) vnější třídy a typicky slouží jako pomocná třída. | ||
+ | |||
+ | Je-li vnitřní třída označena jako static, jedná se o statickou vnitřní třídu, která nemá přístup k instanci vnější třídy. | ||
+ | |||
+ | Výhodou je lepší zapouzdření a přehlednost kódu – vnitřní třídy se používají tam, kde nemá smysl jejich existence samostatně. | ||
+ | |||
+ | < | ||
+ | ```java | ||
+ | class OuterClass { | ||
+ | int x = 10; | ||
+ | |||
+ | class InnerClass { | ||
+ | int y = 5; | ||
+ | } | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== Anonymní třídy ==== | ||
+ | Anonymní vnitřní třída je bezejmenná třída, která je definována a zároveň instanciována na místě. Používá se tam, kde potřebujeme jednorázově implementovat nějaké rozhraní nebo rozšířit třídu. | ||
+ | |||
+ | Typicky se využívá např. pro callbacky nebo posluchače událostí. | ||
+ | |||
+ | Anonymní třída je třída vnitřní bez názvu, pro kterou je vytvořen pouze jediný objekt. | ||
+ | < | ||
+ | [GeeksforGeeks](https:// | ||
+ | ```java | ||
+ | // Interface | ||
+ | interface Age { | ||
+ | int x = 21; | ||
+ | void getAge(); | ||
+ | } | ||
+ | |||
+ | class AnonymousDemo { | ||
+ | |||
+ | // Main driver method | ||
+ | public static void main(String[] args) | ||
+ | { | ||
+ | |||
+ | // A hidden inner class of Age interface is created | ||
+ | // whose name is not written but an object to it | ||
+ | // is created. | ||
+ | Age oj1 = new Age() { | ||
+ | |||
+ | @Override public void getAge() | ||
+ | { | ||
+ | // printing | ||
+ | System.out.print(" | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | oj1.getAge(); | ||
+ | } | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | ==== Imutabilita ==== | ||
+ | Imutabilní objekt je takový objekt, jehož stav po vytvoření již nelze změnit. To znamená: | ||
+ | * všechny atributy jsou private a final, | ||
+ | * objekt neposkytuje žádné metody, které by umožnily změnu stavu, | ||
+ | * objekt nevrací reference na své vnitřní proměnné. | ||
+ | |||
+ | Výhody: | ||
+ | * bezpečnost při vícevláknovém přístupu, | ||
+ | * snazší ladění a testování. | ||
+ | |||
+ | ==== Vzor Singleton ==== | ||
+ | Singleton je návrhový vzor, který zajišťuje, | ||
+ | * soukromým (private) konstruktorem, | ||
+ | * statickou proměnnou pro instanci třídy, | ||
+ | * veřejnou statickou metodou pro přístup k instanci. | ||
+ | |||
+ | < | ||
+ | ```java | ||
+ | public class Singleton { | ||
+ | private static final Singleton instance = new Singleton(); | ||
+ | |||
+ | private Singleton() {} | ||
+ | |||
+ | public static Singleton getInstance() { | ||
+ | return instance; | ||
+ | } | ||
+ | } | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | ==== Proměnné a metody třídy vs. instance ==== | ||
+ | |||
+ | * Instanční proměnné – náleží konkrétní instanci třídy, každá instance může mít jiné hodnoty. | ||
+ | * Třídní proměnné (statické) – sdílené všemi instancemi, existují nezávisle na instanci. | ||
+ | |||
+ | * Instanční metody – pracují s instančními daty, volají se na konkrétních objektech. | ||
+ | * Statické metody – patří třídě, volají se bez instance, nemají přístup k nestatickým členům. | ||
+ | |||
+ | |||
+ | ===== 5. Mechanismus výjimek ===== | ||
+ | |||
+ | Výjimka (// | ||
+ | | ||
+ | |||
+ | ==== Hierarchie výjimek v Javě ==== | ||
+ | * Všechny výjimky jsou potomky třídy `Throwable`. | ||
+ | * `Error` – závažné chyby JVM (např. `OutOfMemoryError`). Nejsou určeny k zachytávání. | ||
+ | * `Exception` – výjimky, které lze (a měly by se) ošetřit. | ||
+ | * `RuntimeException` – běhové výjimky (např. `NullPointerException`, | ||
+ | |||
+ | ==== Checked vs. Unchecked výjimky ==== | ||
+ | * **Checked** – kompilátor hlídá; musíš je buď zachytit pomocí '' | ||
+ | * **Unchecked** – všechny výjimky odvozené od '' | ||
+ | |||
+ | ==== Ošetření výjimek ==== | ||
+ | |||
+ | Výjimky se ošetřují pomocí konstrukcí `try-catch-finally`. | ||
+ | |||
+ | <code java> | ||
+ | try { | ||
+ | // rizikový kód | ||
+ | } catch (IOException | SQLException ex) { // multi-catch od Java 7 | ||
+ | e.printStackTrace(); | ||
+ | log(ex); | ||
+ | throw ex; // volitelné předání dál | ||
+ | } finally { | ||
+ | cleanup(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | * `catch` může být více, podle typu výjimky. | ||
+ | * `finally` se vždy vykoná – i když dojde k výjimce nebo `return`. | ||
+ | |||
+ | ==== Try-with-resources ==== | ||
+ | Od Javy 7 existuje `try-with-resources`, | ||
+ | |||
+ | <code java> | ||
+ | try (BufferedReader br = Files.newBufferedReader(Path.of(" | ||
+ | return br.readLine(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== Vlastní výjimky ==== | ||
+ | Vlastní výjimky se vytvářejí děděním ze třídy `Exception` nebo `RuntimeException`. | ||
+ | |||
+ | <code java> | ||
+ | public class MyException extends Exception { | ||
+ | public MyException() {} | ||
+ | public MyException(String msg) { super(msg); } | ||
+ | public MyException(String msg, Throwable cause) { super(msg, cause); } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | * **Kdy se hodí?** Když stávající výjimky nedostačují a potřebuješ popsat specifickou situaci. | ||
+ | * Rozhodni se, zda má být **checked** (nutí volající k ošetření) nebo **unchecked** (dědí z '' | ||
+ | |||
+ | * Pokud dědíme z `Exception`, | ||
+ | * Pokud dědíme z `RuntimeException`, | ||
+ | |||
+ | ==== Best practices ==== | ||
+ | * Zachytávej co nejkonkrétnější typy výjimek, až poté obecné (`Exception`, | ||
+ | * Nepoužívej prázdné `catch` bloky – vždy loguj nebo informuj uživatele. | ||
+ | * Uvolňuj prostředky pomocí `finally` nebo `try-with-resources`. | ||
+ | * Přidávej popisné chybové zprávy (`new IOException(" | ||
+ | * Vlastní výjimky používej pro specifické, | ||
+ | |||
+ | ==== Shrnutí podle typu výjimky ==== | ||
+ | * `Throwable` – kořenová třída, zachytitelná, | ||
+ | * `Exception` – standardní ošetřitelné výjimky. | ||
+ | * `IOException`, | ||
+ | * `RuntimeException`, | ||
+ | * `Error` – závažné chyby – většinou se nezachytávají (`OutOfMemoryError`, | ||
+ | |||
+ | ===== Práce se soubory (java.io) ===== | ||
+ | |||
+ | Soubor je množina údajů uložená ve vnější paměti. Přístup k němu probíhá pomocí proudů (streamů), které umožňují čtení a zápis dat sekvenčně nebo náhodně. Dělíme je podle typu dat na textové a binární. | ||
+ | |||
+ | ==== Klíčové třídy ==== | ||
+ | * **File** – reprezentuje cestu k souboru nebo adresáři. Lze ověřit existenci, práva, velikost, vytvořit složky/ | ||
+ | * **InputStream / OutputStream** – bajtové proudy (pro binární data). | ||
+ | * Dekorátory: | ||
+ | * **Reader / Writer** – znakové proudy (pro textová data). | ||
+ | * Často používané: | ||
+ | * **RandomAccessFile** – umožňuje číst/ | ||
+ | * Rozhraní: Closeable, Flushable, Serializable – sjednocují chování při zavírání, | ||
+ | |||
+ | ==== Otevření binárních proudů ==== | ||
+ | <code java> | ||
+ | try (InputStream | ||
+ | | ||
+ | |||
+ | byte[] buf = new byte[8192]; | ||
+ | int n; | ||
+ | while ((n = in.read(buf)) != -1) { | ||
+ | out.write(buf, | ||
+ | } | ||
+ | } // oba proudy se zavřou automaticky (try-with-resources) | ||
+ | </ | ||
+ | |||
+ | ==== Otevření a čteni textového souboru (java.io) ==== | ||
+ | |||
+ | Nejčastější (a dodnes plně dostačující) kombinací je dvojice **``FileReader`` + ``BufferedReader``**: | ||
+ | |||
+ | <code java> | ||
+ | try (BufferedReader br = | ||
+ | new BufferedReader(new FileReader(" | ||
+ | |||
+ | String line; | ||
+ | while ((line = br.readLine()) != null) { | ||
+ | System.out.println(line); | ||
+ | } | ||
+ | } // try-with-resources zajistí zavření souboru | ||
+ | </ | ||
+ | |||
+ | * **``FileReader``** čte **znaky** (automaticky použije defaultní kódování platformy, nebo explicitně zadej např. ``StandardCharsets.UTF_8``). | ||
+ | * **``BufferedReader``** obalí čtení do větších bloků → méně systémových volání, vyšší výkon. | ||
+ | * Konstrukce **try-with-resources** (Java 7+) zavře reader i v případě výjimky. | ||
+ | |||
+ | ==== Textové vs. binární soubory ==== | ||
+ | * **Textové** – čitelné pro člověka, pracujeme se znaky pomocí Reader/ | ||
+ | * **Binární** – rychlejší, | ||
+ | |||
+ | ==== Serializace objektů ==== | ||
+ | <code java> | ||
+ | try (ObjectOutputStream oos = | ||
+ | new ObjectOutputStream(new FileOutputStream(" | ||
+ | oos.writeObject(gameState); | ||
+ | } | ||
+ | </ | ||
+ | * Třída musí implementovat '' | ||
+ | * Lze uložit i více objektů. Pozor na kompatibilitu verzí tříd (pole '' | ||
+ | |||
+ | ==== Přístup k datům ==== | ||
+ | * **Sekvenční** – čtení/ | ||
+ | * **Náhodný (Random Access)** – přímý přístup k určitému místu v souboru (RandomAccessFile). | ||
+ | |||
+ | ==== Cesty k souborům ==== | ||
+ | * **Absolutní** – začíná kořenem systému (např. / | ||
+ | * **Relativní** – relativní k pracovnímu adresáři aplikace. | ||
+ | |||
+ | ==== Best practices ==== | ||
+ | * Vždy používej try-with-resources – eliminuje riziko nezavření souboru. | ||
+ | * Při práci s textem dej pozor na kódování (UTF-8 doporučeno). | ||
+ | * Bufruj vstupy/ | ||
+ | * Nezachytávej holou '' | ||
+ | * Při sériové práci se soubory preferuj nové NIO API ('' | ||
+ | |||
+ | ===== Sokety ===== | ||
+ | |||
+ | Soket je objekt, který propojuje aplikaci se síťovým protokolem. Umožňuje síťovou komunikaci mezi dvěma koncovými body (např. klientem a serverem) prostřednictvím definovaných API. V Javě se sokety používají pro komunikaci přes protokoly TCP a UDP. | ||
+ | |||
+ | ==== Typy soketů a API ==== | ||
+ | |||
+ | | Třída | ||
+ | |-------------------------|------------------|--------------------------|-------------------------------| | ||
+ | | Socket / ServerSocket | ||
+ | | DatagramSocket | ||
+ | | MulticastSocket | ||
+ | |||
+ | ==== TCP vs. UDP – typy spojení ==== | ||
+ | |||
+ | **TCP (Transmission Control Protocol)** | ||
+ | * Spojovaný protokol – před komunikací naváže spojení | ||
+ | * Zaručuje doručení, pořadí zpráv a detekci chyb | ||
+ | * Pomalejší, | ||
+ | |||
+ | **UDP (User Datagram Protocol)** | ||
+ | * Nespojovaný protokol – žádné spojení, zprávy mohou být ztraceny nebo doručeny jinak | ||
+ | * Rychlý, nízká latence, žádné záruky | ||
+ | * Nutno si případně ošetřit potvrzení a opakování ručně | ||
+ | |||
+ | ==== Ukázkový TCP server/ | ||
+ | <code java> | ||
+ | // === Server === | ||
+ | try (ServerSocket srv = new ServerSocket(9000)) { | ||
+ | while (true) { | ||
+ | try (Socket s = srv.accept(); | ||
+ | | ||
+ | | ||
+ | |||
+ | String line = in.readLine(); | ||
+ | out.println(" | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // === Klient === | ||
+ | try (Socket s = new Socket(" | ||
+ | | ||
+ | | ||
+ | |||
+ | out.println(" | ||
+ | System.out.println(in.readLine()); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== Primitiva soketu ==== | ||
+ | |||
+ | * **create** – vytvoření nového soketu | ||
+ | * **bind** – přiřazení lokální adresy a portu | ||
+ | * **connect** – navázání spojení (klient) | ||
+ | * **listen** – čekání na spojení (server) | ||
+ | * **accept** – přijetí spojení | ||
+ | * **send / receive** – odeslání a příjem dat | ||
+ | * **shutdown / close** – uzavření spojení | ||
+ | |||
+ | ==== Best practices ==== | ||
+ | * **Porty a backlog**: při '' | ||
+ | * Nastav '' | ||
+ | * Na mnoho paralelních spojení použij **'' | ||
+ | * Pro šifrovaný přenos sáhni po '' | ||
+ | * Vždy uzavírej soket v '' | ||
+ | |||
+ | ===== 6. Paralelismus ===== | ||
+ | |||
+ | Paralelismus umožňuje efektivnější využití systémových prostředků (více jader CPU, paralelní zpracování vstupů, vyšší výkon, reakce na události). V Javě se používá vícevláknové programování pomocí třídy `Thread`, rozhraní `Runnable`, případně thread poolu (`ExecutorService`). | ||
+ | |||
+ | Nutné dodržet pravidla synchronizace, | ||
+ | |||
+ | ==== Vytváření a spouštění vláken ==== | ||
+ | |||
+ | Vlákno lze vytvořit buď děděním od třídy `Thread`, nebo implementací rozhraní `Runnable`: | ||
+ | |||
+ | < | ||
+ | Objekty jsou odvozené od třídy `Thread`, tělo nezávislého výpočtu definujeme v metodě `run()`. | ||
+ | ```java | ||
+ | public class Worker extends Thread { | ||
+ | private final int numberOfJobs; | ||
+ | |||
+ | public Worker(int id, int jobs) { | ||
+ | super(" | ||
+ | myID = id; | ||
+ | numberOfJobs = jobs; | ||
+ | stop = false; | ||
+ | System.out.println(" | ||
+ | } | ||
+ | |||
+ | public void run() { | ||
+ | doWork(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | Worker thread = new Worker(1, 10); | ||
+ | thread.start(); | ||
+ | System.out.println(" | ||
+ | ``` | ||
+ | |||
+ | Pokud nelze použít dědění od `Thread` implementujeme rozhraní `Runnable`: | ||
+ | ```java | ||
+ | public class WorkerRunnable implements Runnable { | ||
+ | private final int id; | ||
+ | private final int numberOfJobs; | ||
+ | |||
+ | public WorkerRunnable(int id, int jobs) { | ||
+ | this.id = id; | ||
+ | numberOfJobs = jobs; | ||
+ | } | ||
+ | |||
+ | public String getName() { | ||
+ | return " | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void run() { ... } | ||
+ | } | ||
+ | |||
+ | WorkerRunnable worker = new WorkerRunnable(1, | ||
+ | Thread thread = new Thread(worker, | ||
+ | thread.start(); | ||
+ | |||
+ | public void run() { | ||
+ | Thread thread = Thread.currentThread(); | ||
+ | |||
+ | for (int i = 0; i < numberOfJobs; | ||
+ | System.out.println(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | ==== Synchronizace a problémy souběhu ==== | ||
+ | |||
+ | Při práci s více vlákny vznikají typické problémy: | ||
+ | * Race condition – více vláken přistupuje ke sdíleným datům bez koordinace. Výsledek je nedefinovaný. | ||
+ | * Řešení: synchronized bloky, volatile proměnné | ||
+ | * Deadlock – dvě nebo více vláken čekají na zdroje, které drží jiná vlákna. | ||
+ | * Řešení: správné pořadí zamykání, timeouty, algoritmy prevence deadlocku | ||
+ | * Producer/ | ||
+ | * Řešení: wait(), notify(), fronty z balíku java.util.concurrent | ||
+ | * Reader/ | ||
+ | * Řešení: ReadWriteLock nebo rozdělení na operace pouze pro čtení a zápis | ||
+ | |||
+ | ==== Synchronized, | ||
+ | |||
+ | * synchronized – zajišťuje, | ||
+ | * volatile – proměnná může být měněna z více vláken, JVM nezachová její hodnotu v cache (když se změní na false - informuje to ostatní vlákna, ale ne jako counter) | ||
+ | * join() – čeká na dokončení jiného vlákna | ||
+ | * wait() / notify() – vlákna čekají a signalizují si mezi sebou (pouze uvnitř synchronized bloku) | ||
+ | |||
+ | ==== Thread Pool (Executor) ==== | ||
+ | |||
+ | Používá se místo ručního vytváření velkého počtu vláken. Efektivnější správa a recyklace. | ||
+ | |||
+ | < | ||
+ | ```java | ||
+ | ExecutorService executor = Executors.newFixedThreadPool(4); | ||
+ | executor.submit(new WorkerRunnable(1, | ||
+ | executor.shutdown(); | ||
+ | ``` | ||
+ | </ | ||
+ | |||
+ | * ExecutorService – spravuje vláknový pool | ||
+ | * submit() – spustí úkol | ||
+ | * shutdown() – ukončí Executor | ||
+ | * Future – objekt s výsledkem nebo stavem asynchronního výpočtu | ||
+ | |||
+ | ==== Kdy použít paralelismus ==== | ||
+ | |||
+ | * Více úloh může běžet souběžně – více jádrový procesor | ||
+ | * Aplikace provádí dlouhé IO operace, ale musí zůstat responzivní (např. GUI) | ||
+ | * Kontrola nebo úkoly na pozadí (např. notifikace, synchronizace) | ||