Basics Flashcards

1
Q

HashMap

A

HashMap to struktura danych w języku Java, która implementuje interfejs Map i umożliwia przechowywanie danych w formie par klucz-wartość. Jest często używana do tworzenia kolekcji, w której można szybko znajdować wartości na podstawie ich kluczy. Klucze w HashMap są unikalne, co oznacza, że nie może istnieć więcej niż jedna para z tym samym kluczem.

Oto główne cechy HashMap:

Klucz-Wartość: HashMap przechowuje dane w formie par klucz-wartość. Klucz jest unikalny w obrębie HashMap, co oznacza, że każda para klucz-wartość ma unikalny klucz.

Szybki dostęp: HashMap umożliwia bardzo szybki dostęp do wartości na podstawie klucza. Dzięki temu jest wydajnym sposobem przechowywania i pobierania danych.

Brak gwarancji kolejności: Elementy w HashMap nie są przechowywane w określonej kolejności. W przeciwnym razie, kolejność elementów może być niestabilna i może zmieniać się w zależności od implementacji i historii operacji.

Null-klucze i null-wartości: HashMap zezwala na przechowywanie wartości null oraz pojedynczego klucza null. Oznacza to, że możesz przechowywać wartości, które nie są zdefiniowane, ale nie można przechowywać wielu wartości z kluczem null.

Niestabilność rozmiaru: Rozmiar HashMap może się dynamicznie zmieniać w zależności od ilości danych przechowywanych w kolekcji.

Wielowątkowość: HashMap nie jest w pełni bezpieczna w kontekście wielowątkowym. W przypadku współbieżnego dostępu do HashMap może być konieczne stosowanie dodatkowych mechanizmów synchronizacji lub rozważenie użycia synchronizowanych wersji Hashtable lub ConcurrentHashMap.

Przykład użycia HashMap w Javie:

java
Copy code
import java.util.HashMap;
import java.util.Map;

public class Main {
public static void main(String[] args) {
// Tworzenie i inicjalizacja HashMap
Map<String, Integer> hashMap = new HashMap<>();

    // Dodawanie par klucz-wartość
    hashMap.put("Jan", 25);
    hashMap.put("Anna", 30);
    hashMap.put("Marek", 22);

    // Pobieranie wartości na podstawie klucza
    int age = hashMap.get("Anna");
    System.out.println("Wiek Anny: " + age);
} } HashMap jest często używana do przechowywania danych, takich jak konfiguracje, cache, indeksy i wiele innych, gdzie dostęp do danych na podstawie klucza jest istotny.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

HashMap zasada działania

A

Oto bardziej szczegółowe wyjaśnienie działania HashMap:

Inicjalizacja: Kiedy tworzysz nową instancję HashMap, tworzona jest wewnętrzna tablica o określonym początkowym rozmiarze. Ta tablica będzie służyć do przechowywania par klucz-wartość.

Funkcja mieszająca (hashing): Każdy klucz jest przekształcany w unikalny skrócony hasz (hash code) za pomocą specjalnej funkcji mieszającej. Ta funkcja zamienia długi ciąg znaków, jakim jest klucz, na krótszy ciąg liczbowy (skrót). Skrócony hasz jest używany jako indeks do przechowywania wartości w tablicy.

Zamiana hasza w indeks: Skrócony hasz jest przekształcany w indeks wewnętrznej tablicy, zwykle przez wykorzystanie operacji reszty z dzielenia przez liczbę dostępnych indeksów. Na przykład, skrócony hasz może być przekształcony w indeks w zakresie od 0 do (rozmiar tablicy - 1).

Dodawanie danych: Aby dodać parę klucz-wartość do HashMap, obliczany jest skrócony hasz klucza, a następnie przeliczany na indeks w tablicy. Jeśli wskazany indeks jest wolny (tj. nie ma jeszcze wartości), para klucz-wartość jest zapisywana pod tym indeksem. Jeśli występuje kolizja (czyli inne pary mają ten sam indeks), HashMap musi obsłużyć ją, np. umieszczając nową parę w specjalnej strukturze danych wewnątrz tego indeksu.

Pobieranie danych: Aby pobrać wartość na podstawie klucza, HashMap oblicza skrócony hasz klucza i przelicza go na indeks w tablicy. Następnie przeszukuje tablicę, aby znaleźć odpowiednią parę klucz-wartość pod wskazanym indeksem. W przypadku kolizji, HashMap musi sprawdzić, która para klucz-wartość jest właściwą odpowiedzią.

Rozmiar tablicy: HashMap ma zmienne rozmiary tablicy. Jeśli liczba przechowywanych elementów przekracza pewien próg (nazywany “ładunkiem”), HashMap może zdecydować się na zwiększenie rozmiaru tablicy, aby zmniejszyć gęstość elementów na indeksach. To pomaga utrzymać wydajność.

Null-klucze i null-wartości: HashMap pozwala na przechowywanie kluczy i wartości null. Jednak istnieje ograniczenie, że w danej mapie może istnieć tylko jedna para z kluczem null. Można przechowywać wiele wartości z kluczem null.

Kolizje: W przypadku, gdy dwie różne pary klucz-wartość mają ten sam indeks w tablicy, HashMap używa specjalnych struktur danych wewnętrznych, takich jak lista lub drzewo, aby przechowywać te pary w jednym “bucket” (koszu). Rozwiązywanie kolizji polega na iteracji lub przeszukiwaniu tych struktur danych wewnątrz indeksu.

HashMap oferuje bardzo szybki dostęp do danych, ponieważ przeszukiwanie tablicy jest operacją o stałym czasie (O(1)), o ile nie ma nadmiernego zapełnienia (co może prowadzić do spadku wydajności). Jest to bardzo użyteczna struktura danych do przechowywania i pobierania danych na podstawie kluczy w aplikacjach Java.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

HashMap budowa wewnętrzna

A

Wewnętrzna struktura HashMap w języku Java jest złożona i opiera się na tablicy z tzw. “bucketami”, które zawierają pary klucz-wartość. Oto podstawowa budowa wewnętrza HashMap:

Tablica (Array): HashMap wykorzystuje wewnętrzną tablicę do przechowywania “bucketów”, które zawierają pary klucz-wartość. Tablica jest dynamicznie dostosowywana w zależności od ilości przechowywanych elementów i może być powiększana lub zmniejszana w miarę potrzeb.

Bucket: Każdy element tablicy jest referencją do “bucketu”, który może zawierać jedną lub wiele par klucz-wartość. W przypadku, gdy wiele różnych kluczy ma ten sam indeks w tablicy (kolizja), HashMap używa struktury danych wewnątrz “bucketu” do przechowywania tych par.

Lista lub Drzewo: Dla rozwiązywania kolizji HashMap może wykorzystywać listę lub drzewo wewnątrz “bucketu”. W przypadku, gdy kilka par klucz-wartość ma ten sam indeks w tablicy, są one umieszczane wewnątrz “bucketu”. W takim przypadku HashMap może stosować listę lub drzewo wewnątrz “bucketu” do przechowywania i rozwiązywania konfliktów.

Pary klucz-wartość: Wewnątrz “bucketu” znajdują się pary klucz-wartość. Każda para składa się z klucza i odpowiadającej mu wartości. HashMap wykorzystuje skrócony hasz klucza, aby efektywnie odnajdywać odpowiednią parę w “bucketach”.

Ogólnie rzecz biorąc, HashMap tworzy tablicę z pewnym początkowym rozmiarem, a każda komórka tablicy zawiera referencję do “bucketu”. Wewnątrz “bucketu” są przechowywane pary klucz-wartość, a w przypadku kolizji, listy lub drzewa służą do przechowywania wielu par.

Dynamiczne dostosowywanie rozmiaru tablicy i rozwiązywanie konfliktów w “bucketach” pozwalają na efektywne przechowywanie i pobieranie danych w HashMap. Dzięki temu HashMap jest jednym z najczęściej używanych rodzajów map w Javie.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Linked List

A

Lista jednokierunkowa (ang. singly linked list) to struktura danych, która służy do przechowywania kolekcji elementów, zwanych węzłami, w których każdy węzeł zawiera dane oraz wskaźnik (ang. pointer) do następnego węzła w liście. Działa to na zasadzie łańcucha, gdzie każdy element wskazuje na kolejny, tworząc sekwencję.

Ogólna zasada działania listy jednokierunkowej jest następująca:

Węzły: Każdy węzeł w liście zawiera dwie rzeczy:

Dane: To mogą być dowolne informacje, które chcemy przechowywać w liście, na przykład liczby całkowite, łańcuchy znaków, obiekty itp.
Wskaźnik do następnego węzła: Wskaźnik ten wskazuje na kolejny węzeł w liście. Ostatni węzeł w liście wskazuje na null lub None, co oznacza koniec listy.
Struktura listy: Lista jednokierunkowa zazwyczaj ma jeden wskaźnik, który wskazuje na głowę listy (ang. head). Głowa to pierwszy węzeł w liście. Aby uzyskać dostęp do innych węzłów, musisz przeszukać listę, przechodząc od jednego węzła do drugiego, korzystając z ich wskaźników.

Operacje na liście jednokierunkowej:

Dodawanie elementu: Możesz dodać nowy element do listy, tworząc nowy węzeł i ustawiając wskaźnik poprzedniego węzła na ten nowy węzeł.
Usuwanie elementu: Możesz usunąć węzeł, aktualizując wskaźniki poprzedniego węzła tak, aby omijały usunięty węzeł.
Wyszukiwanie elementu: Możesz przeszukiwać listę, porównując dane węzłów z danymi, których szukasz.
Modyfikowanie elementu: Możesz zmieniać dane w węzłach, gdy znajdziesz węzeł, który chcesz zaktualizować.
Zalety i wady:

Zalety:
Dynamiczny rozmiar: Możesz dodawać i usuwać elementy z listy w czasie rzeczywistym, bez potrzeby alokacji stałej ilości pamięci.
Efektywne wstawianie i usuwanie: Dodawanie i usuwanie elementów z początku listy jest efektywne, o ile masz dostęp do głowy listy.
Wady:
Wolne przeszukiwanie: Przeszukiwanie elementu w liście jednokierunkowej może być wolne, ponieważ musisz przeglądać listę w porządku, zaczynając od głowy.
Brak dostępu wstecznego: Nie masz dostępu do poprzednich węzłów bez rekursji lub innych technik.
Listy jednokierunkowe są często wykorzystywane w programowaniu, szczególnie w językach takich jak C, C++, Java, Python itp. Są używane tam, gdzie dynamiczny rozmiar i szybkie wstawianie/usuwanie elementów są ważne, a dostęp do elementów wstecz nie jest wymagany.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Array List

A

ArrayList to struktura danych w językach programowania, taka jak Java, C#, Python (w ramach bibliotek, np. list w Pythonie), która działa podobnie do tradycyjnej tablicy (array), ale ma elastyczny rozmiar i wiele wbudowanych operacji, które ułatwiają zarządzanie danymi. ArrayList jest często używany, gdy potrzebujesz kolekcji elementów o zmiennej długości, gdzie dostęp do elementów odbywa się na podstawie indeksu.

Oto ogólna zasada działania ArrayList:

Elastyczny rozmiar: ArrayList umożliwia dynamiczne zmienianie rozmiaru kolekcji. Oznacza to, że możesz dodawać i usuwać elementy z listy bez konieczności określania jej rozmiaru na etapie tworzenia.

Przechowywanie danych: ArrayList przechowuje elementy w tablicy o zmiennej długości. Na początku ma pewną początkową pojemność, ale kiedy lista się zapełnia, automatycznie powiększa swoją pojemność, aby pomieścić więcej elementów.

Operacje na ArrayList:

Dodawanie elementów: Możesz dodać nowy element do ArrayList przy użyciu metody add(). Jeśli tablica jest zapełniona, zostanie automatycznie powiększona.
Usuwanie elementów: Możesz usunąć element z ArrayList za pomocą metody remove() lub removeAt().
Dostęp do elementów: Możesz uzyskiwać dostęp do elementów w ArrayList poprzez indeksowanie, np. get(index).
Wyszukiwanie elementów: Możesz przeszukiwać ArrayList w celu znalezienia określonego elementu, używając np. metody contains().
Iteracja: Możesz iterować po elementach w ArrayList, używając pętli lub iteratorów.
Zalety i wady:

Zalety:
Elastyczny rozmiar: ArrayList automatycznie zarządza rozmiarem, co ułatwia dodawanie i usuwanie elementów.
Skuteczne przeszukiwanie: ArrayList umożliwia dostęp do elementów poprzez indeks, co oznacza, że przeszukiwanie jest szybkie.
Dobre wydajności w przypadku dostępu do elementów: Dostęp do elementów w ArrayList jest szybki.
Wady:
Dla dużych kolekcji: Rozszerzanie ArrayList może być kosztowne w przypadku dużych kolekcji, ponieważ wymaga realokacji pamięci.
Nieefektywne wstawianie i usuwanie na początku: Wstawianie lub usuwanie elementów na początku ArrayList może być kosztowne ze względu na przesunięcie innych elementów.
ArrayList jest powszechnie używany w programowaniu do przechowywania i zarządzania kolekcjami danych o zmiennym rozmiarze, w szczególności w językach, które nie mają wbudowanych tablic o zmiennej długości, takich jak Java czy C#.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Typy danych w javie

A

ava oferuje różne typy danych, które można podzielić na kilka kategorii. Poniżej przedstawiam najważniejsze typy danych dostępne w Javie:

Typy prymitywne (primitive types):

int: Przechowuje liczby całkowite.
byte: Przechowuje małe liczby całkowite.
short: Przechowuje krótkie liczby całkowite.
long: Przechowuje długie liczby całkowite.
float: Przechowuje liczby zmiennoprzecinkowe (z ograniczoną precyzją).
double: Przechowuje liczby zmiennoprzecinkowe (z podwójną precyzją).
char: Przechowuje pojedyncze znaki Unicode.
boolean: Przechowuje wartości logiczne true lub false.
Typy referencyjne (reference types):

String: Przechowuje łańcuchy znaków.
Klasy: Programiści mogą tworzyć własne klasy zdefiniowane przez użytkownika.
Interfejsy: Definiują abstrakcyjne metody, które implementują różne klasy.
Enumeracje (enum): Reprezentują zestaw stałych wartości.
Tablice (arrays): Przechowują sekwencje elementów o tym samym typie danych.
Typy zdefiniowane przez użytkownika (user-defined types):

Klasa: Programiści mogą tworzyć własne klasy, definiując własne typy danych.
Interfejs: Definiują zestaw metod, które inne klasy mogą implementować.
Enumeracje (enum): Reprezentują zestaw stałych wartości.
Typy generyczne (generic types):

Programiści mogą tworzyć ogólne klasy i interfejsy, które mogą obsługiwać różne typy danych.
Typy złożone (complex types):

Klasa: Obejmuje dane i metody.
Interfejs: Definiuje zestaw metod, które inne klasy implementują.
Enumeracje (enum): Reprezentują zestaw stałych wartości.
Tablice: Przechowują sekwencje elementów o tym samym typie danych.
Typy bazowe (base types):

Byte, Short, Integer, Long: Klasa opakowująca dla typów prymitywnych.
Float, Double: Klasa opakowująca dla typów zmiennoprzecinkowych.
Character: Klasa opakowująca dla typu char.
Boolean: Klasa opakowująca dla typu boolean.
W Javie, typy prymitywne są bardziej wydajne w użyciu niż typy referencyjne, ale nie mogą przechowywać wartości null. Typy referencyjne, takie jak String czy klasy, mogą przechowywać null i są bardziej wszechstronne. Programiści mogą również tworzyć swoje własne typy danych, tworząc klasy i interfejsy zdefiniowane przez użytkownika.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Przeciążanie i nadpisywanie metod

A

Przeciążanie (overloading) i nadpisywanie (overriding) to dwa różne mechanizmy w języku Java, które pozwalają na definiowanie różnych zachowań dla metod o tych samych nazwach w różnych klasach lub w tej samej klasie. Oto ich krótka charakteryzacja oraz przykłady:

Przeciążanie (overloading):

Przeciążanie metod w Javie polega na definiowaniu wielu wersji tej samej metody w danej klasie, ale z różnymi zestawami parametrów (typami lub ilością parametrów). Wszystkie te wersje muszą różnić się od siebie pod względem parametrów.

Przykład przeciążania:

java
Copy code
public class Calculator {
public int add(int a, int b) {
return a + b;
}

public double add(double a, double b) {
    return a + b;
}

public String add(String a, String b) {
    return a + b;
} } W powyższym przykładzie mamy trzy wersje metody add, z których każda przyjmuje różne typy danych jako parametry. Dzięki przeciążaniu, możemy używać add do dodawania liczb całkowitych, zmiennoprzecinkowych lub łańcuchów znaków.

Nadpisywanie (overriding):

Nadpisywanie metod w Javie występuje, gdy klasa podrzędna dostarcza własną implementację metody, która jest już zdefiniowana w klasie nadrzędnej (lub interfejsie). Metoda podrzędna musi mieć ten sam nazwę, ten sam typ zwracany i ten sam zestaw parametrów co metoda nadrzędna.

Przykład nadpisywania:

java
Copy code
class Animal {
public void makeSound() {
System.out.println(“Dźwięk zwierzęcia”);
}
}

class Dog extends Animal {
@Override
public void makeSound() {
System.out.println(“Szczekanie psa”);
}
}
W powyższym przykładzie metoda makeSound w klasie Dog nadpisuje metodę makeSound z klasy Animal. Dzięki temu, gdy wywołamy makeSound na obiekcie Dog, zostanie wykonana implementacja z klasy Dog, a nie z klasy Animal.

Przeciążanie pozwala na różne wersje tej samej metody w ramach jednej klasy, natomiast nadpisywanie umożliwia modyfikację zachowania dziedziczonej metody w klasie podrzędnej. Obie te techniki są ważne w programowaniu obiektowym i pozwalają na elastyczność i reużywalność kodu.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Różnica między == a equals?

A

W języku Java == i .equals() to dwie różne operacje używane do porównywania obiektów. Oto główne różnice między nimi:

== (operator porównywania referencji):

== służy do porównywania referencji do obiektów, a nie samych obiektów.
Porównuje, czy dwie referencje wskazują na ten sam obszar pamięci, czyli na ten sam obiekt.
Zwraca true, jeśli referencje wskazują na ten sam obiekt, a false, jeśli wskazują na różne obiekty.
.equals() (metoda porównywania zawartości):

.equals() jest metodą zdefiniowaną w klasie java.lang.Object, którą dziedziczy każda klasa w Javie.
Domyślna implementacja metody .equals() w klasie Object działa tak samo jak ==, tj. porównuje referencje do obiektów.
Niemniej jednak, wiele klas w Javie przesłania tę metodę, aby porównać zawartość obiektów, a nie tylko referencje.
Przykład:

java
Copy code
String str1 = new String(“abc”);
String str2 = new String(“abc”);
String str3 = str1;

boolean result1 = (str1 == str2); // Porównuje referencje, zwraca false
boolean result2 = (str1 == str3); // Porównuje referencje, zwraca true
boolean result3 = str1.equals(str2); // Porównuje zawartość (treść) obiektów, zwraca true

System.out.println(result1); // false
System.out.println(result2); // true
System.out.println(result3); // true
W powyższym przykładzie, == porównuje referencje str1 i str2, co zwraca false, ponieważ są to różne obiekty. == porównuje referencje str1 i str3, co zwraca true, ponieważ obie te referencje wskazują na ten sam obiekt. .equals() porównuje zawartość obiektów str1 i str2, co zwraca true, ponieważ oba obiekty zawierają ten sam łańcuch znaków “abc”.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Co to jest deklaracja, inicjalizacja i przypisanie w kontekście zmiennych w Javie?

A

Deklaracja, inicjalizacja i przypisanie to trzy ważne kroki związane z zarządzaniem zmiennymi w języku Java:

Deklaracja:

Deklaracja to pierwszy krok w tworzeniu zmiennej.
W deklaracji określasz typ zmiennej i jej nazwę.
Deklaracja nie przydziela pamięci ani nie przypisuje wartości zmiennej; po prostu informuje kompilator o istnieniu zmiennej o określonym typie i nazwie.
Przykład deklaracji:
java
Copy code
int x;
String name;
Inicjalizacja:

Inicjalizacja to proces nadawania zmiennej początkowej wartości.
Po zadeklarowaniu zmiennej możesz przypisać jej wartość przy pomocy operatora przypisania =.
Inicjalizacja jest ważna, ponieważ niezainicjalizowana zmienna w Javie ma wartość domyślną (zero, null, itp.), co może prowadzić do błędów w działaniu programu.
Przykład inicjalizacji:
java
Copy code
int x = 10;
String name = “John”;
Przypisanie:

Przypisanie jest procesem zmiany wartości zmiennej po jej zainicjowaniu.
Możesz wielokrotnie przypisywać nowe wartości zmiennej w trakcie działania programu.
Przypisanie odbywa się również przy użyciu operatora przypisania =.
Przykład przypisania:
java
Copy code
x = 20; // Zmiana wartości zmiennej x na 20
name = “Alice”; // Zmiana wartości zmiennej name na “Alice”
Podsumowując, deklaracja to proces informowania kompilatora o istnieniu zmiennej, inicjalizacja to nadawanie zmiennej początkowej wartości podczas jej deklaracji lub później, a przypisanie to zmiana wartości zmiennej po jej zainicjowaniu. Właściwe zarządzanie zmiennymi jest kluczowe w programowaniu, aby uniknąć błędów i osiągnąć oczekiwane rezultaty w programach.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Różnica między klasą a obiektem

A

W języku Java, klasa i obiekt to dwa fundamentalne pojęcia związane z programowaniem obiektowym. Oto główne różnice między nimi:

Klasa:

Klasa to szablon lub projekt, który definiuje, jakie właściwości (pola) i zachowania (metody) powinny mieć obiekty utworzone na jej podstawie.
Klasa jest abstrakcyjnym opisem typu obiektu, opisuje, jakie cechy i zachowania mogą posiadać obiekty tej klasy.
Klasa jest jednym z fundamentów programowania obiektowego i służy do tworzenia nowych typów danych.
Obiekt:

Obiekt to konkretna instancja klasy. Oznacza to, że obiekt jest rzeczywistą reprezentacją klasy i ma określone wartości pól i stan.
Każdy obiekt jest tworzony na podstawie klasy i dziedziczy od niej właściwości i zachowania.
Obiekty są używane do przechowywania danych i wykonywania operacji zdefiniowanych w klasie.
Każdy obiekt jest niezależny od innych obiektów tej samej klasy i ma swoje własne dane i stan.
Przykład:

java
Copy code
class Person { // Klasa Person
String name; // Pole klasy
int age; // Pole klasy

void introduce() { // Metoda klasy
    System.out.println("Nazywam się " + name + " i mam " + age + " lat.");
} }

public class Main {
public static void main(String[] args) {
// Tworzenie dwóch obiektów klasy Person
Person person1 = new Person(); // Obiekt 1
Person person2 = new Person(); // Obiekt 2

    // Inicjalizacja pól obiektów
    person1.name = "John";
    person1.age = 30;
    person2.name = "Alice";
    person2.age = 25;

    // Wywoływanie metody obiektów
    person1.introduce();
    person2.introduce();
} } W powyższym przykładzie Person to klasa, która definiuje właściwości (pole name i pole age) oraz zachowanie (metodę introduce). person1 i person2 to dwa obiekty utworzone na podstawie tej klasy, które posiadają różne wartości pól i zachowują się niezależnie od siebie. Obiekt to konkretna reprezentacja klasy, a klasa to abstrakcyjny szablon, na podstawie którego tworzone są obiekty.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Co to jest constructor i do czego służy?

A

Konstruktor w języku Java to specjalna metoda wewnątrz klasy, której głównym zadaniem jest inicjalizacja obiektu tej klasy. Konstruktor ma kilka ważnych cez, w tym:

Inicjalizacja obiektu: Konstruktor jest używany do ustawienia początkowych wartości pól (zmiennych) obiektu. Dzięki konstruktorowi można zapewnić, że obiekt będzie mieć określony stan na początku swojego istnienia.

Wywoływany automatycznie: Konstruktor jest wywoływany automatycznie w momencie tworzenia nowego obiektu danej klasy. W momencie tworzenia obiektu przy użyciu słowa kluczowego new, Java automatycznie wybiera odpowiedni konstruktor do inicjalizacji obiektu.

Może być przeciążany: Klasa może mieć wiele konstruktorów o różnych zestawach parametrów, co nazywa się przeciążaniem konstruktorów. Dzięki temu programista ma możliwość tworzenia obiektów z różnymi początkowymi ustawieniami.

Nie zwraca wartości: Konstruktor nie ma zadeklarowanego typu zwracanego (nawet nie jest to void). Jest to jedna z różnic między konstruktorem a zwykłą metodą.

Przykład:

java
Copy code
public class Person {
String name;
int age;

// Konstruktor bezargumentowy (domyślny)
public Person() {
    name = "John";
    age = 30;
}

// Konstruktor z argumentami
public Person(String name, int age) {
    this.name = name;
    this.age = age;
}

public void introduce() {
    System.out.println("Nazywam się " + name + " i mam " + age + " lat.");
}

public static void main(String[] args) {
    // Tworzenie obiektów klasy Person za pomocą konstruktorów
    Person person1 = new Person();
    Person person2 = new Person("Alice", 25);

    person1.introduce(); // Wywołanie metody introduce()
    person2.introduce();
} } W powyższym przykładzie mamy dwie wersje konstruktora: jeden bezargumentowy (domyślny) i drugi przyjmujący argumenty. Konstruktory inicjalizują pola obiektów klasy Person na podstawie przekazanych wartości lub wartości domyślnych. Konstruktory umożliwiają tworzenie obiektów z określonymi danymi na początku ich istnienia.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Jak działa mechanizm garbage collection w Javie?

A

Mechanizm garbage collection (GC) w języku Java jest częścią systemu zarządzania pamięcią i jest odpowiedzialny za automatyczne usuwanie nieużywanych obiektów z pamięci w celu zwolnienia zasobów. Działanie garbage collection w Javie można opisać w kilku krokach:

Śledzenie referencji: GC śledzi wszystkie referencje do obiektów w programie. Referencje to wskaźniki do obiektów i wskazują, które obiekty są aktualnie używane przez program.

Oznaczenie nieużywanych obiektów: W regularnych odstępach czasu lub w odpowiednich momentach GC analizuje wszystkie dostępne referencje i oznacza te obiekty, do których nie można dotrzeć z aktualnych referencji. Te oznaczone obiekty są uważane za nieużywane i do usunięcia.

Usuwanie nieużywanych obiektów: Po oznaczeniu nieużywanych obiektów, GC usuwa je z pamięci. Proces ten nazywa się “zbieraniem śmieci” (garbage collection). Usunięcie nieużywanych obiektów zwalnia pamięć i przywraca ją do użytku.

Mechanizm GC w Javie zapewnia kilka zalet:

Automatyczne zarządzanie pamięcią: Programista nie musi ręcznie zwalniać pamięci po nieużywanych obiektach, co pomaga uniknąć wycieków pamięci (memory leaks).

Unikanie błędów: Usunięcie nieużywanych obiektów pozwala uniknąć błędów związanych z dostępem do pamięci, takich jak odwołania do pamięci, które zostały już zwolnione.

Wydajność: Mechanizm GC działa w sposób zoptymalizowany, co pozwala na efektywne zarządzanie pamięcią i minimalizuje wpływ na wydajność programu.

Należy jednak pamiętać, że mechanizm GC nie jest pozbawiony wad. Może wpływać na wydajność programu w niektórych sytuacjach, zwłaszcza w aplikacjach wymagających niskiego opóźnienia (low-latency) lub dużych ilości danych. Dlatego istnieją różne algorytmy GC, które można dostosować do konkretnych potrzeb aplikacji.

Warto również zaznaczyć, że programiści w Javie mają pewien wpływ na zachowanie GC poprzez zarządzanie referencjami, takimi jak referencje słabe (weak references) i referencje miękkie (soft references), oraz poprzez konfigurację parametrów GC w maszynie wirtualnej Javy (JVM).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Różnice między equals i hashcode

A

equals i hashCode to dwie metody w języku Java, które są związane z porównywaniem i hashowaniem obiektów. Oto różnice między nimi:

equals:

equals jest metodą używaną do porównywania dwóch obiektów pod kątem ich zawartości, to znaczy, czy są one “równe” z punktu widzenia ich wartości.
Możesz przesłonić metodę equals w swojej klasie, aby zdefiniować własną logikę porównywania obiektów na podstawie ich atrybutów.
Domyślna implementacja equals w klasie Object porównuje jedynie referencje do obiektów (czy są to te same obiekty w pamięci).
Jeśli przesłaniasz metodę equals, powinieneś również przesłonić metodę hashCode, aby zachować spójność - dwa obiekty, które są równe pod względem equals, powinny mieć ten sam hash code.
hashCode:

hashCode to metoda używana do generowania unikalnej liczby całkowitej, która służy jako “skrót” obiektu.
Hash code jest wykorzystywany w kolekcjach, takich jak HashSet i HashMap, aby efektywnie przechowywać i wyszukiwać obiekty.
Dobrej jakości implementacja hashCode powinna minimalizować kolizje (sytuacje, w których dwa różne obiekty mają ten sam hash code), co przyczynia się do wydajności kolekcji.
Wartość hash code jest obliczana na podstawie atrybutów obiektu, ale jest zwykle stała dla danego obiektu podczas jego życia.
Podsumowując, equals służy do porównywania zawartości obiektów, podczas gdy hashCode służy do efektywnego przechowywania i indeksowania obiektów w kolekcjach. Oba te zagadnienia są istotne w kontekście pracy z kolekcjami i porównywania obiektów w języku Java.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Różnica między FetchType a CascadeType?

A

Różnica między FetchType a CascadeType dotyczy dwóch różnych aspektów mapowania obiektowo-relacyjnego w kontekście technologii ORM (Object-Relational Mapping), takich jak Hibernate czy Java Persistence API (JPA). Oto omówienie tych dwóch pojęć:

FetchType:

FetchType odnosi się do sposobu, w jaki dane związane z daną encją są pobierane z bazy danych w momencie odwołania się do tych danych.
Domyślnie, dla pól, które reprezentują relacje @ManyToOne, @OneToOne lub @OneToMany, wartość FetchType to EAGER. Oznacza to, że dane te są automatycznie pobierane z bazy danych razem z obiektem nadrzędnym.
Jeśli ustawisz FetchType na LAZY, dane te zostaną pobrane dopiero wtedy, gdy zostaniesz odwołasz się do powiązanego obiektu lub kolekcji. To pozwala na leniwe ładowanie i może poprawić wydajność, szczególnie gdy masz wiele relacji i nie zawsze potrzebujesz pobierać wszystkie dane.
CascadeType:

CascadeType odnosi się do propagacji operacji z obiektu nadrzędnego na związane obiekty w kontekście cyklu życia obiektów.
Na przykład, ustawienie CascadeType.PERSIST oznacza, że operacja persist() (czyli zapis nowego obiektu) na obiekcie nadrzędnym spowoduje, że ta operacja zostanie również wywołana na wszystkich związanych obiektach, które są oznaczone jako CascadeType.PERSIST.
CascadeType pomaga w zarządzaniu cyklem życia obiektów w kontekście ORM. Ułatwia to zapisywanie, usuwanie i aktualizowanie obiektów w spójny sposób.
Podsumowując, FetchType dotyczy sposobu pobierania danych z bazy danych w momencie dostępu do związanych obiektów, podczas gdy CascadeType dotyczy propagacji operacji na obiekcie nadrzędnym na jego związane obiekty w kontekście cyklu życia obiektów. Oba te mechanizmy są ważne w kontekście technologii ORM i wpływają na wydajność oraz zachowanie operacji na danych.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Jak działa Hashmapa

A

HashMapa to struktura danych w języku Java, która implementuje interfejs Map i jest używana do przechowywania danych w formie par klucz-wartość. Działa na zasadzie tablicy skrótów (hash table) i zapewnia efektywne przeszukiwanie, wstawianie i usuwanie elementów. Oto jak dokładnie działa HashMapa:

Tworzenie HashMapy: Można utworzyć nową HashMapę, podając typ klucza i wartości, na przykórej chcemy ją zastosować. Na przykład:

java
Copy code
Map<String, Integer> hashMap = new HashMap<>();
Wstawianie elementów: Aby wstawić element do HashMapy, używamy metody put(key, value), gdzie key jest kluczem, a value jest wartością. Klucz musi być unikalny w obrębie HashMapy. Przykład:

java
Copy code
hashMap.put(“apple”, 5);
hashMap.put(“banana”, 3);
Pobieranie elementów: Możemy pobrać wartość na podstawie klucza za pomocą metody get(key). Jeśli klucz istnieje, zostanie zwrócona jego wartość. Przykład:

java
Copy code
int appleCount = hashMap.get(“apple”); // Zwróci 5
Usunięcie elementu: Aby usunąć element, używamy metody remove(key). Przykład:

java
Copy code
hashMap.remove(“apple”);
Iterowanie po HashMapie: Możemy iterować po elementach HashMapy za pomocą pętli for-each lub innych metod dostępnych w Java. Na przykład:

java
Copy code
for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
String key = entry.getKey();
int value = entry.getValue();
System.out.println(key + “: “ + value);
}
Podstawowa zasada działania: HashMapa przechowuje elementy w tablicy skrótów, gdzie indeksy w tablicy są obliczane na podstawie skrótu (hash code) klucza. Wartości są przechowywane pod odpowiednimi indeksami. W przypadku kolizji, tj. gdy dwa różne klucze mają ten sam skrót, używana jest lista lub drzewo do przechowywania elementów.

Wybór odpowiedniego rozmiaru: Rozmiar wewnętrzej tablicy skrótów jest ważny dla wydajności HashMapy. Zbyt mała tablica może prowadzić do kolizji, a zbyt duża tablica do straty pamięci. W praktyce zazwyczaj nie jest to problem, ponieważ HashMapa dostosowuje swój rozmiar automatycznie w miarę dodawania i usuwania elementów.

HashMapa jest jedną z najczęściej używanych struktur danych w języku Java do szybkiego wyszukiwania i przechowywania danych w formie par klucz-wartość. Jeśli potrzebujesz trzymać elementy w określonej kolejności, zamiast HashMapy możesz użyć LinkedHashMap lub TreeMap, które utrzymują porządek elementów.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Optional w springu

A

Optional w Springu to typ pochodzący z języka Java, który jest często wykorzystywany w kontekście programowania reaktywnego i obsługi błędów. Spring Framework obsługuje Optional w różnych częściach swojej infrastruktury, a także zachęca do jego stosowania w niektórych przypadkach.

Oto kilka zastosowań Optional w Springu:

Obsługa wyników metod serwisów: W serwisach Springa często zwracane są wyniki operacji, na przykład rezultat wyszukiwania w bazie danych. Można użyć Optional do opakowania wyniku, aby określić, że wynik może być pusty. Przykład:

java
Copy code
public Optional<User> findUserById(Long userId) {
// Logika wyszukiwania użytkownika
}
W przypadku braku użytkownika, możesz zwrócić Optional.empty(), a w przypadku znalezienia użytkownika - Optional.of(user).</User>

Obsługa wyników kontrolerów: Kontrolery Spring MVC lub Spring WebFlux mogą zwracać Optional w wyniku swoich akcji. Dzięki temu klient może łatwo sprawdzić, czy zasób istnieje. Przykład w kontrolerze Spring MVC:

java
Copy code
@GetMapping(“/user/{id}”)
public ResponseEntity<Optional<User>> getUserById(@PathVariable Long id) {
Optional<User> user = userService.findUserById(id);
return ResponseEntity.ok(user);
}
Manipulacje wartościami opcjonalnymi: Spring Framework dostarcza szereg narzędzi do pracy z Optional, takie jak ifPresent, orElse, orElseGet, itp., które pozwalają na wygodne operacje na wartościach opcjonalnych. Na przykład:</User></User>

java
Copy code
Optional<User> user = userService.findUserById(id);
user.ifPresent(u -> {
// Wykonywanie operacji na obiekcie użytkownika, jeśli istnieje
});
Obsługa błędów w strumieniach reaktywnych: W programowaniu reaktywnym, Optional jest używane do obsługi przypadków, gdy reaktywny strumień może nie zawierać wartości. Możesz użyć operatora defaultIfEmpty w Mono lub Flux, aby określić wartość domyślną, jeśli strumień jest pusty. Przykład w Spring WebFlux:</User>

java
Copy code
userService.findUserById(id)
.defaultIfEmpty(User.getDefaultUser())
.subscribe(user -> {
// Obsługa użytkownika lub domyślnego użytkownika
});
Optional w Springu jest często używane jako narzędzie do obsługi opcjonalnych wartości lub braku wyników w bardziej elegancki sposób niż sprawdzanie wartości na null. Pomaga to unikać błędów NPE (NullPointerException) i zwiększa czytelność kodu. Jednak zawsze warto dobrze przemyśleć, gdzie Optional jest odpowiednie, a gdzie lepiej stosować tradycyjne warunki if, w zależności od konkretnego przypadku użycia.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Controller a RestController

A

Czym różni się Controller od Rest ControlleraW środowisku programowania w języku Java, w ramach frameworka Spring, Controller i RestController to dwie różne adnotacje używane w tworzeniu aplikacji internetowych. Oto główne różnice między nimi:

Controller:

@Controller jest adnotacją używaną do oznaczania klas, które pełnią rolę kontrolerów w aplikacji webowej.
Kontrolery oznaczone adnotacją @Controller obsługują żądania HTTP i generują odpowiedzi HTML, co oznacza, że są używane w tradycyjnych aplikacjach internetowych opartych na modelu widok-kontroler (MVC - Model-View-Controller).
Standardowe metody w kontrolerach mogą zwracać widoki HTML, które są generowane na serwerze i przesyłane do klienta, co umożliwia renderowanie treści na stronie internetowej.
RestController:

@RestController to specjalizowana wersja kontrolera w Springu, która jest używana do tworzenia tzw. RESTful API (API, które działa w oparciu o standardy REST - Representational State Transfer).
Kontrolery oznaczone adnotacją @RestController obsługują żądania HTTP i generują odpowiedzi w formacie JSON lub XML. Odpowiedzi te są zwykle przetwarzane przez aplikacje klienckie, takie jak aplikacje internetowe, aplikacje mobilne itp.
Standardowe metody w kontrolerach @RestController zazwyczaj zwracają dane bezpośrednio, a te dane są serializowane do formatu JSON lub XML i przesyłane jako treść odpowiedzi HTTP.
Podsumowując, główną różnicą między Controller a RestController jest sposób generowania odpowiedzi. @Controller generuje odpowiedzi HTML, które są przeznaczone do wyświetlenia w przeglądarkach internetowych, podczas gdy @RestController generuje odpowiedzi w formacie danych (zwykle JSON lub XML), które są przeznaczone do komunikacji między aplikacjami. Wybór między tymi dwiema adnotacjami zależy od rodzaju aplikacji, którą tworzysz i jakie rodzaje odpowiedzi musisz obsłużyć.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Dependency injection

A

Dependency Injection (DI) to technika używana w programowaniu obiektowym, która polega na dostarczaniu zależności (innych obiektów lub komponentów) do klasy lub obiektu, zamiast pozwalania im na tworzenie tych zależności samodzielnie. Wstrzykiwanie zależności ma na celu rozluźnienie powiązań między komponentami, zwiększenie modularności i ułatwienie testowania kodu. Jest to jedna z ważnych koncepcji stosowanych w kontekście projektowania oprogramowania i zarządzania cyklem życia obiektów.

Główne zalety Dependency Injection to:

Rozluźnienie powiązań: Wstrzykiwanie zależności pomaga w rozluźnieniu silnych powiązań między komponentami, co czyni kod bardziej elastycznym i łatwiejszym do modyfikacji. Komponenty nie muszą wiedzieć, jakie konkretne obiekty są używane jako ich zależności.

Testowanie: Wstrzykiwanie zależności ułatwia testowanie komponentów, ponieważ zależności mogą być zastępowane atrapami lub innymi zależnościami dostosowanymi do potrzeb testów jednostkowych.

Zarządzanie cyklem życia: Przy użyciu DI można kontrolować cykl życia obiektów (np. zarządzanie dostępem do baz danych, połączeniami sieciowymi) i zapewnić, że obiekty są tworzone i niszczone w odpowiednich momentach.

Istnieje wiele różnych mechanizmów wstrzykiwania zależności, takie jak:

Wstrzykiwanie przez konstruktor (Constructor Injection): Zależności są przekazywane poprzez konstruktor klasy.
Wstrzykiwanie przez metodę ustawiającą (Setter Injection): Zależności są ustawiane za pomocą specjalnych setterów.
Wstrzykiwanie przez pole (Field Injection): Zależności są ustawiane poprzez bezpośrednie przypisanie ich do pól klasy.
Wstrzykiwanie przez kontekst (Contextual Injection): Zależności są dostarczane na podstawie kontekstu aplikacji (np. korzystając z kontenera wstrzykiwania zależności, takiego jak Spring Framework).
Przykład wstrzykiwania zależności w Javie z wykorzystaniem Spring Framework poprzez konstruktor:

java
Copy code
public class OrderService {
private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
    this.orderRepository = orderRepository;
}

// Metody serwisu korzystają z orderRepository } W tym przykładzie OrderService przyjmuje OrderRepository jako zależność poprzez konstruktor, co oznacza, że zależność zostanie wstrzyknięta, gdy obiekt OrderService zostanie utworzony.
19
Q

Co to są enumy i podaj przykłady

A

W języku Java, enum to specjalny rodzaj typu, który reprezentuje zbiór stałych. Enumy są używane do zdefiniowania zestawu nazwanych wartości, co może uczynić kod bardziej czytelnym i bezpiecznym. Oto przykłady enumów w Javie:

Prosty Enum:
java
Copy code
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
Enum z Wartościami:
java
Copy code
public enum Season {
SPRING(“Mild”),
SUMMER(“Hot”),
AUTUMN(“Cool”),
WINTER(“Cold”);

private final String description;

Season(String description) {
    this.description = description;
}

public String getDescription() {
    return description;
} } Enum z Metodami: java Copy code public enum Operation {
ADD {
    public int apply(int x, int y) {
        return x + y;
    }
},
SUBTRACT {
    public int apply(int x, int y) {
        return x - y;
    }
},
MULTIPLY {
    public int apply(int x, int y) {
        return x * y;
    }
},
DIVIDE {
    public int apply(int x, int y) {
        return x / y;
    }
};

public abstract int apply(int x, int y); } W przykładzie 2, Season jest enumem z dodatkowym polem (description) i metodą (getDescription). Enumy pozwalają na definiowanie bardziej skomplikowanych struktur danych niż po prostu zestaw stałych.

Enumy są przydatne w wielu sytuacjach, szczególnie tam, gdzie potrzebujesz zdefiniować stały i ograniczony zestaw wartości.

20
Q

Response Entity

A

ResponseEntity w Spring Framework to klasa reprezentująca pełną odpowiedź HTTP do klienta. Umożliwia kontrolę różnych aspektów odpowiedzi, takich jak kod stanu HTTP, nagłówki i ciało odpowiedzi. Jest powszechnie używana w kontekście budowania usług sieciowych (np. RESTful) w aplikacjach opartych na Spring.

Oto kilka kluczowych cech ResponseEntity:

Kod Stanu HTTP: Możesz określić kod stanu HTTP, który zostanie zwrócony w odpowiedzi. Na przykład:

java
Copy code
return new ResponseEntity<>(“Hello World”, HttpStatus.OK);
W tym przypadku, HttpStatus.OK oznacza kod stanu 200 (OK).

Nagłówki HTTP: Możesz dodać niestandardowe nagłówki do odpowiedzi. Na przykład:

java
Copy code
HttpHeaders headers = new HttpHeaders();
headers.add(“Custom-Header”, “header-value”);

return new ResponseEntity<>(“Hello World”, headers, HttpStatus.OK);
Ciało Odpowiedzi: Możesz ustawić ciało odpowiedzi, czyli dane, które zostaną wysłane do klienta. Na przykład:

java
Copy code
return new ResponseEntity<>(“Hello World”, HttpStatus.OK);
Obsługa Błędów: ResponseEntity umożliwia również obsługę błędów, zwracając odpowiedni kod stanu HTTP. Na przykład:

java
Copy code
return new ResponseEntity<>(“Error occurred”, HttpStatus.INTERNAL_SERVER_ERROR);
Użycie ResponseEntity daje dużą elastyczność w dostosowywaniu odpowiedzi HTTP w zależności od konkretnej sytuacji. Jest szeroko stosowana w kontrolerach Spring MVC oraz w warstwach serwisu w aplikacjach opartych na Spring Boot.

21
Q

Dto, przykłady

A

DTO, czyli Data Transfer Object, to obiekt służący do przesyłania danych między warstwami aplikacji lub pomiędzy aplikacjami w architekturze oprogramowania. DTO jest często używane w kontekście warstwy prezentacji (np. w aplikacjach webowych) do przekazywania danych z warstwy usług (serwisów) do warstwy interfejsu użytkownika.

Przykład ProductDTO może wyglądać tak:

java
Copy code
public class ProductDTO {
private Long id;
private String name;
private BigDecimal price;
private String category; // Kategoria produktu jako tekst, np. “ELEKTRONIKA”

// Konstruktory, gettery i settery } W tym przypadku ProductDTO zawiera tylko te informacje o produkcie, które są potrzebne w warstwie prezentacji. Dla przykładu, zamiast przesyłać pełen obiekt Product z wszystkimi polami, można użyć ProductDTO, aby przekazać tylko niektóre informacje, na przykład identyfikator, nazwę, cenę i kategorię produktu.

Przykładowe użycie w warstwie kontrolera:

java
Copy code
@RestController
@RequestMapping(“/api/products”)
public class ProductController {

@Autowired
private ProductService productService;

@GetMapping("/{productId}")
public ResponseEntity<ProductDTO> getProductById(@PathVariable Long productId) {
    Product product = productService.getProductById(productId);
    
    // Mapowanie obiektu Product na ProductDTO
    ProductDTO productDTO = mapToProductDTO(product);
    
    return new ResponseEntity<>(productDTO, HttpStatus.OK);
}

private ProductDTO mapToProductDTO(Product product) {
    ProductDTO productDTO = new ProductDTO();
    productDTO.setId(product.getId());
    productDTO.setName(product.getName());
    productDTO.setPrice(product.getPrice());
    productDTO.setCategory(product.getCategory().name());  // Mapowanie kategorii jako tekst

    return productDTO;
} } W powyższym przykładzie, ProductController obsługuje żądania dotyczące produktów i zwraca obiekty ProductDTO zamiast pełnych obiektów Product.
22
Q

Optional

A

Optional to klasa w języku Java wprowadzona w Java 8, która reprezentuje potencjalnie pusty (null) lub obecny obiekt. Głównym celem Optional jest zastąpienie użycia wartości null, co może prowadzić do błędów związanych z odwoływaniem się do null oraz ułatwienie obsługi przypadków, w których wartość może być nieobecna.

Przykład użycia Optional:

java
Copy code
import java.util.Optional;

public class OptionalExample {
public static void main(String[] args) {
// Tworzenie Optional z obecnej wartości
Optional<String> nonEmptyOptional = Optional.of("Hello, World!");</String>

    // Tworzenie pustego Optional
    Optional<String> emptyOptional = Optional.empty();

    // Tworzenie Optional z możliwie null wartości
    String nullableValue = "Hello, Java!";
    Optional<String> nullableOptional = Optional.ofNullable(nullableValue);

    // Sprawdzanie, czy Optional zawiera wartość
    System.out.println(nonEmptyOptional.isPresent()); // true
    System.out.println(emptyOptional.isPresent()); // false

    // Pobieranie wartości z Optional (jeśli obecna)
    String value = nonEmptyOptional.get();
    System.out.println(value); // Hello, World!

    // Wykonywanie operacji w przypadku obecnej wartości
    nonEmptyOptional.ifPresent(val -> System.out.println("Value is present: " + val));

    // Pobieranie wartości lub domyślnej wartości (jeśli nieobecna)
    String result = emptyOptional.orElse("Default Value");
    System.out.println(result); // Default Value

    // Pobieranie wartości lub wykonanie dostawcy (Supplier) w przypadku jej braku
    String resultSupplier = emptyOptional.orElseGet(() -> "Default Value from Supplier");
    System.out.println(resultSupplier); // Default Value from Supplier

    // Rzucanie wyjątku w przypadku braku wartości
    try {
        String resultOrElseThrow = emptyOptional.orElseThrow(() -> new IllegalStateException("Value is not present"));
    } catch (IllegalStateException e) {
        System.out.println(e.getMessage()); // Value is not present
    }
} } W powyższym przykładzie, Optional jest używane do bezpiecznego obsługiwania przypadków, w których wartość może być null, oraz do wykonania operacji w zależności od obecności wartości. Jest to szczególnie przydatne w przypadkach, gdzie null może prowadzić do błędów wykonania.
23
Q

Kody requestów

A

Kody odpowiedzi HTTP, które są przesyłane w nagłówkach odpowiedzi HTTP, informują klienta o rezultacie jego żądania. Poniżej znajdziesz kilka przykładowych kodów odpowiedzi HTTP:

2xx (Success - Sukces): Oznacza, że żądanie zostało pomyślnie przetworzone.

200 OK: Standardowy kod odpowiedzi dla udanych żądań HTTP.
201 Created: Używany, gdy zasób został pomyślnie utworzony (np. po wysłaniu formularza).
3xx (Redirection - Przekierowanie): Informuje klienta, że powinien podjąć dodatkowe kroki w celu ukończenia żądania.

301 Moved Permanently: Zasób został przeniesiony na nowe miejsce na stałe.
302 Found (or Moved Temporarily): Zasób został przeniesiony tymczasowo.
4xx (Client Error - Błąd klienta): Oznacza błąd ze strony klienta. Klient powinien przemyśleć żądanie przed ponowną próbą.

400 Bad Request: Klient wysłał nieprawidłowe żądanie.
401 Unauthorized: Klient nie jest uwierzytelniony i potrzebuje zalogować się.
403 Forbidden: Klient jest uwierzytelniony, ale nie ma dostępu do zasobu.
404 Not Found: Zasób nie został odnaleziony.
5xx (Server Error - Błąd serwera): Oznacza, że błąd wystąpił po stronie serwera.

500 Internal Server Error: Ogólny błąd serwera, który nie został obsłużony.
502 Bad Gateway: Serwer działa jako brama, otrzymał nieprawidłową odpowiedź od upstram (zwyczajowo innego serwera) serwera.
503 Service Unavailable: Serwer nie jest gotów obsługiwać żądań. Najczęściej występuje w trakcie prac konserwacyjnych.
To tylko kilka przykładów. Pełna lista kodów odpowiedzi HTTP znajduje się w specyfikacji HTTP (RFC 7231).

24
Q

Różnice między FetchType a FetchMode

A

FetchType i FetchMode to dwa różne pojęcia związane z ładowaniem danych w kontekście ORM (Object-Relational Mapping) i relacyjnych baz danych. Oto krótkie omówienie różnic między nimi:

FetchType:

Definicja: FetchType jest pojęciem związanym z JPA (Java Persistence API), które definiuje, jak dane powiązane z encją są ładowane z bazy danych.
Rodzaje:
FetchType.LAZY: Dane są ładowane leniwie, czyli w momencie, gdy są potrzebne. Na przykład, gdy dostęp do danej właściwości zostanie wywołany po pierwszy raz.
FetchType.EAGER: Dane są ładowane natychmiast, razem z załadunkiem samej encji. To oznacza, że ​​wszystkie dane związkowe są pobierane od razu.
Użycie: Określa się go na poziomie relacji encji, na przykład w adnotacji @OneToMany lub @ManyToOne.
java
Copy code
@OneToMany(mappedBy = “category”, cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
private Set<Product> products;
FetchMode:</Product>

Definicja: FetchMode jest pojęciem związanym z biblioteką Hibernate, która jest jedną z implementacji JPA. Jest używane w konkretnych sytuacjach, gdzie chcemy dostosować sposób ładowania danych dla zapytań HQL (Hibernate Query Language) lub kryteriów Hibernate.
Rodzaje:
FetchMode.SELECT: Własność związku jest ładowana oddzielnie, używając osobnego zapytania SQL. To jest domyślne zachowanie.
FetchMode.JOIN: Własność związku jest ładowana przez złączenie (JOIN) w jednym zapytaniu SQL. Może prowadzić do pobierania większej ilości danych niż potrzeba.
Użycie: Występuje w kontekście zapytań HQL lub kryteriów Hibernate.
java
Copy code
// Przykład użycia w zapytaniu HQL
String hql = “SELECT c FROM Category c LEFT JOIN FETCH c.products WHERE c.id = :categoryId”;
Category category = (Category) session.createQuery(hql)
.setParameter(“categoryId”, categoryId)
.uniqueResult();
Podsumowując, FetchType jest ogólnym pojęciem związanym z JPA, używanym do określenia, jak dane związane z encją są ładowane, podczas gdy FetchMode jest specyficznym dla Hibernate pojęciem, które umożliwia dostosowanie ładowania danych dla konkretnych zapytań.

25
Q

@Transactional

A

@Transactional to adnotacja w kontekście Spring Framework, która wskazuje, że metoda, do której jest przypisana, powinna być wykonywana w transakcji. Transakcje są używane do zapewnienia spójności danych w systemach bazodanowych. Oto kilka kluczowych punktów dotyczących adnotacji @Transactional:

Zastosowanie adnotacji:

@Transactional może być stosowane zarówno do metod publicznych klasy, jak i do klas jako całości (nad klasą). W przypadku klasy, adnotacja jest dziedziczona przez wszystkie publiczne metody klasy.
Adnotacja może być również używana na poziomie interfejsu.
Obsługiwane operacje:

Adnotacja może obejmować różne rodzaje operacji bazodanowych, takie jak odczyt (SELECT), zapis (INSERT lub UPDATE), a także operacje na wielu encjach.
Parametry adnotacji:

@Transactional obsługuje różne parametry, które pozwalają dostosować zachowanie transakcji, na przykład readOnly, timeout, isolation, itp.
java
Copy code
@Transactional(readOnly = true, timeout = 30, isolation = Isolation.READ_COMMITTED)
public void performTransactionalOperation() {
// Logika operacji bazodanowej
}
Zarządzanie transakcjami:
Spring zarządza transakcjami na poziomie metod, co oznacza, że ​​jeżeli metoda z adnotacją @Transactional zostanie wywołana, a transakcja nie została jeszcze utworzona, Spring utworzy nową transakcję. Jeśli już istnieje transakcja, metoda dołączy się do bieżącej transakcji.
java
Copy code
@Service
public class MyService {

@Transactional
public void myTransactionalMethod() {
    // Logika operacji bazodanowej
} } Rozwijanie transakcji: W przypadku korzystania z wielu metod, adnotacja @Transactional może również obejmować więcej niż jedną metodę, a Spring będzie rozwijał transakcję do momentu, gdy najwyższy poziom metody zostanie zakończony (jeśli nie zostanie utworzona nowa transakcja). java Copy code @Transactional public void myTopLevelMethod() {
// Logika operacji bazodanowej
myTransactionalMethod(); } Rzucony wyjątek i transakcja: Jeżeli metoda z adnotacją @Transactional rzuca wyjątek, transakcja domyślnie zostanie oznaczona do rollbacku, chyba że wyjątek jest oznaczony adnotacją @Transactional z parametrem noRollbackFor lub rollbackFor. java Copy code @Transactional(rollbackFor = CustomException.class) public void myTransactionalMethod() throws CustomException {
// Logika operacji bazodanowej } Warto pamiętać, że @Transactional jest potężnym narzędziem, ale jego niewłaściwe użycie może prowadzić do problemów związanych z wydajnością i spójnością danych. Ważne jest zrozumienie, kiedy i jak go używać w zależności od wymagań aplikacji.
26
Q

@PersistentContext

A

@PersistenceContext to adnotacja w kontekście Java Persistence API (JPA) i Spring, która jest używana do wskazania, że pole powinno być wstrzykiwane przez menedżera encji (EntityManager). @PersistenceContext jest często używane w klasach zarządzanych przez kontener Spring, takich jak serwisy, repozytoria, lub kontrolery.

Oto kilka kluczowych punktów dotyczących @PersistenceContext:

Wstrzykiwanie EntityManagera:
@PersistenceContext jest używane do wstrzykiwania obiektu EntityManager do pola klasy. EntityManager jest często używany do wykonywania operacji bazodanowych na encjach JPA.
java
Copy code
@Service
public class MyService {

@PersistenceContext
private EntityManager entityManager;

public void myMethod() {
    // Użycie entityManager do operacji bazodanowych
} } Zasięg obiektu: @PersistenceContext definiuje zasięg obiektu EntityManager. Domyślnie, zasięg jest ustawiony na Transaction, co oznacza, że dla każdej transakcji będzie tworzony nowy EntityManager. Można to dostosować za pomocą atrybutów unitName lub type. java Copy code @PersistenceContext(unitName = "myPersistenceUnit") private EntityManager entityManager; Wielkość obiektu EntityManager: @PersistenceContext umożliwia również kontrolowanie wielkości (rozmiaru) puli EntityManager. Działa to wtedy, gdy aplikacja jest skalowana i chcemy, aby różne egzemplarze klasy miały dostęp do różnych instancji EntityManager. java Copy code @PersistenceContext(unitName = "myPersistenceUnit", type = PersistenceContextType.EXTENDED) private EntityManager entityManager; Adnotacja dla pól, setterów lub konstruktorów: @PersistenceContext może być stosowane do pól klasy, setterów lub konstruktorów. W przypadku pól, EntityManager jest wstrzykiwane po utworzeniu instancji klasy. W przypadku setterów i konstruktorów, wstrzykiwanie może nastąpić podczas tworzenia obiektu. java Copy code @Service public class MyService {

private EntityManager entityManager;

@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
} } Wstrzykiwanie EntityManager za pomocą @PersistenceContext jest jednym ze sposobów integracji Springa z JPA. Pozwala to na korzystanie z mechanizmów zarządzania transakcjami i sesjami dostarczanych przez JPA, jednocześnie korzystając z wygodnych funkcji Springa, takich jak zarządzanie ziarnami i wstrzykiwanie zależności.
27
Q

@EntityMenager

A

EntityManager jest częścią Java Persistence API (JPA) i pełni rolę menedżera encji w kontekście zarządzania obiektami encji (reprezentującymi dane w bazie danych) i operacjami bazodanowymi. Jest to interfejs dostarczony przez JPA do zarządzania cyklem życia obiektów encji, a także do wykonywania operacji takich jak zapisywanie, usuwanie, odpytywanie i aktualizowanie danych w bazie.

W skrócie, EntityManager pozwala aplikacji Java na współpracę z bazą danych przy użyciu obiektów encji, co umożliwia programistom pracę na poziomie obiektów w miejscu korzystania z czystego SQL.

28
Q

Co to jest rollback

A

Rollback odnosi się do operacji anulowania (cofniecia) transakcji. W kontekście baz danych i transakcji, rollback oznacza, że wszelkie zmiany wprowadzone w bazie danych podczas trwania transakcji są cofane, a stan bazy danych wraca do tego, który był przed rozpoczęciem transakcji. To zapewnia spójność danych i unika sytuacji, w której pewne operacje zostaną zatwierdzone, a inne nie, co mogłoby prowadzić do nieprzewidywalnych stanów.

Jeśli transakcja zakończyła się sukcesem, to znaczy, że wszystkie operacje zostały zatwierdzone, a zmiany są trwałe. W przypadku wystąpienia błędu lub innego problemu w trakcie trwania transakcji, może zostać wywołane rollback, aby cofnąć wszelkie zmiany wprowadzone w ramach danej transakcji.

W kontekście frameworków i technologii, takich jak Spring czy Java EE, możesz używać adnotacji @Transactional i mechanizmów zarządzania transakcjami, które automatycznie obsługują commit i rollback w zależności od rezultatu transakcji.

29
Q

@Builder

A

@Builder to adnotacja z biblioteki Lombok w języku Java. Lombok jest narzędziem, które pomaga w redukcji nadmiaru kodu w klasach Java poprzez generowanie automatyczne getterów, setterów, konstruktorów, metod toString(), equals(), hashCode() i innych.

Adnotacja @Builder generuje wzorzec projektowy Builder, który umożliwia konstrukcję obiektu z wieloma polami w sposób bardziej czytelny i łatwy do zrozumienia. Dzięki temu, zamiast używać wielu konstruktorów z różnymi zestawami argumentów, można użyć wzorca Builder do stopniowego dodawania kolejnych pól do obiektu.

Przykład użycia @Builder:

java
Copy code
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Product {
private Long id;
private String name;
private String description;
private double price;
private int quantity;
}
Użycie tej adnotacji pozwala na stworzenie obiektu klasy Product w sposób bardziej zwięzły i intuicyjny:

java
Copy code
Product product = Product.builder()
.id(1L)
.name(“Laptop”)
.description(“Powerful laptop with high-resolution display”)
.price(1299.99)
.quantity(10)
.build();
Warto zauważyć, że kod powyżej jest bardziej zwięzły niż konstrukcja obiektu za pomocą tradycyjnych konstruktorów z wieloma argumentami.

30
Q

Relacja one to many

A

Relacja “one-to-many” (jeden do wielu) to jeden z rodzajów relacji między encjami w kontekście baz danych. W kontekście JPA (Java Persistence API) i relacyjnych baz danych, taka relacja oznacza, że jedna encja (obiekt) związana jest z kolekcją innych encji.

Na przykład, rozważmy dwie encje: Author (Autor) i Book (Książka). Jednemu autorowi może przypisywać się wiele książek, co jest przykładem relacji “one-to-many”. Poniżej znajduje się przykładowy kod Java, który ilustruje taką relację za pomocą JPA:

java
Copy code
@Entity
public class Author {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
private List<Book> books;

// getters, setters, konstruktory }

@Entity
public class Book {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String title;

@ManyToOne
@JoinColumn(name = "author_id")
private Author author;

// getters, setters, konstruktory } W tym przykładzie:

Klasa Author reprezentuje autora i ma pole books, które jest kolekcją książek napisanych przez tego autora. Adnotacja @OneToMany oznacza, że jest to relacja jeden do wielu. Parametr mappedBy = “author” wskazuje, że to pole jest mapowane przez pole author w klasie Book.

Klasa Book reprezentuje książkę i ma pole author, które jest odniesieniem do autora tej książki. Adnotacja @ManyToOne oznacza, że jest to relacja wielu do jednego. Parametr @JoinColumn(name = “author_id”) wskazuje, które pole w tabeli bazy danych będzie przechowywało klucz obcy (ID autora).

Dzięki temu, korzystając z JPA, możemy łatwo pobierać i zapisywać dane w relacji “one-to-many” pomiędzy autorami a ich książkami.

31
Q

many to many

A

Relacja “many-to-many” (wiele do wielu) to rodzaj relacji między encjami, w której jedna encja może być powiązana z wieloma innymi encjami, a jedna encja może być powiązana z wieloma encjami. W kontekście JPA (Java Persistence API) i baz danych, taka relacja jest zazwyczaj reprezentowana za pomocą tabeli łączącej (join table), która przechowuje pary kluczy obcych związane z obiema encjami.

Przykładowo, rozważmy dwie encje: Student (Student) i Course (Kurs). Jeden student może uczestniczyć w wielu kursach, a jeden kurs może mieć wielu studentów. Oto jak można zaimplementować relację “many-to-many” za pomocą JPA:

java
Copy code
@Entity
public class Student {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@ManyToMany
@JoinTable(
    name = "student_course",
    joinColumns = @JoinColumn(name = "student_id"),
    inverseJoinColumns = @JoinColumn(name = "course_id"))
private Set<Course> courses;

// getters, setters, konstruktory }

@Entity
public class Course {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String title;

@ManyToMany(mappedBy = "courses")
private Set<Student> students;

// getters, setters, konstruktory } W tym przykładzie:

Klasa Student ma pole courses, które jest kolekcją kursów, w których uczestniczy student. Adnotacja @ManyToMany oznacza, że jest to relacja “many-to-many”. Adnotacja @JoinTable pozwala zdefiniować nazwę tabeli łączącej oraz kolumny klucza obcego dla obu encji.

Klasa Course ma pole students, które jest kolekcją studentów biorących udział w danym kursie. Adnotacja @ManyToMany(mappedBy = “courses”) wskazuje, że to pole jest mapowane przez pole courses w klasie Student.

Dzięki takiemu podejściu, JPA automatycznie zarządza tabelą łączącą i umożliwia łatwe pobieranie i zapisywanie danych w relacji “many-to-many”.

32
Q

many to one

A

Relacja “many-to-one” (wiele do jeden) to rodzaj relacji między encjami, w której wiele instancji jednej encji może być powiązane z jedną instancją innej encji. W kontekście JPA (Java Persistence API) i baz danych, taka relacja jest zazwyczaj reprezentowana za pomocą klucza obcego w encji “wiele” wskazującym na encję “jeden”.

Przykładowo, rozważmy dwie encje: Book (Książka) i Author (Autor). Wiele książek może być napisanych przez jednego autora, ale jeden autor może być powiązany z wieloma książkami. Oto jak można zaimplementować relację “many-to-one” za pomocą JPA:

java
Copy code
@Entity
public class Book {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String title;

@ManyToOne
@JoinColumn(name = "author_id")
private Author author;

// inne pola, getters, setters, konstruktory }

@Entity
public class Author {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@OneToMany(mappedBy = "author")
private List<Book> books;

// inne pola, getters, setters, konstruktory } W tym przykładzie:

Klasa Book ma pole author, które reprezentuje autora książki. Adnotacja @ManyToOne oznacza, że jest to relacja “many-to-one”. Adnotacja @JoinColumn pozwala zdefiniować nazwę kolumny klucza obcego w tabeli książek.

Klasa Author ma pole books, które reprezentuje listę książek napisanych przez danego autora. Adnotacja @OneToMany(mappedBy = “author”) wskazuje, że to pole jest mapowane przez pole author w klasie Book.

Dzięki temu, możemy łatwo uzyskiwać dostęp do informacji o autorze dla danej książki i vice versa. JPA zarządza automatycznie kluczami obcymi i umożliwia operacje CRUD (Create, Read, Update, Delete) na powiązanych encjach.

33
Q

Co to jest SET, rodzaje setów?

A

W programowaniu, Set to kolekcja, która przechowuje unikalne elementy, czyli elementy, które nie mogą się powtarzać. W Javie, interfejs Set jest częścią frameworka kolekcji i jest implementowany przez różne klasy, z których najczęściej używaną jest HashSet.

Rodzaje setów w Javie:

HashSet: Implementacja Set oparta na hashtable. Nie gwarantuje ona zachowania kolejności elementów, a także nie dopuszcza duplikatów.

java
Copy code
Set<String> hashSet = new HashSet<>();
LinkedHashSet: Implementacja Set rozszerzająca HashSet, ale dodatkowo przechowująca porządek wstawiania elementów. Zapewnia iterację w kolejności, w jakiej elementy zostały dodane.</String>

java
Copy code
Set<String> linkedHashSet = new LinkedHashSet<>();
TreeSet: Implementacja Set, która przechowuje elementy w porządku naturalnym (lub określonym przez komparator). Zapewnia efektywne dodawanie, usuwanie i sprawdzanie czy element istnieje, ale ma wyższą złożoność czasową niż HashSet.</String>

java
Copy code
Set<String> treeSet = new TreeSet<>();
EnumSet: Specjalna implementacja Set zoptymalizowana do przechowywania elementów typu enum. Jest bardzo wydajna i zajmuje mniej miejsca w porównaniu do innych implementacji.</String>

java
Copy code
EnumSet<DayOfWeek> daysOfWeek = EnumSet.allOf(DayOfWeek.class);
CopyOnWriteArraySet: Implementacja Set zapewniająca bezpieczny dostęp wielu wątków poprzez kopiowanie kolekcji przy każdej modyfikacji. Jest przydatna, gdy odczyty są znacznie bardziej powszechne niż zapisy.</DayOfWeek>

java
Copy code
Set<String> copyOnWriteArraySet = new CopyOnWriteArraySet<>();
Wybór odpowiedniego Set zależy od wymagań dotyczących zachowania, dostępu wielowątkowego, oraz ewentualnej potrzeby utrzymania porządku elementów.</String>

34
Q

Cascade Types

A

CascadeType to mechanizm w JPA (Java Persistence API), który definiuje, jakie operacje powinny być propagowane z jednej encji na drugą. Jest to często używane w kontekście relacji między encjami, takimi jak relacja OneToOne, OneToMany, ManyToOne, itp. Mechanizm CascadeType pozwala na automatyczne rozszerzanie operacji (takich jak zapis, aktualizacja, usunięcie) z jednej encji na powiązaną encję.

Poniżej przedstawiam rodzaje CascadeType:

ALL: Wszystkie operacje są propagowane (zapis, aktualizacja, usunięcie, odłączenie, scalanie, odświeżanie).

java
Copy code
@OneToMany(cascade = CascadeType.ALL)
private Set<ChildEntity> children;
PERSIST: Operacja zapisu jest propagowana.</ChildEntity>

java
Copy code
@OneToOne(cascade = CascadeType.PERSIST)
private ChildEntity child;
MERGE: Operacja aktualizacji (scalania) jest propagowana.

java
Copy code
@ManyToOne(cascade = CascadeType.MERGE)
private ParentEntity parent;
REMOVE: Operacja usuwania jest propagowana.

java
Copy code
@OneToMany(cascade = CascadeType.REMOVE)
private Set<ChildEntity> children;
REFRESH: Operacja odświeżania jest propagowana.</ChildEntity>

java
Copy code
@ManyToOne(cascade = CascadeType.REFRESH)
private ParentEntity parent;
DETACH: Operacja odłączenia jest propagowana.

java
Copy code
@OneToOne(cascade = CascadeType.DETACH)
private ChildEntity child;
Uwaga: Nadmierne korzystanie z CascadeType.ALL może prowadzić do niepożądanych skutków, takich jak przypadkowe zapisywanie lub usuwanie danych. Dlatego zaleca się precyzyjne określanie tylko tych operacji, które są rzeczywiście potrzebne w danym kontekście biznesowym.

35
Q

Do czego służy liquibase?

A

Liquibase to narzędzie do kontroli wersji schematu bazy danych. Jest to open-source’owe narzędzie, które umożliwia programistom zarządzanie zmianami w strukturze bazy danych w sposób kontrolowany i zautomatyzowany. Główne cele Liquibase to zapewnienie spójności struktury bazy danych między różnymi środowiskami (np. środowisko deweloperskie, testowe, produkcyjne) oraz śledzenie i zarządzanie zmianami w bazie danych w czasie.

Podstawowe funkcje Liquibase to:

Zarządzanie migracjami: Pozwala na definiowanie i śledzenie zmian w strukturze bazy danych w formie plików XML, YAML, SQL lub JSON. Każda zmiana jest zarejestrowana w tzw. changelogu.

Automatyzacja procesu migracji: Liquibase automatycznie stosuje migracje, dostosowując bazę danych do najnowszej wersji struktury. Działa to na zasadzie sprawdzania, które migracje zostały już zastosowane, a które nie.

Wsparcie dla wielu systemów baz danych: Liquibase jest niezależny od dostawcy bazy danych, co oznacza, że ​​można go używać z różnymi systemami baz danych, takimi jak MySQL, PostgreSQL, Oracle, SQL Server itp.

Integracja z narzędziami do budowania i wdrażania: Może być łatwo zintegrowany z narzędziami do budowania projektu, takimi jak Apache Maven czy Gradle, co umożliwia automatyczne stosowanie migracji podczas procesu budowania aplikacji.

Przykład pliku changelogu w Liquibase:

xml
Copy code

<databaseChangeLog>

<changeSet>
<createTable>
<column>
<constraints></constraints>
</column>
<column></column>
</createTable>
</changeSet>

<changeSet>
<addColumn>
<column></column>
</addColumn>
</changeSet>
</databaseChangeLog>

W tym przykładzie są dwie migracje. Pierwsza tworzy tabelę, a druga dodaje kolumnę do istniejącej tabeli.

36
Q

Timestamp a LocalTimeDate

A

W kontekście bazy danych i Java, “TimeStamp”, “LocalTime”, “Date” to różne typy danych służące do reprezentacji czasu. Oto krótka charakteryzacja każdego z nich:

TimeStamp (czasowy znacznik czasu):

Java: W Javie, Timestamp to klasa, która dziedziczy po klasie Date i reprezentuje datę i czas, włączając w to sekundy i nanosekundy. Jest często używana do reprezentacji daty i czasu w kontekście baz danych, szczególnie w połączeniu z JDBC (Java Database Connectivity).
Przykład w Javie:
java
Copy code
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
LocalTime:

Java: Klasa LocalTime jest częścią pakietu java.time wprowadzonego w Java 8. Reprezentuje czas, bez daty i strefy czasowej. Jest używana do przechowywania czasu w izolacji od daty.
Przykład w Javie:
java
Copy code
LocalTime localTime = LocalTime.now();
Date:

Java: Klasa Date w Javie jest starszym sposobem reprezentacji daty i czasu. Obejmuje zarówno datę, jak i czas oraz jest często używana w starszym kodzie. Jednak jest to klasa uznawana za przestarzałą w nowoczesnych aplikacjach.
Przykład w Javie:
java
Copy code
Date date = new Date();
W nowoczesnych aplikacjach zaleca się korzystanie z klasy LocalTime (lub innych klas z pakietu java.time) dla reprezentacji czasu oraz LocalDate lub LocalDateTime dla reprezentacji daty i czasu. Jeśli konieczne jest użycie w kontekście bazy danych, Timestamp jest nadal popularnym wyborem w połączeniu z JDBC.

37
Q

Adnotacje do walidacji

A

Adnotacje walidacyjne są często używane w Javie w kontekście technologii walidacji, takich jak Java Bean Validation (JSR 380). Te adnotacje pozwalają na określanie reguł i warunków, które obiekty muszą spełniać. Poniżej znajdziesz kilka popularnych adnotacji walidacyjnych w Javie:

@NotNull:

Adnotacja ta sprawdza, czy wartość pola nie jest null.
java
Copy code
@NotNull
private String fieldName;
@NotEmpty:

Ta adnotacja sprawdza, czy ciąg znaków lub kolekcja nie jest pusta.
java
Copy code
@NotEmpty
private List<String> items;
@NotBlank:</String>

Adnotacja ta sprawdza, czy ciąg znaków nie jest pusty i nie składa się wyłącznie z białych znaków.
java
Copy code
@NotBlank
private String text;
@Min i @Max:

Te adnotacje sprawdzają, czy liczba jest większa lub mniejsza niż określone wartości.
java
Copy code
@Min(1)
private int minValue;

@Max(100)
private int maxValue;
@Size:

Adnotacja ta sprawdza, czy wielkość ciągu znaków lub kolekcji mieści się w określonym zakresie.
java
Copy code
@Size(min = 2, max = 50)
private String username;
@Pattern:

Adnotacja ta sprawdza, czy wartość pola pasuje do określonego wzorca (wyrażenie regularne).
java
Copy code
@Pattern(regexp = “[a-zA-Z0-9]+”)
private String alphanumeric;
@Email:

Adnotacja ta sprawdza, czy wartość pola jest poprawnym adresem e-mail.
java
Copy code
@Email
private String emailAddress;
@AssertTrue i @AssertFalse:

Sprawdzają, czy wartość pola jest true lub false.
java
Copy code
@AssertTrue
private boolean agreedToTerms;

@AssertFalse
private boolean isNotBlocked;
Te adnotacje są często używane w kombinacji z obiektami DTO (Data Transfer Object) lub klasami encji w celu zdefiniowania reguł walidacji. Aby aktywować walidację, można użyć validatora, który implementuje interfejs Validator z pakietu javax.validation.

38
Q

Pattern DTO

A

W Javie termin “DTO” oznacza “Data Transfer Object”. Jest to wzorzec projektowy, który polega na tworzeniu obiektów przeznaczonych do przesyłania danych między warstwami aplikacji. DTO jest używane w celu przeniesienia danych pomiędzy warstwami, na przykład między warstwą prezentacji a warstwą biznesową lub między warstwą biznesową a warstwą dostępu do danych.

Główne cele stosowania wzorca DTO w Javie to:

Separacja warstw: DTO pomaga oddzielić logikę warstwy prezentacji od logiki warstwy biznesowej. Pozwala na przekazywanie tylko niezbędnych informacji między warstwami.

Optymalizacja komunikacji: Przesyłanie pełnych obiektów biznesowych może być nieefektywne, szczególnie w przypadku komunikacji między zdalnymi systemami. Użycie DTO pozwala na przesyłanie tylko tych danych, które są rzeczywiście potrzebne w danej sytuacji.

Zwiększenie przenośności: DTO może również zwiększyć przenośność danych między różnymi warstwami lub aplikacjami, ponieważ struktura danych przesyłanych w ramach DTO może być dostosowywana do konkretnych potrzeb komunikacyjnych.

Przykład prostego DTO w Javie może wyglądać tak:

java
Copy code
public class UserDTO {
private String username;
private String email;

// konstruktory, gettery, settery } W tym przykładzie UserDTO może być używane do przekazywania informacji o użytkowniku między warstwami aplikacji, na przykład z warstwy prezentacji do warstwy biznesowej. Warto zaznaczyć, że obiekty DTO często są proste i zawierają tylko niezbędne dane do przekazania, bez dodatkowej logiki biznesowej.
39
Q

Contract Hashcode a equals

A

rawidłowe zaimplementowanie metod hashCode i equals jest ważne, gdy tworzysz własne klasy w Javie, szczególnie gdy planujesz używać obiektów tych klas jako kluczy w kolekcjach typu HashMap czy HashSet. Oto kilka zasad dotyczących implementacji tych metod:

hashCode:
Metoda hashCode powinna zwracać ten sam wynik dla dwóch obiektów, które są równe w sensie metody equals.
Jeśli dwa obiekty są równe według equals, to ich hashe powinny być również równe.
Nie jest wymagane, aby różne obiekty miały różne hashe, ale zazwyczaj jest to pożądane, aby uniknąć konfliktów w kolekcjach.
Przykładowa implementacja hashCode może wyglądać tak:

java
Copy code
@Override
public int hashCode() {
int result = 17;
result = 31 * result + field1.hashCode();
result = 31 * result + field2.hashCode();
// Dodaj kolejne pola, jeśli istnieją
return result;
}
equals:
Metoda equals powinna być symetryczna, czyli dla dwóch obiektów a i b, jeśli a.equals(b) to również b.equals(a).
Powinna być przechodnia: dla dowolnych obiektów a, b i c, jeśli a.equals(b) i b.equals(c), to również a.equals(c).
Metoda equals powinna zwracać false dla null oraz nie być czuła na kolejność porównywanych pól.
Nieprzekształcaj typu: dla dowolnych obiektów a i b, jeśli a.equals(b) to nie powinno być rzutu a ani b na inny typ, który nie jest równy a lub b.
Przykładowa implementacja equals może wyglądać tak:

java
Copy code
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;

MyClass other = (MyClass) obj;

return Objects.equals(field1, other.field1) &&
       Objects.equals(field2, other.field2);
// Dodaj kolejne pola, jeśli istnieją } Warto zauważyć, że od Javy 7 można używać klasy Objects do prostego porównywania obiektów i uniknięcia problemów związanych z null. Metoda Objects.equals(a, b) zwraca true, jeśli oba argumenty są równe, również w przypadku, gdy oba są nul
40
Q

Wsztrzykiwanie zależności wjavie

A

Wstrzykiwanie zależności (Dependency Injection, DI) to technika projektowania, która polega na dostarczaniu obiektom ich zależności z zewnątrz, zamiast pozwalania im tworzyć te zależności samodzielnie. W Javie istnieje kilka sposobów wstrzykiwania zależności. Poniżej przedstawiam kilka z nich:

Wstrzykiwanie przez konstruktor (Constructor Injection):
W tej metodzie zależności są przekazywane przez konstruktor klasy.

java
Copy code
public class MyClass {
private Dependency dependency;

public MyClass(Dependency dependency) {
    this.dependency = dependency;
}

// ... } Wstrzykiwanie przez konstruktor jest jednym z najczęstszych sposobów wstrzykiwania zależności.

Wstrzykiwanie przez metody (Method Injection):
Zależności są przekazywane poprzez metody.

java
Copy code
public class MyClass {
private Dependency dependency;

public void setDependency(Dependency dependency) {
    this.dependency = dependency;
}

// ... } Ta metoda może być używana do dynamicznego ustawiania zależności w czasie życia obiektu.

Wstrzykiwanie przez pole (Field Injection):
Zależności są wstrzykiwane bezpośrednio do pól klasy. To podejście jest mniej zalecane, ponieważ utrudnia testowanie (niemożliwe jest wstrzykiwanie zależności w czasie testowania jednostkowego).

java
Copy code
public class MyClass {
@Inject
private Dependency dependency;

// ... } Wstrzykiwanie przez pole jest popularne w frameworkach do wstrzykiwania zależności, takich jak Spring czy Guice.

Wstrzykiwanie przez interfejsy (Interface Injection):
Wstrzykiwanie zależności może być również realizowane poprzez implementację interfejsów, które definiują metody ustawiające zależności.

java
Copy code
public interface DependencyInjector {
void injectDependency(MyClass myClass);
}

public class MyClass implements DependencyInjector {
private Dependency dependency;

@Override
public void injectDependency(Dependency dependency) {
    this.dependency = dependency;
}

// ... } Ta metoda może być bardziej elastyczna, ale wprowadza również większą złożoność.

Wstrzykiwanie z użyciem kontenera IoC (Inversion of Control):
Kontenery IoC, takie jak Spring czy CDI, zarządzają cyklem życia obiektów i automatycznie wstrzykują zależności. W takim przypadku, konfiguracja odbywa się zazwyczaj za pomocą plików konfiguracyjnych lub adnotacji.

java
Copy code
@Component
public class MyClass {
@Autowired
private Dependency dependency;

// ... } W tym przykładzie używane są adnotacje Springa (@Component i @Autowired) do zautomatyzowania wstrzykiwania zależności.

Wybór konkretnego sposobu wstrzykiwania zależy od wymagań projektu, struktury kodu i preferencji programisty. W praktyce często stosuje się różne metody w zależności od kontekstu i potrzeb aplikacji.

41
Q

Mapowanie DTO to Product

A

Mapowanie danych z obiektu DTO (Data Transfer Object) do obiektu klasy Product w Javie można zrealizować na różne sposoby. Jednym z popularnych narzędzi do mapowania jest biblioteka ModelMapper. Oto przykład, jak można to zrobić:

ModelMapper:
ModelMapper to narzędzie do mapowania obiektów w Javie, które automatyzuje proces przypisywania pól z jednego obiektu do drugiego.

java
Copy code
import org.modelmapper.ModelMapper;

public class ProductMapper {
private ModelMapper modelMapper;

public ProductMapper() {
    this.modelMapper = new ModelMapper();
}

public Product mapDtoToProduct(ProductDTO productDto) {
    return modelMapper.map(productDto, Product.class);
} } W tym przypadku, ProductDTO to klasa reprezentująca obiekt DTO, a Product to klasa reprezentująca obiekt docelowy.

Ręczne mapowanie:
Możesz również ręcznie przypisywać wartości pól z obiektu DTO do obiektu Product. Poniżej znajduje się prosty przykład:

java
Copy code
public class ProductMapper {
public Product mapDtoToProduct(ProductDTO productDto) {
Product product = new Product();
product.setName(productDto.getName());
product.setPrice(productDto.getPrice());
// Przypisz pozostałe pola

    return product;
} } Ta metoda wymaga ręcznego ustawiania każdego pola, co może być uciążliwe, szczególnie w przypadku obiektów z wieloma polami.

MapStruct:
MapStruct to inna biblioteka do automatycznego generowania kodu mapującego. Wymaga zdefiniowania interfejsu z adnotacjami, a następnie generuje klasę mapującą na podstawie tego interfejsu.

java
Copy code
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface ProductMapper {
ProductMapper INSTANCE = Mappers.getMapper(ProductMapper.class);

Product mapDtoToProduct(ProductDTO productDto); } W przypadku MapStruct, generowany kod mapujący jest automatycznie dostępny poprzez wywołanie ProductMapper.INSTANCE.mapDtoToProduct(productDto).

Niektóre z tych podejść mogą wymagać dodatkowych konfiguracji lub zależności, dlatego warto sprawdzić dokumentację i dostosować implementację do konkretnych potrzeb projektu.

42
Q

Jak naprawić Lazy Loading

A

Mapowanie danych z obiektu DTO (Data Transfer Object) do obiektu klasy Product w Javie można zrealizować na różne sposoby. Jednym z popularnych narzędzi do mapowania jest biblioteka ModelMapper. Oto przykład, jak można to zrobić:

ModelMapper:
ModelMapper to narzędzie do mapowania obiektów w Javie, które automatyzuje proces przypisywania pól z jednego obiektu do drugiego.

java
Copy code
import org.modelmapper.ModelMapper;

public class ProductMapper {
private ModelMapper modelMapper;

public ProductMapper() {
    this.modelMapper = new ModelMapper();
}

public Product mapDtoToProduct(ProductDTO productDto) {
    return modelMapper.map(productDto, Product.class);
} } W tym przypadku, ProductDTO to klasa reprezentująca obiekt DTO, a Product to klasa reprezentująca obiekt docelowy.

Ręczne mapowanie:
Możesz również ręcznie przypisywać wartości pól z obiektu DTO do obiektu Product. Poniżej znajduje się prosty przykład:

java
Copy code
public class ProductMapper {
public Product mapDtoToProduct(ProductDTO productDto) {
Product product = new Product();
product.setName(productDto.getName());
product.setPrice(productDto.getPrice());
// Przypisz pozostałe pola

    return product;
} } Ta metoda wymaga ręcznego ustawiania każdego pola, co może być uciążliwe, szczególnie w przypadku obiektów z wieloma polami.

MapStruct:
MapStruct to inna biblioteka do automatycznego generowania kodu mapującego. Wymaga zdefiniowania interfejsu z adnotacjami, a następnie generuje klasę mapującą na podstawie tego interfejsu.

java
Copy code
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface ProductMapper {
ProductMapper INSTANCE = Mappers.getMapper(ProductMapper.class);

Product mapDtoToProduct(ProductDTO productDto); } W przypadku MapStruct, generowany kod mapujący jest automatycznie dostępny poprzez wywołanie ProductMapper.INSTANCE.mapDtoToProduct(productDto).

Niektóre z tych podejść mogą wymagać dodatkowych konfiguracji lub zależności, dlatego warto sprawdzić dokumentację i dostosować implementację do konkretnych potrzeb projektu.

43
Q

Lazy loading

A

Lazy loading (leniwe ładowanie) to technika używana w kontekście ORM (Object-Relational Mapping), która umożliwia opóźnienie ładowania danych z bazy danych do momentu, gdy są one faktycznie potrzebne. W skrócie, oznacza to, że niektóre dane nie są wczytywane od razu podczas pobierania głównego obiektu z bazy danych, ale są ładowane dopiero wtedy, gdy są używane lub odwoływane.

W kontekście Hibernate, popularnego frameworka ORM dla Javy, lazy loading jest powszechnie stosowaną strategią. Oto jak to działa:

Domyślnie, leniwe ładowanie jest włączone:
W Hibernate domyślnie stosuje się leniwe ładowanie dla relacji jednostronnych i wielostronnych. Oznacza to, że powiązane obiekty nie są pobierane automatycznie wraz z głównym obiektem, lecz są ładowane dopiero wtedy, gdy są rzeczywiście potrzebne.

Typy leniwego ładowania:
Hibernate oferuje różne strategie leniwego ładowania, takie jak:

Leniwe ładowanie przy dostępie (Lazy Loading Proxy): Powiązane obiekty są ładowane dopiero wtedy, gdy są rzeczywiście używane po wywołaniu metody dostępu.
Leniwe ładowanie przy pobieraniu (Lazy Loading Collection): Powiązane kolekcje są ładowane dopiero wtedy, gdy są rzeczywiście używane.
Zastosowanie:

Optymalizacja wydajności: Leniwe ładowanie może pomóc w optymalizacji wydajności, zwłaszcza w sytuacjach, gdy duża ilość danych jest dostępna, a nie wszystkie są potrzebne w danym kontekście.
Unikanie zbytecznego pobierania danych: Leniwe ładowanie pozwala unikać pobierania zbędnych danych, co jest szczególnie przydatne w dużych systemach, gdzie efektywność dostępu do danych jest kluczowa.
Potencjalne problemy:

LazyInitializationException: Jednym z potencjalnych problemów związanym z leniwym ładowaniem jest LazyInitializationException, która może wystąpić, gdy próbujesz uzyskać dostęp do leniwie ładowanego pola poza kontekstem sesji Hibernate.
Warto zaznaczyć, że mimo korzyści wynikających z leniwego ładowania, należy uważać na jego zastosowanie i upewnić się, że jest stosowane w odpowiedni sposób, aby uniknąć potencjalnych problemów związanych z dostępem do danych poza kontekstem sesji.