Składnia języka Java

Writing /home/grochu/public_html/wiki/data/meta/zajecia/java/02_skladnia.meta failed
Unable to save metadata file. Hint: disk full; file permissions; safe_mode setting.
Writing /home/grochu/public_html/wiki/data/meta/zajecia/java/sidebar.meta failed

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=1024×768

<html> <style type=„text/css”> p { text-align: left;} .reveal pre code {

height: 100%;
max-height: 100%;
box-sizing: border-box; }

</style> </html>

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
  • 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
  • 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:

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: 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).