Details zum E-Book

Java. Podstawy. Wydanie XII

Java. Podstawy. Wydanie XII

Cay Horstmann

E-book

W 1995 roku świat ujrzał przyszłą gwiazdę programowania: Javę. Dziś to język dojrzały i elastyczny, dzięki czemu może służyć do pisania dużych systemów, małych programów, aplikacji mobilnych i internetowych. Java została zaprojektowana z ogromną starannością. W język wbudowano wysublimowane zabezpieczenia, a także pewne zaawansowane funkcje, które docenia każdy programista tworzący systemy o skomplikowanej architekturze.

Ta książka jest kolejnym, zaktualizowanym i uzupełnionym wydaniem kultowego podręcznika dla profesjonalnych programistów Javy. To pierwszy tom, w którym opisano podstawy języka i najważniejsze zagadnienia związane z programowaniem interfejsu użytkownika, a także kolekcje, wyrażenia lambda, techniki programowania współbieżnego i funkcyjnego. W tym wydaniu poszczególne zagadnienia zoptymalizowano pod kątem Javy 17, opisano też takie nowości jak bloki tekstu, rozszerzenia konstrukcji switch, rekordy, dopasowywanie wzorców operatora instanceof, klasy zapieczętowane i wiele więcej. Podręcznik zawiera mnóstwo przykładów kodu, obrazujących zasady działania niemal każdej opisywanej funkcji czy biblioteki. Aby nauka najważniejszych zagadnień była jeszcze łatwiejsza, przykładowe programy są proste i realistyczne.

W książce między innymi:

  • składnia i najlepsze praktyki pisania kodu w języku Java
  • interfejsy, klasy wewnętrzne i wyrażenia lambda
  • obsługa wyjątków i skuteczne techniki debugowania
  • korzystanie z typów generycznych i standardowych kolekcji Javy
  • nowoczesne graficzne interfejsy użytkownika przy użyciu komponentów Swing
  • stosowanie modelu współbieżności Javy

Java: biegle opanuj język mistrzów programowania!

Wstęp

  • Do Czytelnika
  • O książce
  • Konwencje typograficzne
  • Przykłady kodu

Podziękowania

Rozdział 1. Wprowadzenie do Javy

  • 1.1. Java jako platforma programistyczna
  • 1.2. Słowa klucze białej księgi Javy
    • 1.2.1. Prostota
    • 1.2.2. Obiektowość
    • 1.2.3. Sieciowość
    • 1.2.4. Niezawodność
    • 1.2.5. Bezpieczeństwo
    • 1.2.6. Niezależność od architektury
    • 1.2.7. Przenośność
    • 1.2.8. Interpretacja
    • 1.2.9. Wysoka wydajność
    • 1.2.10. Wielowątkowość
    • 1.2.11. Dynamiczność
  • 1.3. Aplety Javy i internet
  • 1.4. Krótka historia Javy
  • 1.5. Główne nieporozumienia dotyczące Javy

Rozdział 2. Środowisko programistyczne Javy

  • 2.1. Instalacja oprogramowania Java Development Kit
    • 2.1.1. Pobieranie pakietu JDK
    • 2.1.2. Instalacja pakietu JDK
    • 2.1.3. Instalacja plików źródłowych i dokumentacji
  • 2.2. Używanie narzędzi wiersza poleceń
  • 2.3. Praca w zintegrowanym środowisku programistycznym
  • 2.4. JShell

Rozdział 3. Podstawowe elementy języka Java

  • 3.1. Prosty program w Javie
  • 3.2. Komentarze
  • 3.3. Typy danych
    • 3.3.1. Typy całkowite
    • 3.3.2. Typy zmiennoprzecinkowe
    • 3.3.3. Typ char
    • 3.3.4. Unicode i typ char
    • 3.3.5. Typ boolean
  • 3.4. Zmienne i stałe
    • 3.4.1. Deklarowanie zmiennych
    • 3.4.2. Inicjalizacja zmiennych
    • 3.4.3. Stałe
    • 3.4.4. Typ wyliczeniowy
  • 3.5. Operatory
    • 3.5.1. Operatory arytmetyczne
    • 3.5.2. Funkcje i stałe matematyczne
    • 3.5.3. Konwersja typów numerycznych
    • 3.5.4. Rzutowanie
    • 3.5.5. Przypisanie
    • 3.5.6. Operatory inkrementacji i dekrementacji
    • 3.5.7. Operatory relacyjne i logiczne
    • 3.5.8. Operator warunkowy
    • 3.5.9. Wyrażenia switch
    • 3.5.10. Operatory bitowe
    • 3.5.11. Nawiasy i priorytety operatorów
  • 3.6. Łańcuchy
    • 3.6.1. Podłańcuchy
    • 3.6.2. Konkatenacja
    • 3.6.3. Łańcuchów nie można modyfikować
    • 3.6.4. Porównywanie łańcuchów
    • 3.6.5. Łańcuchy puste i łańcuchy null
    • 3.6.6. Współrzędne kodowe znaków i jednostki kodowe
    • 3.6.7. API String
    • 3.6.8. Dokumentacja API w internecie
    • 3.6.9. Składanie łańcuchów
    • 3.6.10. Bloki tekstowe
  • 3.7. Wejście i wyjście
    • 3.7.1. Odbieranie danych wejściowych
    • 3.7.2. Formatowanie danych wyjściowych
    • 3.7.3. Zapis i odczyt plików
  • 3.8. Sterowanie wykonywaniem programu
    • 3.8.1. Zasięg blokowy
    • 3.8.2. Instrukcje warunkowe
    • 3.8.3. Pętle
    • 3.8.4. Pętle o określonej liczbie powtórzeń
    • 3.8.5. Wybór wielokierunkowy - instrukcja switch
    • 3.8.6. Instrukcje przerywające przepływ sterowania
  • 3.9. Wielkie liczby
  • 3.10. Tablice
    • 3.10.1. Deklarowanie tablic
    • 3.10.2. Dostęp do elementów tablicy
    • 3.10.3. Pętla typu for each
    • 3.10.4. Kopiowanie tablicy
    • 3.10.5. Parametry wiersza poleceń
    • 3.10.6. Sortowanie tablicy
    • 3.10.7. Tablice wielowymiarowe
    • 3.10.8. Tablice postrzępione

Rozdział 4. Obiekty i klasy

  • 4.1. Wstęp do programowania obiektowego
    • 4.1.1. Klasy
    • 4.1.2. Obiekty
    • 4.1.3. Identyfikacja klas
    • 4.1.4. Relacje między klasami
  • 4.2. Używanie klas predefiniowanych
    • 4.2.1. Obiekty i zmienne obiektów
    • 4.2.2. Klasa LocalDate
    • 4.2.3. Metody udostępniające i zmieniające wartość elementu
  • 4.3. Definiowanie własnych klas
    • 4.3.1. Klasa Employee
    • 4.3.2. Używanie wielu plików źródłowych
    • 4.3.3. Analiza klasy Employee
    • 4.3.4. Pierwsze kroki w tworzeniu konstruktorów
    • 4.3.5. Deklarowanie zmiennych lokalnych za pomocą słowa kluczowego var
    • 4.3.6. Praca z referencjami null
    • 4.3.7. Parametry jawne i niejawne
    • 4.3.8. Korzyści z hermetyzacji
    • 4.3.9. Przywileje klasowe
    • 4.3.10. Metody prywatne
    • 4.3.11. Stałe jako pola klasy
  • 4.4. Pola i metody statyczne
    • 4.4.1. Pola statyczne
    • 4.4.2. Stałe statyczne
    • 4.4.3. Metody statyczne
    • 4.4.4. Metody fabryczne
    • 4.4.5. Metoda main
  • 4.5. Parametry metod
  • 4.6. Konstruowanie obiektów
    • 4.6.1. Przeciążanie
    • 4.6.2. Domyślna inicjalizacja pól
    • 4.6.3. Konstruktor bezargumentowy
    • 4.6.4. Jawna inicjalizacja pól
    • 4.6.5. Nazywanie parametrów
    • 4.6.6. Wywoływanie innego konstruktora
    • 4.6.7. Bloki inicjalizujące
    • 4.6.8. Niszczenie obiektów i metoda finalize
  • 4.7. Rekordy
    • 4.7.1. Koncepcja rekordu
    • 4.7.2. Konstruktory: kanoniczny, niestandardowy i kompaktowy
  • 4.8. Pakiety
    • 4.8.1. Nazwy pakietów
    • 4.8.2. Importowanie klas
    • 4.8.3. Importowanie statyczne
    • 4.8.4. Dodawanie klasy do pakietu
    • 4.8.5. Dostęp do pakietu
    • 4.8.6. Ścieżka klas
    • 4.8.7. Ustawianie ścieżki klas
  • 4.9. Pliki JAR
    • 4.9.1. Tworzenie plików JAR
    • 4.9.2. Manifest
    • 4.9.3. Wykonywalne pliki JAR
    • 4.9.4. Pliki JAR z wieloma wersjami klas
    • 4.9.5. Kilka uwag na temat opcji wiersza poleceń
  • 4.10. Komentarze dokumentacyjne
    • 4.10.1. Wstawianie komentarzy
    • 4.10.2. Komentarze do klas
    • 4.10.3. Komentarze do metod
    • 4.10.4. Komentarze do pól
    • 4.10.5. Komentarze ogólne
    • 4.10.6. Komentarze do pakietów
    • 4.10.7. Pobieranie komentarzy
  • 4.11. Porady dotyczące projektowania klas

Rozdział 5. Dziedziczenie

  • 5.1. Klasy, nadklasy i podklasy
    • 5.1.1. Definiowanie podklas
    • 5.1.2. Przesłanianie metod
    • 5.1.3. Konstruktory podklas
    • 5.1.4. Hierarchia dziedziczenia
    • 5.1.5. Polimorfizm
    • 5.1.6. Zasady wywoływania metod
    • 5.1.7. Wyłączanie dziedziczenia - klasy i metody finalne
    • 5.1.8. Rzutowanie
    • 5.1.9. Operator instanceof i dopasowywanie wzorców
    • 5.1.10. Ograniczanie dostępu
  • 5.2. Kosmiczna klasa wszystkich klas - Object
    • 5.2.1. Zmienne typu Object
    • 5.2.2. Metoda equals
    • 5.2.3. Porównywanie a dziedziczenie
    • 5.2.4. Metoda hashCode
    • 5.2.5. Metoda toString
  • 5.3. Generyczne listy tablicowe
    • 5.3.1. Deklarowanie list tablicowych
    • 5.3.2. Dostęp do elementów listy tablicowej
    • 5.3.3. Zgodność pomiędzy typowanymi a surowymi listami tablicowymi
  • 5.4. Opakowania obiektów i automatyczne pakowanie
  • 5.5. Metody ze zmienną liczbą parametrów
  • 5.6. Klasy abstrakcyjne
  • 5.7. Klasy wyliczeniowe
  • 5.8. Klasy zapieczętowane
  • 5.9. Refleksja
    • 5.9.1. Klasa Class
    • 5.9.2. Podstawy deklarowania wyjątków
    • 5.9.3. Zasoby
    • 5.9.4. Zastosowanie refleksji w analizie funkcjonalności klasy
    • 5.9.5. Refleksja w analizie obiektów w czasie działania programu
    • 5.9.6. Zastosowanie refleksji w generycznym kodzie tablicowym
    • 5.9.7. Wywoływanie dowolnych metod i konstruktorów
  • 5.10. Porady projektowe dotyczące dziedziczenia

Rozdział 6. Interfejsy, wyrażenia lambda i klasy wewnętrzne

  • 6.1. Interfejsy
    • 6.1.1. Koncepcja interfejsu
    • 6.1.2. Własności interfejsów
    • 6.1.3. Interfejsy a klasy abstrakcyjne
    • 6.1.4. Metody statyczne i prywatne
    • 6.1.5. Metody domyślne
    • 6.1.6. Wybieranie między metodami domyślnymi
    • 6.1.7. Interfejsy i wywołania zwrotne
    • 6.1.8. Interfejs Comparator
    • 6.1.9. Klonowanie obiektów
  • 6.2. Wyrażenia lambda
    • 6.2.1. Po co w ogóle są lambdy
    • 6.2.2. Składnia wyrażeń lambda
    • 6.2.3. Interfejsy funkcyjne
    • 6.2.4. Referencje do metod
    • 6.2.5. Referencje do konstruktorów
    • 6.2.6. Zakres dostępności zmiennych
    • 6.2.7. Przetwarzanie wyrażeń lambda
    • 6.2.8. Poszerzenie wiadomości o komparatorach
  • 6.3. Klasy wewnętrzne
    • 6.3.1. Dostęp do stanu obiektu w klasie wewnętrznej
    • 6.3.2. Specjalne reguły składniowe dotyczące klas wewnętrznych
    • 6.3.3. Czy klasy wewnętrzne są potrzebne i bezpieczne?
    • 6.3.4. Lokalne klasy wewnętrzne
    • 6.3.5. Dostęp do zmiennych finalnych z metod zewnętrznych
    • 6.3.6. Anonimowe klasy wewnętrzne
    • 6.3.7. Statyczne klasy wewnętrzne
  • 6.4. Moduły ładowania usług
  • 6.5. Klasy pośredniczące
    • 6.5.1. Kiedy używać klas pośredniczących
    • 6.5.2. Tworzenie obiektów pośredniczących
    • 6.5.3. Właściwości klas pośredniczących

Rozdział 7. Wyjątki, asercje i dzienniki

  • 7.1. Obsługa błędów
    • 7.1.1. Klasyfikacja wyjątków
    • 7.1.2. Deklarowanie wyjątków kontrolowanych
    • 7.1.3. Zgłaszanie wyjątków
    • 7.1.4. Tworzenie klas wyjątków
  • 7.2. Przechwytywanie wyjątków
    • 7.2.1. Przechwytywanie wyjątku
    • 7.2.2. Przechwytywanie wielu typów wyjątków
    • 7.2.3. Powtórne generowanie wyjątków i budowanie łańcuchów wyjątków
    • 7.2.4. Klauzula finally
    • 7.2.5. Instrukcja try z zasobami
    • 7.2.6. Analiza danych ze stosu wywołań
  • 7.3. Wskazówki dotyczące stosowania wyjątków
  • 7.4. Asercje
    • 7.4.1. Koncepcja asercji
    • 7.4.2. Włączanie i wyłączanie asercji
    • 7.4.3. Zastosowanie asercji do sprawdzania parametrów
    • 7.4.4. Zastosowanie asercji do dokumentowania założeń
  • 7.5. Dzienniki
    • 7.5.1. Podstawy zapisu do dziennika
    • 7.5.2. Zaawansowane techniki zapisu do dziennika
    • 7.5.3. Zmiana konfiguracji menedżera dzienników
    • 7.5.4. Lokalizacja
    • 7.5.5. Obiekty typu Handler
    • 7.5.6. Filtry
    • 7.5.7. Formatery
    • 7.5.8. Przepis na dziennik
  • 7.6. Wskazówki dotyczące debugowania

Rozdział 8. Programowanie generyczne

  • 8.1. Dlaczego programowanie generyczne
    • 8.1.1. Zalety parametrów typów
    • 8.1.2. Dla kogo programowanie generyczne
  • 8.2. Definicja prostej klasy generycznej
  • 8.3. Metody generyczne
  • 8.4. Ograniczenia zmiennych typowych
  • 8.5. Kod generyczny a maszyna wirtualna
    • 8.5.1. Wymazywanie typów
    • 8.5.2. Translacja wyrażeń generycznych
    • 8.5.3. Translacja metod generycznych
    • 8.5.4. Używanie starego kodu
  • 8.6. Ograniczenia i braki
    • 8.6.1. Nie można podawać typów prostych jako parametrów typowych
    • 8.6.2. Sprawdzanie typów w czasie działania programu jest możliwe tylko dla typów surowych
    • 8.6.3. Nie można tworzyć tablic typów generycznych
    • 8.6.4. Ostrzeżenia dotyczące zmiennej liczby argumentów
    • 8.6.5. Nie wolno tworzyć egzemplarzy zmiennych typowych
    • 8.6.6. Nie można utworzyć egzemplarza generycznej tablicy
    • 8.6.7. Zmiennych typowych nie można używać w statycznych kontekstach klas generycznych
    • 8.6.8. Obiektów klasy generycznej nie można generować ani przechwytywać
    • 8.6.9. Można wyłączyć sprawdzanie wyjątków kontrolowanych
    • 8.6.10. Uważaj na konflikty, które mogą powstać po wymazaniu typów
  • 8.7. Zasady dziedziczenia dla typów generycznych
  • 8.8. Typy wieloznaczne
    • 8.8.1. Koncepcja typu wieloznacznego
    • 8.8.2. Ograniczenia nadtypów typów wieloznacznych
    • 8.8.3. Typy wieloznaczne bez ograniczeń
    • 8.8.4. Chwytanie typu wieloznacznego
  • 8.9. Refleksja a typy generyczne
    • 8.9.1. Generyczna klasa Class
    • 8.9.2. Zastosowanie parametrów Class<T> do dopasowywania typów
    • 8.9.3. Informacje o typach generycznych w maszynie wirtualnej
    • 8.9.4. Literały typowe

Rozdział 9. Kolekcje

  • 9.1. Architektura kolekcji Javy
    • 9.1.1. Oddzielenie warstwy interfejsów od warstwy klas konkretnych
    • 9.1.2. Interfejs Collection
    • 9.1.3. Iteratory
    • 9.1.4. Generyczne metody użytkowe
  • 9.2. Interfejsy w systemie kolekcji Javy
  • 9.3. Konkretne klasy kolekcyjne
    • 9.3.1. Listy powiązane
    • 9.3.2. Listy tablicowe
    • 9.3.3. Zbiór HashSet
    • 9.3.4. Zbiór TreeSet
    • 9.3.5. Kolejki Queue i Deque
    • 9.3.6. Kolejki priorytetowe
  • 9.4. Słowniki
    • 9.4.1. Podstawowe operacje słownikowe
    • 9.4.2. Modyfikowanie wpisów w słowniku
    • 9.4.3. Widoki słowników
    • 9.4.4. Klasa WeakHashMap
    • 9.4.5. Klasy LinkedHashSet i LinkedHashMap
    • 9.4.6. Klasy EnumSet i EnumMap
    • 9.4.7. Klasa IdentityHashMap
  • 9.5. Kopie i widoki
    • 9.5.1. Małe kolekcje
    • 9.5.2. Niemodyfikowalne kopie i widoki
    • 9.5.3. Przedziały
    • 9.5.4. Widoki kontrolowane
    • 9.5.5. Widoki synchronizowane
    • 9.5.6. Uwagi dotyczące operacji opcjonalnych
  • 9.6. Algorytmy
    • 9.6.1. Dlaczego algorytmy generyczne
    • 9.6.2. Sortowanie i tasowanie
    • 9.6.3. Wyszukiwanie binarne
    • 9.6.4. Proste algorytmy
    • 9.6.5. Operacje zbiorowe
    • 9.6.6. Konwersja pomiędzy kolekcjami a tablicami
    • 9.6.7. Pisanie własnych algorytmów
  • 9.7. Stare kolekcje
    • 9.7.1. Klasa Hashtable
    • 9.7.2. Wyliczenia
    • 9.7.3. Słowniki własności
    • 9.7.4. Stosy
    • 9.7.5. Zbiory bitów

Rozdział 10. Graficzne interfejsy użytkownika

  • 10.1. Historia zestawów narzędzi do tworzenia interfejsów użytkownika
  • 10.2. Wyświetlanie ramki
    • 10.2.1. Tworzenie ramki
    • 10.2.2. Właściwości ramki
  • 10.3. Wyświetlanie informacji w komponencie
    • 10.3.1. Figury 2D
    • 10.3.2. Kolory
    • 10.3.3. Czcionki
    • 10.3.4. Wyświetlanie obrazów
  • 10.4. Obsługa zdarzeń
    • 10.4.1. Podstawowe koncepcje obsługi zdarzeń
    • 10.4.2. Przykład - obsługa kliknięcia przycisku
    • 10.4.3. Zwięzłe definiowanie procedur nasłuchowych
    • 10.4.4. Klasy adaptacyjne
    • 10.4.5. Akcje
    • 10.4.6. Zdarzenia generowane przez mysz
    • 10.4.7. Hierarchia zdarzeń w bibliotece AWT
  • 10.5. API Preferences

Rozdział 11. Komponenty Swing interfejsu użytkownika

  • 11.1. Swing i wzorzec model-widok-kontroler
  • 11.2. Wprowadzenie do zarządzania rozkładem
    • 11.2.1. Zarządcy układu
    • 11.2.2. Rozkład brzegowy
    • 11.2.3. Rozkład siatkowy
  • 11.3. Wprowadzanie tekstu
    • 11.3.1. Pola tekstowe
    • 11.3.2. Etykiety komponentów
    • 11.3.3. Pola haseł
    • 11.3.4. Obszary tekstowe
    • 11.3.5. Panele przewijane
  • 11.4. Komponenty umożliwiające wybór opcji
    • 11.4.1. Pola wyboru
    • 11.4.2. Przełączniki
    • 11.4.3. Obramowanie
    • 11.4.4. Listy rozwijane
    • 11.4.5. Suwaki
  • 11.5. Menu
    • 11.5.1. Tworzenie menu
    • 11.5.2. Ikony w elementach menu
    • 11.5.3. Pola wyboru i przełączniki jako elementy menu
    • 11.5.4. Menu podręczne
    • 11.5.5. Mnemoniki i akceleratory
    • 11.5.6. Aktywowanie i dezaktywowanie elementów menu
    • 11.5.7. Paski narzędzi
    • 11.5.8. Dymki
  • 11.6. Zaawansowane techniki zarządzania rozkładem
    • 11.6.1. Rozkład GridBagLayout
    • 11.6.2. Niestandardowi zarządcy rozkładu
  • 11.7. Okna dialogowe
    • 11.7.1. Okna dialogowe opcji
    • 11.7.2. Tworzenie okien dialogowych
    • 11.7.3. Wymiana danych
    • 11.7.4. Okna dialogowe wyboru plików

Rozdział 12. Współbieżność

  • 12.1. Czym są wątki
  • 12.2. Stany wątków
    • 12.2.1. Wątki tworzone za pomocą operatora new
    • 12.2.2. Wątki RUNNABLE
    • 12.2.3. Wątki BLOCKED i WAITING
    • 12.2.4. Zamykanie wątków
  • 12.3. Własności wątków
    • 12.3.1. Przerywanie wątków
    • 12.3.2. Wątki demony
    • 12.3.3. Nazwy wątków
    • 12.3.4. Procedury obsługi nieprzechwyconych wyjątków
    • 12.3.5. Priorytety wątków
  • 12.4. Synchronizacja
    • 12.4.1. Przykład sytuacji powodującej wyścig
    • 12.4.2. Wyścigi
    • 12.4.3. Obiekty klasy Lock
    • 12.4.4. Warunki
    • 12.4.5. Słowo kluczowe synchronized
    • 12.4.6. Bloki synchronizowane
    • 12.4.7. Monitor
    • 12.4.8. Pola ulotne
    • 12.4.9. Zmienne finalne
    • 12.4.10. Zmienne atomowe
    • 12.4.11. Zakleszczenia
    • 12.4.12. Dlaczego metody stop i suspend są wycofywane
    • 12.4.13. Inicjalizacja na żądanie
    • 12.4.14. Zmienne lokalne wątków
  • 12.5. Kolekcje bezpieczne wątkowo
    • 12.5.1. Kolejki blokujące
    • 12.5.2. Szybkie słowniki, zbiory i kolejki
    • 12.5.3. Atomowe modyfikowanie elementów słowników
    • 12.5.4. Operacje masowe na współbieżnych słownikach skrótów
    • 12.5.5. Współbieżne widoki zbiorów
    • 12.5.6. Tablice kopiowane przy zapisie
    • 12.5.7. Równoległe algorytmy tablicowe
    • 12.5.8. Starsze kolekcje bezpieczne wątkowo
  • 12.6. Zadania i pule wątków
    • 12.6.1. Interfejsy Callable i Future
    • 12.6.2. Klasa Executors
    • 12.6.3. Kontrolowanie grup zadań
    • 12.6.4. Metoda rozgałęzienie-złączenie
  • 12.7. Obliczenia asynchroniczne
    • 12.7.1. Klasa CompletableFuture
    • 12.7.2. Tworzenie obiektów CompletableFuture
    • 12.7.3. Czasochłonne zadania w wywołaniach zwrotnych interfejsu użytkownika
  • 12.8. Procesy
    • 12.8.1. Budowanie procesu
    • 12.8.2. Uruchamianie procesu
    • 12.8.3. Uchwyty procesów

Dodatek

Skorowidz

  • Titel: Java. Podstawy. Wydanie XII
  • Autor: Cay Horstmann
  • Originaler Titel: Core Java, Volume I: Fundamentals (Oracle Press Java), 12th Edition
  • Übersetzung: Łukasz Piwko
  • ISBN: 978-83-283-9480-3, 9788328394803
  • Veröffentlichungsdatum: 2022-12-06
  • Format: E-book
  • Artikelkennung: javp12
  • Verleger: Helion