~~NOCACHE~~ ~~REVEAL theme=simple&disableLayout=0&transition=none&controls=1&show_progress_bar=1&build_all_lists=0&show_image_borders=0&horizontal_slide_level=2&enlarge_vertical_slide_headers=0&show_slide_details=1&open_in_new_window=1&size=1024x768~~ ===== Zajęcia 2 - Składnia języka Java ===== ==== Najprostszy program w języku Java ==== // Main.java public class Main { public static void main(String[] args) { System.out.println("Hello World!"); } } * ''System'' - predefiniowana klasa w bibliotece standardowej Javy, zawierająca m.in. strumienie wejścia/wyjścia (''in'', ''out'', ''err'') * ''public static void main(String[] args)'' - punkt wejścia aplikacji ==== Słowa kluczowe ==== abstract assert boolean break byte case catch char class const continue default do double else enum exports extends final finally float for goto if implements import instanceof int interface long module native new non-sealed open opens package permits private protected provides public record requires return sealed short static strictfp super switch synchronized this throw throws to transient transitive try uses var void volatile while with yield ''true'', ''false'' i ''null'' - literały, także zarezerwowane słowa ==== Pakiet (paczka) ==== * **Pakiet** (ang. //package//) - grupuje klasy, pozwala uniknąć konfliktów nazw (odpowiednik przestrzeni nazw), struktura katalogów odpowiadająca hierarchii pakietów * [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/package-summary.html|java.lang]] - pakiet zawierający podstawowe klasy Javy (''String'', ''Math'', ''System'', itp.), jedyna paczka importowana domyślnie * struktura pakietów odzwierciedla strukturę katalogów w projekcie * Importowanie pakietów za pomocą dyrektywy ''import'' import java.util.Scanner; // import pojedynczej klasy Scanner import java.util.*; // import wszystkich klas z pakietu ==== Definiowanie własnych paczek ==== * Dodajemy katalog o nazwie odpowiadającej pakietowi (wewnątrz modułu/projektu). * Wewnątrz katalogu tworzymy plik ''.java'' o nazwie klasy. * Na początku pliku dodajemy deklarację pakietu, np.: ''package myMain;'' // Main.java package myMain; public class Main { public static void main(String[] args) { System.out.println("Hello World!"); } } ==== Komentarze w języku Java ==== Komentarz jednoliniowy: // TO JEST KOMENTARZ Komentarz blokowy: /* TO JEST KOMENTARZ I TO TEŻ JEST KOMENTARZ */ ==== Typy danych w języku Java ==== **Typy proste** (ang. //primitives//): * **całkowitoliczbowe:** ''byte'', ''short'', ''int'', ''long'' * **zmiennoprzecinkowe:** ''float'', ''double'' * **logiczne:** ''boolean'' (''true''/''false'', nie jest liczbą) * **znakowe:** ''char'' **Typy złożone** (obiektowe): * ''String'', tablice, ''Object'', klasy użytkownika, interfejsy, kolekcje (''List'', ''Set'', ''Map''), itp. Dla typów prostych istnieją klasy opakowujące (wrappery), które rozszerzają ''Number'': \\ ''int'' → ''Integer'', ''double'' → ''Double'', ''float'' → ''Float'', itd. ==== Deklaracja zmiennych ==== // typy proste int a, b = 42; double d = 3.14; boolean flag = true; char c = 'a'; // typy obiektowe Scanner sc = new Scanner(System.in); String str = "Hello"; int [] arr = {1, 2, 3, 4, 5}; * zmienne typu obiektowego przechowują referencję (adres) do obiektu w pamięci, a nie sam obiekt * domyślne wartości dla typów prostych: ''0'' dla liczb, ''false'' dla ''boolean'', ''\u0000'' dla ''char'' * domyślna wartość dla typów obiektowych: ''null'' (nie wskazuje na żaden obiekt) ==== Stałe liczbowe i znakowe ==== int a = 42; // stała całkowitoliczbowa (int) int b = 0x2A; // stała szesnastkowa (42 w systemie szesnastkowym) int c = 0b101010; // stała binarna (42 w systemie binarnym) int d = 042; // stała ósemkowa (34 w systemie ósemkowym) long e = 42L; // stała typu long int f = 3_000_000; // podkreślenia dla czytelności (3000000) float x1 = 3.14f; // stała typu float double x2 = 3.14; // stała zmiennoprzecinkowa (double) double x3 = 1.5e-3; // stała w notacji naukowej (0.0015) char c1 = 'A'; // stała znakowa (pojedynczy znak) char c2 = 65; // stała znakowa jako liczba (również 'A', bo 65 to kod ASCII dla 'A') char c3 = '\u0041'; // stała znakowa w notacji Unicode (również 'A') char c4 = '\101'; // stała znakowa w notacji ósemkowej (również 'A') char c5 = '\n'; // stała znakowa dla nowej linii String str1 = "Hello"; // stała łańcuchowa (ciąg znaków) String str2 = "Line1\nLine2"; // stała łańcuchowa z nową linią ==== Rzutowanie typów prostych ==== * **Rzutowanie rozszerzające** (automatyczne, bezstratne): \\ ''byte'' → ''short'' → ''int'' → ''long'' → ''float'' → ''double'' * **Rzutowanie zawężające** (wymagane jawnie; możliwa utrata informacji): \\ ''double'' → ''float'' → ''long'' → ''int'' → ''short'' → ''byte'' \\ int i = (int) 3.14; * Uwaga: w operacjach arytmetycznych automatyczna promocja wyrażeń ''byte'', ''short'' i ''char'' do ''int'' \\ byte b = 10; b = b*2; // BŁĄD, bo wynik jest int, a nie byte b = (byte)(b*2); // OK, rzutowanie zawężające, wynik jest byte ==== Tablice ==== Jednowymiarowa: Typ[] tablica1D = { ... }; Typ[] tablica1D = new Typ[rozmiar]; Typ tablica1D[] = new Typ[rozmiar]; // alternatywna składnia Wielowymiarowa: Typ[][] tablica2D = { { ... }, ..., { ... } }; Typ[][] tablica2D = new Typ[rozmiar1][rozmiar2]; Typ[][] tablica2D = new Typ[rozmiar1][]; // tablica tablic Dostęp do elementów: * ''tablica[i]'' - i-ty element jednowymiarowej tablicy * ''tablica[i][j]'' - element tablicy dwuwymiarowej * indeksowanie od 0 * [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html|java.util.Arrays (Java SE 17 & JDK 17)]] - klasa z metodami pomocniczymi do pracy z tablicami ==== Łańcuchy znaków ==== Java posiada rozbudowaną bibliotekę do obsługi łańcuchów znaków (''String''), dokumentacja: [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html|String (Java SE 17 & JDK 17)]] String str = "abc"; // is equivalent to: char data[] = {'a', 'b', 'c'}; String str = new String(data); * Stringi są niemodyfikowalne (immutable) - każda operacja tworzy nowy obiekt String * Do modyfikacji łańcuchów znaków służą klasy ''StringBuilder'' i ''StringBuffer'' ==== Operatory ==== * **Arytmetyczne:** ''+'', ''-'', ''*'', ''/'', ''%'', ''++'', ''%%--%%'' * **Logiczne:** ''&&'', ''||'', ''!'', ''^'', ''&'', ''|'' (bez skracania) * **Bitowe** (dla ''int'' i ''long''): ''&'', ''|'', ''~'', ''^'', ''%%<<%%'', ''%%>>%%'', ''%%>>>%%'' (bez znaku) * **Porównania:** ''=='', ''!='', ''>'', ''<'', ''>='', ''%%<=%%'' * **Przypisania i operatory skrócone:** ''='', ''+='', ''-='', ''*='', ''/='', ''%='', ''&='', ''|='', ''^='', ''%%>>=%%'', ''%%<<=%%'' ==== Biblioteka matematyczna ==== Java dostarcza klasę ''Math'' z wieloma przydatnymi funkcjami. Dokumentacja: [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Math.html|Math (Java SE 17 & JDK 17) (oracle.com)]] ==== Instrukcja warunkowa if ==== if (warunek) { // ... } else if (innyWarunek) { // ... } else { // ... } * warunek musi być typu ''boolean'' ==== Operatory logiczne i wyrażenia warunkowe ==== Operatory logiczne bez skracania if(x != 0 & 10/x > 1) { // BŁĄD, bo x może być równe 0, a wtedy dzielenie przez zero spowoduje wyjątek } Operatory skracające if(x != 0 && 10/x > 1) { // OK, bo jeśli x jest równe 0, to drugi operand nie jest sprawdzany } Operacje warunkowe tylko dla typu ''boolean'': int x = 5; if (!x) { /* BŁĄD, bo x nie jest typu boolean */ } if (x > 0) { /* OK, bo x > 0 jest wyrażeniem typu boolean */ } ==== Instrukcja switch ==== switch (wyrazenie) { case wartosc1: // ... break; case wartosc2: // ... break; default: // ... } * wyrażenie musi być typu ''byte'', ''short'', ''char'', ''int'', ''String'' lub wyliczeniowego (''enum'') ==== Pętla while, do while ==== while (warunek) { // ... } do { // ... } while (warunek); ==== Pętle for / foreach ==== for (inicjalizacja; warunek; inkrementacja) { // ... } for (Typ zmienna : tablica) { // foreach (pętla rozszerzona) } * zmienna w pętli foreach tylko do odczytu (nie można jej modyfikować, bo jest tylko kopią elementu z tablicy) ==== Instrukcje skoku ==== * ''break'' - przerywa najbliższą pętlę lub instrukcję ''switch'' * ''continue'' - przeskakuje do następnej iteracji pętli * ''goto'' - nie istnieje w Javie (ale jest słowem kluczowym) * ''return'' - zwraca wartość z metody i kończy jej wykonanie * ''try'', ''catch'', ''finally'' - obsługa wyjątków. Jeżeli jakaś metoda deklaruje, że operacja rzuca wyjątek, to musi być on obsłużony lub zadeklarowany w sygnaturze metody (''throws''). try { // ... } catch (Wyjatek e) { // ... } finally { // ... } ==== break / continue - skok do etykiety ==== label: while (warunek) { // ... while(innyWarunek) { // ... if (jeszczeInnyWarunek) { break label; // przerywa pętlę oznaczoną etykietą } } } label: for (int i = 0; i < n; i = i + 1) { // ... for (int j = 0; j < m; j = j +1) { // ... if (warunek) { continue label; // przeskakuje do następnej iteracji // pętli oznaczonej etykietą } } } ==== Konwencja nazewnictwa ==== * klasy i interfejsy: PascalCase (np. ''Main'', ''Scanner'', ''String'') * metody i zmienne: camelCase (np. ''main'', ''nextLine'', ''myVariable'') * stałe: UPPER_SNAKE_CASE (np. ''MAX_VALUE'', ''PI'') * pakiety: lowercase (np. ''java.util'', ''myapp'') ==== Operacje I/O w konsoli ==== Strumień wejściowy ''System.in'' - odczyt danych z konsoli: * klasa ''BufferedReader'' i ''InputStreamReader'' \\ var reader = new BufferedReader(new InputStreamReader(System.in)); String line = reader.readLine(); // czyta linię tekstu Integer.parseInt(line); // konwersja tekstu na liczbę całkowitą * klasa ''Scanner'' \\ Scanner sc = new Scanner(System.in); sc.nextLine(); // czyta linię tekstu sc.nextInt(); // czyta liczbę całkowitą Strumień wyjściowy ''System.out'' \\ System.out.println("Hello World!"); // wypisuje tekst i przechodzi do nowej linii System.out.print("Hello World!"); // wypisuje tekst bez przechodzenia do nowej linii System.out.printf("Wartość: %.2f", 3.14159); // formatowanie jak w C ==== Ćwiczenie: silnia ==== Stwórz pakiet ''factorial'' i napisz program ''FactorialCalculator'', który czyta nieujemne $n$ i oblicza silnię $n!$ $$n! = 1 \cdot 2 \cdot ... \cdot n$$. Spróbuj zrealizować program w taki sposób, aby działał poprawnie dla dużych wartości ''n'' (np. 1000). Użyj typu ''java.math.BigInteger''. ==== Zadanie 1 - Aproksymacja funkcji wykładniczej ==== Napisz program, który oblicza przybliżenie funkcji wykładniczej $e^x$ przy pomocy szeregu Taylora: $$e^x = \sum_{n=0}^{\infty} \frac{x^n}{n!}$$ obliczając sumę $n$ pierwszych wyrazów tego szeregu. Użyj typu ''java.math.BigDecimal'' do przechowywania wyniku i zapewnij odpowiednią precyzję obliczeń. Kolejne wyrazy szeregu $t_0, t_1, t_2, ...$ umieść w tablicy. Wskazówki: * użyj rekurencji wyrazu: $t_0=1, t_{k+1}=t_k \cdot \frac{x}{k+1}$ aby uniknąć wielokrotnego liczenia silni. * przy dzieleniu liczb ''BigDecimal'' określ kontekst matematyczny ''MathContext'' (lub ''scale'' i ''RoundingMode'') aby uniknąć ''ArithmeticException'' dla nieskończonych rozwinięć. **Wejście programu:** * liczba rzeczywista $x$, * liczba całkowita $n$ (liczba wyrazów szeregu, domyślnie 100), * precyzja obliczeń (liczba cyfr znaczących, domyślnie $50$). Wartości domyślne są używane, gdy użytkownik poda pustą linię zamiast liczby. **Wyjście programu:** * przybliżenie $e^x$, * porównanie z wartością obliczoną przy pomocy funkcji ''Math.exp(x)''.