→ Slide 1
↓ Slide 2
// 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
↓ Slide 3
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

↓ Slide 4
  • 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
↓ Slide 5
  • 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!");
    }
}
↓ Slide 6

Komentarz jednoliniowy:

// TO JEST KOMENTARZ

Komentarz blokowy:

/*
   TO JEST KOMENTARZ
   I TO TEŻ JEST KOMENTARZ
*/
↓ Slide 7

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:
intInteger, doubleDouble, floatFloat, itd.

↓ Slide 8
// 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)
↓ Slide 9
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ą
↓ Slide 10
  • Rzutowanie rozszerzające (automatyczne, bezstratne):
    byteshortintlongfloatdouble
  • Rzutowanie zawężające (wymagane jawnie; możliwa utrata informacji):
    doublefloatlongintshortbyte
     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
↓ Slide 11

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
↓ Slide 12

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
↓ Slide 13
  • Arytmetyczne: +, -, *, /, %, ++, --
  • Logiczne: &&, ||, !, ^, &, | (bez skracania)
  • Bitowe (dla int i long): &, |, ~, ^, <<, >>, >>> (bez znaku)
  • Porównania: ==, !=, >, <, >=, <=
  • Przypisania i operatory skrócone: =, +=, -=, *=, /=, %=, &=, |=, ^=, >>=, <<=
↓ Slide 14

Java dostarcza klasę Math z wieloma przydatnymi funkcjami.

Dokumentacja: Math (Java SE 17 & JDK 17) (oracle.com)

↓ Slide 15
if (warunek) {
    // ...
} else if (innyWarunek) {
    // ...
} else {
    // ...
}
  • warunek musi być typu boolean
↓ Slide 16

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 */ }
↓ Slide 17
switch (wyrazenie) {
    case wartosc1:
        // ...
        break;
    case wartosc2:
        // ...
        break;
    default:
        // ...
}
  • wyrażenie musi być typu byte, short, char, int, String lub wyliczeniowego (enum)
↓ Slide 18
while (warunek) {
    // ...
}
do {
    // ...
} while (warunek);
↓ Slide 19
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)
↓ Slide 20
  • 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 {
    // ...
}
↓ Slide 21
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ą
        }
    }
}
↓ Slide 22
  • 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)
↓ Slide 23

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
↓ Slide 24

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.

↓ Slide 25

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