- 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
SQLException ex) { e.printStackTrace(); // ošetření výjimky
log(ex);
throw ex; // volitelné předání dál
} finally {
cleanup(); // provede se vždy
}
</code>
* `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`, který automaticky zavře prostředky (např. soubory, streamy) implementující `AutoCloseable`.
try (BufferedReader br = Files.newBufferedReader(Path.of("data.txt"))) {
return br.readLine();
}
==== Vlastní výjimky ====
Vlastní výjimky se vytvářejí děděním ze třídy `Exception` nebo `RuntimeException`.
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 RuntimeException).
* Pokud dědíme z `Exception`, jedná se o checked výjimku – musí být ošetřena.
* Pokud dědíme z `RuntimeException`, jedná se o unchecked výjimku – nemusí být ošetřena.
==== Best practices ====
* Zachytávej co nejkonkrétnější typy výjimek, až poté obecné (`Exception`, `Throwable`).
* 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(“Soubor nenalezen”)`).
* Vlastní výjimky používej pro specifické, smysluplné chyby v aplikaci.
==== Shrnutí podle typu výjimky ====
* `Throwable` – kořenová třída, zachytitelná, ale neměla by se běžně používat.
* `Exception` – standardní ošetřitelné výjimky.
* `IOException`, `SQLException`, `ParseException` – checked výjimky.
* `RuntimeException`, `NullPointerException`, `IndexOutOfBoundsException` – unchecked.
* `Error` – závažné chyby – většinou se nezachytávají (`OutOfMemoryError`, `StackOverflowError`).
===== 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/soubory.
* InputStream / OutputStream – bajtové proudy (pro binární data).
* Dekorátory: Buffered* (vyrovnávací paměť), Data* (primitiva), Object* (serializace), GZIP* (komprese)…
* **Reader / Writer** – znakové proudy (pro textová data).
* Často používané: BufferedReader, InputStreamReader, FileWriter.
* **RandomAccessFile** – umožňuje číst/zapisovat na libovolnou pozici (náhodný přístup).
* Rozhraní: Closeable, Flushable, Serializable – sjednocují chování při zavírání, flushování a serializaci objektů.
==== Otevření binárních proudů ====
try (InputStream in = new FileInputStream("logo.png");
OutputStream out = new FileOutputStream("copy.png")) {
byte[] buf = new byte[8192];
int n;
while ((n = in.read(buf)) != -1) {
out.write(buf, 0, n);
}
} // 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``:
try (BufferedReader br =
new BufferedReader(new FileReader("soubor.txt"))) {
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/Writer. Nutné správné kódování (UTF-8, ASCII…).
* Binární – rychlejší, nečitelné, používáme InputStream/OutputStream. Vhodné pro obrázky, audio, objekty apod.
==== Serializace objektů ====
try (ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("state.bin"))) {
oos.writeObject(gameState);
}
* Třída musí implementovat Serializable.
* Lze uložit i více objektů. Pozor na kompatibilitu verzí tříd (pole serialVersionUID).
==== Přístup k datům ====
* Sekvenční – čtení/zápis po sobě jdoucích bajtů/řádků (většina proudů).
* 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ř. /home/user/file.txt nebo C:\Users\file.txt).
* 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/výstupy pomocí Buffered* – zvyšuje výkon.
* Nezachytávej holou ''Exception''; loguj a přeposílej konkrétní typy.
* Při sériové práci se soubory preferuj nové NIO API (''java.nio.file.Path'') – ošetří limity ''File'' a umí asynchronní I/O, ale porozumění ''java.io'' je nutný základ.
===== 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 | Protokol | Povaha | Typická použití |
|————————-|——————|————————–|——————————-|
| Socket / ServerSocket | TCP | spojované, spolehlivé | chat, přenos souborů |
| DatagramSocket | UDP | nespojované, best-effort | streaming, multiplayer hry |
| MulticastSocket | UDP multicast | skupinový přenos | discovery, video broadcast |
==== 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ší, ale spolehlivý
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/klient ====
// === Server ===
try (ServerSocket srv = new ServerSocket(9000)) {
while (true) {
try (Socket s = srv.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(), true)) {
String line = in.readLine();
out.println("Echo: " + line);
}
}
}
// === Klient ===
try (Socket s = new Socket("localhost", 9000);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(), true)) {
out.println("Ahoj světe");
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 new ServerSocket(port, backlog) nastavíš frontu nepřijatých spojení.
* Nastav setSoTimeout() → ochrana proti zablokování čtení.
* Na mnoho paralelních spojení použij java.nio.channels + selektory (non-blocking I/O).
* Pro šifrovaný přenos sáhni po SSLSocket / SSLServerSocket nebo moderním klientovi java.net.http.
* Vždy uzavírej soket v try-with-resources nebo finally.
===== 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, aby se zabránilo deadlocku.
==== 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().
public class Worker extends Thread {
private final int numberOfJobs;
public Worker(int id, int jobs) {
super("Worker " + id);
myID = id;
numberOfJobs = jobs;
stop = false;
System.out.println("Worker id: " + id + " has been created threadID:" + getId());
}
public void run() {
doWork();
}
}
Worker thread = new Worker(1, 10);
thread.start(); //new thread is created
System.out.println("Program continues here");
Pokud nelze použít dědění od Thread implementujeme rozhraní Runnable:
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 "WorkerRunnable " + id;
}
@Override
public void run() { ... }
}
WorkerRunnable worker = new WorkerRunnable(1, 10);
Thread thread = new Thread(worker, worker.getName());
thread.start();
public void run() {
Thread thread = Thread.currentThread();
for (int i = 0; i < numberOfJobs; ++i) {
System.out.println("Thread name: " + thread.getName());
}
}
==== 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/Consumer – problém koordinace mezi vlákny produkujícími a spotřebovávajícími data (např. fronta).
* Řešení: wait(), notify(), fronty z balíku java.util.concurrent
* Reader/Writer – vícero vláken čte a/nebo zapisuje do stejného objektu.
* Řešení: ReadWriteLock nebo rozdělení na operace pouze pro čtení a zápis
==== Synchronized, Volatile, Join ====
* synchronized – zajišťuje, že kód (kritická sekce) provádí v daném čase jen jedno vlákno
* volatile – proměnná může být měněna z více vláken, JVM nezachová její hodnotu v cache
* 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.
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(new WorkerRunnable(1, 10));
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)