Czytaj dalej...Modyfikatory dostępu w języku Java
The post Modyfikatory dostępu w języku Java appeared first on Dev Foundry.
]]>W języku Java istnieją cztery modyfikatory dostępu (zwane również modyfikatorami widoczności). Każdy z nich określa czy dana klasa, metodą bądź pole klasy jest widoczne dla innych klas. W języku Java istnieją cztery poziomy, zaczynając od najszerszego są to – public, protected, default (package), private. Trzeba pamiętać, że choć modyfikatory dostępu są cztery to słów kluczowych je określających jest już tylko trzy – private, public i protected. Poziom package jest poziomem domyślnym i jeśli chcemy go użyć to po prostu nie dodajemy żadnego modyfikatora dostępu przed nazwą pola czy metody.
W filmie poniżej znajdziesz opis na praktycznym przykładzie, zapraszam do obejrzenia.
Public jest najszerszym poziomem widoczności – klasy, pola i metody oznaczone w ten sposób są widoczne dla wszystkich innych klas.
Drugi w kolejności – protected– jest dostępny dla klas zdefiniowanej w tej samej paczce oraz w klasach dziedziczących (extends) po klasie, która zawiera pola czy metody oznaczone jako protected.
Package, będący domyślnym poziomem widoczności nieposiadającym własnego modyfikatora, ogranicza widoczność do klas z tej samej paczki.
Finalnie mamy private– czyli prywatne. Jak sama nazwa wskazuje elementy z dostępem na poziomie prywatnym są widoczne tylko dla struktur zdefiniowanych w tej samej klasie.
Jeśli dowiedziałeś się dzięki temu wpisowi czegoś nowego, będzie nam niezmiernie miło, gdybyś podzielił się tym postem w swoich social mediach.
The post Modyfikatory dostępu w języku Java appeared first on Dev Foundry.
]]>Czytaj dalej...Różnice pomiędzy final, finally, a finalize
The post Różnice pomiędzy final, finally, a finalize appeared first on Dev Foundry.
]]>final i finally oraz metody finalize. Funkcjonalności te, wbrew pozorom, poza zbliżonymi nazwami nie mają ze sobą nic wspólnego.
Na poniższym filmie omawiam działanie każdego z nich:
Final jest słowem kluczowym, które użyte ze zmienną zamienia ją w stałą. Natomiast użyte wraz z metodą powoduje, iż nie można jej nadpisać. Można również wykorzystać je wraz z klasą – wówczas blokuje ono możliwość dziedziczenia danej klasy.
Finally jest elementem bloku try-catch-finally. Operacje zawarte w tej sekcji zostaną zawsze wykonane – niezależnie czy kod zawarty w sekcji catch zakończył się sukcesem, czy rzucił wyjątkiem.
Finallize jest natomiast metodą z klasy Object, która w teorii miała być wywoływana przed tym, gdy dany obiekt zostanie usunięty z pamięci. W praktyce nie zawsze (albo wręcz z reguły) nie działała w 100%. Obecnie oznaczona jest jako deprecated i nie powinna być używana pod żadnym pozorem.
Jeśli ten post Ci się przydał podziel się nim proszę w swoich social mediach 
The post Różnice pomiędzy final, finally, a finalize appeared first on Dev Foundry.
]]>Czytaj dalej...Praca z Optional w Hibernate
The post Praca z Optional w Hibernate appeared first on Dev Foundry.
]]>Optional jest jednym z ciekawszych dodatków do Javy w ostatnich latach, jednak gdy chcemy użyć go jako typ pola dla encji (obiekt, którego stan przechowywany jest w bazie danych) to czeka nas nieprzyjemna niespodzianka zaserwowana przez Hibernate.
Mając klasę
@Entity
public class Book {
@Id
private Integer id;
private String title;
private Optional publisher;
public Book() {
}
public Book(Integer id, String title, Optional publisher) {
this.id = id;
this.title = title;
this.publisher = publisher;
}
//...gettery
}
Dostaniemy następujący wyjątek już przy starcie aplikacji:
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Optional
Dzieje się tak, ponieważ Hibernate nie jest w stanie zmapować typu Optional na znany mu typ wspierany przez baze danych.
Na szczęście nie wszystko stracone. Mianowicie możemy skorzystać z faktu, że nasze zmienne i tak są prywatne, więc ukryte przed całym światem, a dostęp do nich mamy tylko poprzez gettery.
Wystarczy drobna zmiana w kodzie:
@Entity
public class Book {
@Id
private Integer id;
private String title;
private String publisher;
public Book() {
}
public Book(Integer id, String title, String publisher) {
this.id = id;
this.title = title;
this.publisher = publisher;
}
public Optional getPublisher() {
return Optional.ofNullable(publisher);
}
}
Zamieniliśmy typ stanu z Optional na String oraz standardowy getter – teraz zwraca on typ Optional, który to jest tworzony przy wywoływaniu gettera. W ten oto sposób zadowalamy wymagania Hibernate, bo nie ma on problemu ze zmapowaniem na typ tekstowy w dowolnej bazie danych, oraz wymagania biznesowe by publisher był dostępny jako typ opcjonalny.
Jedyną niedogodnością takiego rozwiązania jest to, że jeśli chcemy wewnątrz klasy korzystać z opcjonalnego publisher to musimy albo korzystać z gettera (preferowane), albo sami tworzyć Optional.ofNullable(...).
Rozwiązanie ma jeszcze jedną zaletę. Przy takiej definicji klasy możemy nieco rozszerzyć zwracanie pustego Optional również do sytuacji, gdy mamy pusty tekst („”) jako publisher:
@Entity
public class Book {
@Id
private Integer id;
private String title;
private String publisher;
public Book() {
}
public Book(Integer id, String title, String publisher) {
this.id = id;
this.title = title;
this.publisher = publisher;
}
public Optional getPublisher() {
if( publisher != null || publisher.isEmpty()) {
return Optional.empty();
} else {
return Optional.ofNullable(publisher);
}
}
}
Jeśli chcesz dowiedzieć się więcej na temat typu Optional polecam nasz poprzedni wpis, a w nagraniu poniżej możesz zobaczyć program demonstrujący zachowanie Optional wraz z Hibernate.
Bardzo nam pomożesz udostępniając ten artykuł na swoim facebooku, twitterze czy innym medium społecznościowym, które preferujesz 
The post Praca z Optional w Hibernate appeared first on Dev Foundry.
]]>Czytaj dalej...GitHub – Podstawy
The post GitHub – Podstawy appeared first on Dev Foundry.
]]>
) , czyli: tworzymy coś lokalnie (nieważne czy kod czy e-book), zapisujemy i wysyłamy na platformę, a nasi współpracownicy mogą aktualną wersję podejrzeć, ściągnąć na swój dysk i dokonać dalszych zmian. Dodatkowo cała historia zmian jest przechowywana i w dowolnym momencie możemy wrócić do wersji sprzed tygodnia na przykład. Dzięki platformie GitHub współpraca nad wspólnymi projektami jest bardzo wygodna. Wrzucenie tam paru ciekawych projektów w ramach portfolio może realnie zwiększyć nasze szanse na zdobycie pracy.
GitHub wspiera tylko jeden system kontroli wersji, a jest nim najpopularniejszy z nich – Git. Tak więc cała przygoda z GitHub zaczyna się po naszej stronie – musimy zainstalować po swojej stronie program wspierający pracę z tym systemem. Najlepiej zrobić to pobierając odpowiedni dla naszego systemu operacyjnego instalator ze strony https://git-scm.com/downloads . Następnie, dla osoby zaczynającej swoją przygodę z Gitem, dobrym pomysłem jest instalacja jakiegoś wygodnego GUI. Może to być na przykład TortoiseGit . Teraz możemy utworzyć katalog, w którym umieścimy rzeczy, które chcemy przechowywać na platformie GitHub. W moim przypadku będzie to: C:\Dev\Workspace\github. Dodam tam jeden plik – ToDo.txt z treścią „1. Learn GitHub”. Tu już pojawia się pierwsza ważna rzecz – GitHub nie służy tylko do przechowywania źródeł programów, ale równie dobrze może służyć za np. miejsce do publikacji listy ciekawych artykułów czy własnych poradników, a nawet e-booków naszego autorstwa. Należy tylko pamiętać, że wszystkie te rzeczy są widoczne dla całego świata (chyba, że zapłacimy za repozytorium prywatne).
Następnie w tym katalogu wykonajmy serie komend:
git init git add ToDo.txt git commit -m "Initial Commit"
Komendy te tworzą nowe repozytorium git w aktualnym katalogu roboczym (init), dodają plik ToDo.txt do utworzonego repozytorium (add), finalnie zapisujemy zmiany w repozytorium (w tym wypadku dodanie pliku) z komentarzem „Initial commit” (commit). Z poziomu menu kontekstowego Windows dostarczanego przez TortoiseGit, w katalogu C:\Dev\Workspace\ ,będą to opcje „Git create repository here…”, „TortoiseGit -> Add”, „Git Commit”
Tak oto utworzyliśmy lokalne repozytorium Git i mamy wszystko, czego nam potrzeba by zacząć przygodę z platformą GitHub.
Pierwszym krokiem na drodze poznania tej platformy jest oczywiście rejestracja, którą możemy wykonać tutaj – tradycyjnie należy wybrać nazwę użytkownika oraz podać e-mail i hasło. Kolejnym jest wybór planu. Opcja darmowa oferuje nieograniczoną ilość publicznych repozytoriów (czyli widocznych dla wszystkich), a płatna – nieograniczoną ilość zarówno prywatnych, jak i publicznych. Nas interesuje opcja publiczna.
Na sam koniec możemy wypełnić składającą się z kilku pytań ankietę.
Teraz jesteśmy już gotowi na utworzenie pierwszego projektu:
Na ekranie, który pojawi się po rejestracji, możemy utworzyć nowy projekt („Start a project”), przejrzeć nasze repozytoria, bądź zagłębić się w kod źródłowy innych. My utworzymy nowe repozytorium, wybieramy więc „Start a project” (pamiętaj, by przed tym krokiem zweryfikować swoje konto, GitHub prześle link weryfikacyjny na podany adres e-mail).
Zostaniemy przeniesieni na ekran tworzenia nowego repozytorium:
Wystarczy podać nazwę i już możemy je utworzyć. W następnym kroku zostaną nam pokazane trzy możliwości inicjalizacji repozytorium na platformie GitHub – utworzenie zupełnie nowego repozytorium lokalnego i udostępnienie go, podpięcie istniejącego już repozytorium, bądź import z innego systemu kontroli wersji (na przykład Mercurial czy SVN). Do dwóch pierwszych z nich została dodana lista komend, jakie należy lokalnie uruchomić, by udostępnić nasze repozytorium.
Nas interesuje opcja numer dwa, ponieważ mamy już stworzone repozytorium. Wykonujemy więc dwa brakujące kroki:
git remote add origin https://github.com/dev-foundry/githubdemo.git git push -u origin master
Pierwsza z nich dodaje nowy, zewnętrzny serwer, na którym przechowywane będzie nasze repozytorium. Natomiast push wypycha zmiany z lokalnego repozytorium na ten właśnie serwer. Po odświeżeniu strony, na którą przekierował nas GitHub, powinniśmy ujrzeć teraz nieco inny widok, który warto nieco opisać
I tak zaczynając od góry mamy nazwę użytkownika oraz nazwę tego repozytorium (w tym wypadku dev-foundry/githubdemo), poniżej mamy szereg zakładek. Najbardziej interesują nas trzy pierwsze – na obrazie powyżej aktywny jest Code – czyli pliki źródłowe naszego projektu. Następnie mamy Issues – czyli lista błędów jakie zgłosili użytkownicy tego kodu . Pull requests natomiast są to prośby o dołączenie jakiegoś kodu (umieszczonego na osobnym branchu) do głównego kodu aplikacji (master branch).
Gdy zmienimy coś lokalnie w pliku ToDo.txt wystarczy, ze wykonamy komendy:
git commit -m "First change" git push origin master
i momentalnie zmiany będą widoczne na platformie. Komenda commit zapisze zmiany dokonane w pliku ToDo.txt do repozytorium, a komenda push prześle zmiany na serwer GitHub.
W tym miejscu zakończymy wprowadzenie do platformy GitHub – napisz w komentarzach jeśli chcesz wiedzieć więcej o branchach czy pull-requestach, a może interesuję Cie jak efektywnie pracować z Gitem?
Wszelkie sugestie będą mile widziane 
The post GitHub – Podstawy appeared first on Dev Foundry.
]]>Czytaj dalej...Zapis i odczyt plików w Java 7+
The post Zapis i odczyt plików w Java 7+ appeared first on Dev Foundry.
]]>Zacznijmy od utworzenia naszego przykładowego pliku z danymi:
EmployeeData Paweł,Ćwik 32 y EmployeeData Dawid,Nowak 32 n
Plik przechowuje informacje o pracowniku – jego imię, nazwisko, wiek oraz czy jest zatrudniony na pełny etat. Stwórzmy więc w pierwszej kolejności klasę Employee, która będzie korzystać z tych danych:
package pl.devfoundry.newio.demo.domain;
public class Employee {
private String firstName;
private String lastName;
private int age;
private boolean fullTime;
public Employee(String firstName, String lastName, int age, boolean fullTime) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.fullTime = fullTime;
}
@Override
public String toString() {
return "Employee{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", age=" + age +
", fullTime=" + fullTime +
'}';
}
}
Skoro mamy już nasz plik oraz klasę wzorcową, czas zabrać się za odczyt z pliku. Od Javy 7 służą nam (w podstawowych przypadkach) dwie klasy – Path i File. Pierwsza z nich odpowiada za wszelkiego rodzaju ścieżki w naszym systemie – zarówno do plików, jak i katalogów. Nie operujemy więc już na czystych ścieżkach. File, jak łatwo wywnioskować, służy do przechowywania informacji o pliku. Z tymi dwoma klasami spokrewnione są dwie klasy „utilsowe” o nazwach (jak to w Javie się przyjęło) Paths i Files. Dzięki nim możemy w bardzo prosty sposób porównać ze sobą np. dwie ścieżki, pobierać plik z danej ścieżki, odczytywać zawartość pliku, sprawdzać prawa dostępowe i wiele innych. Nas jednak interesuje obecnie najprostszy przypadek użycia – czyli odczyt wszystkich linijek pliku. Kod rozwiązania będzie prezentował się tak:
package pl.devfoundry.newio.demo;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class MainApp {
public static void main(String[] args) throws IOException {
Path path = Paths.get("./employees.txt");
List lines = Files.readAllLines(path);
}
}
Używamy metody .get() z klasy Paths by utworzyć nową ścieżkę, która będzie wskazywać na plik employees.txt, który znajduje się w katalogu projektu. Następnie używamy klasy pomocniczej Files, by odczytać całą zawartość pliku podanego w ścieżce, linia po linii. I to tyle. Lista lines zawiera wszystkie linijki tekstu z pliku wejściowego. Czas więc na odrobinę logiki biznesowej i ich obróbkę.
package pl.devfoundry.newio.demo;
import pl.devfoundry.newio.demo.domain.Employee;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class MainApp {
public static void main(String[] args) throws IOException {
Path path = Paths.get("./employees.txt");
List lines = Files.readAllLines(path);
List employees = new ArrayList<>();
for(int i=0;i
Czyli wyszukujemy linijkę z napisem „EmployeeData”, a następnie pobieramy dane z trzech kolejnych i na ich podstawie tworzymy nowego pracownika. Oczywiście nie ma tutaj żadnej kontroli czy dane są odpowiednie i czy nie przekroczymy indeksu – w aplikacji produkcyjnej taka walidacja musiałaby się oczywiście pojawić. Tutaj dla zachowania większej przejrzystości po prostu przechodzimy dalej.
NewIO 2 – zapis do pliku
Po pierwsze potrzebujemy logiki, która nasz obiekt przerobi na format JSON. W 99% przypadków takie rzeczy robi się za pomocą bibliotek zewnętrznych, jednak tu mamy prosty przypadek, dla którego nie warto dociągać całych bibliotek, skoro wystarczy jedna prosta metoda toJson() dla obiektu i druga dla całej listy. Do klasy Emplyee dodajemy
public String toJson() {
return "{" +
"\"firstName\": \"" + this.firstName + "\", " +
"\"lastName\": \"" + this.lastName + "\", " +
"\"age\":" + this.age + ", " +
"\"fullTime\": " + Boolean.toString(this.fullTime) +
"}";
}
Natomiast do klasy MainApp dorzucamy metodę statyczną
public static String toJson(List employees) {
String empl = employees.stream()
.map(Employee::toJson)
.collect(Collectors.joining(","));
return "{\"employees\": ["+empl+"]}";
}
Tak oto za pomocą kilku linijek kodu, bez użycia i narzutu zewnętrznych bibliotek, mamy nasze dane w formacie JSON. Jedyne, co pozostało, to zapisać je do pliku. Na szczęście dla nas Java 7 również bardzo ułatwiła sprawę. Przez „bardzo” mam na myśli fakt, że całą tę operację zmieścimy w dwóch linijkach:
Path savePath = Paths.get("./employees.json");
Files.write(savePath,toJson(employees).getBytes(Charset.forName("UTF-8")));
W pierwszej z nich tworzymy (nieistniejącą jeszcze) ścieżkę do pliku i ponownie używamy klasy Files, tym razem by zapisać nasz plik. Zawsze warto do metody .getBytes() dorzucić kodowanie, w jakim chcemy zapisać nasze dane – by uniknąć potencjalnych szlaczków zamiast np. polskich znaków.
Podsumowanie
Jak powyższe przykłady pokazują – Java 7 bardzo wiele zmieniła, jeśli chodzi o obsługę plików. Wszystko sprowadza się do tego, że w końcu można zapamiętać jak wczytać i zapisać plik, co przy wcześniejszych rozwiązaniach było dla mnie niemożliwością
i zawsze powodowało wspomaganie się StackOverflow 
Kod rozwiązania jest dostępny na platformie github.
The post Zapis i odczyt plików w Java 7+ appeared first on Dev Foundry.
]]> Czytaj dalej...Multicatch wyjątków w języku Java
The post Multicatch wyjątków w języku Java appeared first on Dev Foundry.
]]>Za przykład niech posłuży nam sytuacja, w której dana metoda może rzucić jednym z wielu wyjątków, na przykład:
public void businessMethod() throws IOException, IllegalStateException, BusinessException{
gdzie BusinessException jest zdefiniowany w następujący sposób:
public BusinessException() extends IllegalStateException() {
public BusinessException(String msg) {
super(msg);
}
}
Po użyciu tej metody musimy obsłużyć wszystkie trzy wyjątki i potrzebujemy osobny blok catch dla każdego z nich:
try {
businessMethod()
} catch (IOException ex) {
System.out.println(ex.getMessage());
} catch (BusinessException ex) {
System.out.println(ex.getMessage());
} catch (IllegalStateException ex) {
System.out.println(ex.getMessage());
}
W tym wypadku należy również pamiętać by obsłużyć wszystkie wyjątki w odpowiedniej kolejności, a konkretniej by obsłużyć BusinessException przed IllegalStateException. Jest to spowodowane faktem, że nasz własny wyjątek dziedziczy po IllegalStateException i gdyby był w kolejności po nim, to wtedy (jako że każdy BusinessException jest typu IllegalStateException), nigdy nie dochodziłoby do obsługi naszego wyjątku, ponieważ wszystko byłoby łapane w bloku catch IllegalStateException.
W Javie od wersji 7 w górę możemy zmniejszyć ilość bloków catch, jeśli chcemy obsłużyć wiele różnych wyjątków w ten sam sposób – służy do tego tak zwany mulitcatch:
try {
businessMethod()
} catch (BusinessException ex) {
System.out.println(ex.getMessage());
} catch (IllegalStateException | IOException ex) {
System.out.println(ex.getMessage());
}
Dzięki temu skraca nam się nieco składnia – wyjątki rozdzielamy znakiem |. Jednak i tu należy uważać na kwestie dotyczące dziedziczenia i hierarchii wyjątków. Ponownie BusinessException jest „problematyczny” – nie może się on znaleźć w tym samym bloku multicatch co jego rodzic – czyli IllegalStateException, wciąż musi być on obsługiwany w osobnym bloku.
Drugą różnicą, już mniej dotkliwą, jest kwestia „przepakowania” parametru ex. W „starej” Javie mogliśmy zrobić coś takiego:
catch (IOException ex) {
ex = new IOException("new message");
}
W nowszych wersjach, przy użyciu mulitcatch, nie jest to już możliwe – parametr ex jest niejawnie typu final.
I to by było na tyle jeżeli chodzi o temat multicatch w Javie. Na pewno warto pamiętać, że mamy takie narzędzie do dyspozycji (w zależności od tego z jakiej wersji Javy akurat korzystamy w projekcie). Natomiast korzystając już z multicatcha oraz pracując z wyjątkami, które sami utworzyliśmy, nie zapominajmy o hierarchii dziedziczenia.
The post Multicatch wyjątków w języku Java appeared first on Dev Foundry.
]]>Czytaj dalej...Spring Data – @Query
The post Spring Data – @Query appeared first on Dev Foundry.
]]>Zacznijmy tradycyjnie od utworzenia nowego projektu – w tym wypadku skorzystamy z generatora projektów springowych – strony http://start.spring.io/
Interesuję nas taka konfiguracja projektu:
Niezbędne dla nas zależności to JPA i H2 (wbudowana, lekka baza danych).
Po utworzeniu projektu w IntelliJ dodajmy prosty obiekt domenowy Employee, z którego robimy od razu encję:
package pl.devfoundry.querydemo.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Employee {
@Id
@GeneratedValue
private int id;
private String name;
private int age;
private Employee() {
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
Następnie w tej samej paczce co klasa Employee dodajmy paczkę repository i tam utwórzmy nowy interfejs EmployeeRepository, który będzie rozszerzał interfejs JpaRepository rodem ze Spring Data
package pl.devfoundry.querydemo.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; import pl.devfoundry.querydemo.domain.Employee; public interface EmployeeRepository extends JpaRepository{ }
Interfejs JpaRepository potrzebuje dwóch wartości generycznych – pierwsza z nich odpowiada encji, której repozytorium chcemy utworzyć. Drugie natomiast typowi klucza głównego tej encji (w naszym wypadku int -> Integer)
Teraz w głównej klasie aplikacji, możemy śmiało korzystać z tego interfejsu, by dodawać, usuwać i wyszukiwać wszystkich pracowników. To wszystko bez napisania nawet linijki kodu związanego z JPA.
Użyjmy naszego repozytorium. Utwórzmy springowy bean, który w metodzie init() będzie tworzył nowego pracownika.
package pl.devfoundry.querydemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import pl.devfoundry.querydemo.domain.Employee;
import pl.devfoundry.querydemo.domain.repository.EmployeeRepository;
import javax.annotation.PostConstruct;
@Component
public class DataLoader {
@Autowired
EmployeeRepository employeeRepository;
@PostConstruct
public void init() {
System.out.println("Database operations");
employeeRepository.save(new Employee("Pawel", 32));
}
}
Wstrzykujemy poprzez @Autowired komponent EmployeeRepository, warto zwrócić tu uwagę, że sami takiego komponentu nigdzie nie definiowaliśmy – został on wygenerowany przez Spring Data automatycznie na podstawie interefejsu. Dzięki użyciu @PostConstruct mamy pewność, że kawałek kodu zawarty w metodzie init() wywoła się zaraz po utworzeniu komponenetu DataLoader.
Dodatkowo do pliku application.properties dodajmy wpisy:
spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true
Dzięki nim na konsoli będziemy widzieć jakie kwerendy wykonuje Hibernate.
Uwaga! Jeśli używasz Javy 9+ do dependencji wygenerowanego projektu należy dodać wpis:
javax.xml.bind jaxb-api 2.3.0
A dlaczego to już temat na zupełnie osobny wpis, albo i więcej. Na chwilę obecną musisz mi zaufać 
Po wywołaniu tego kodu pośród logów zaobserwować można wpis:
Hibernate:
insert
into
employee
(age, name, id)
values
(?, ?, ?)
Czyli Hibernate dodał pracownika do bazy.
Dodatkowo możemy w bardzo łatwy sposób dodawać metody, które będą wyszukiwały pracownika po danym parametrze. Wystarczy dodać metodę findByName do interfejsu by Spring Data automagicznie automatycznie utworzył niezbędny kod JPA i wygenerował kod dla metody.
public interface EmployeeRepository extends JpaRepository{ List findByName(String name); }
@Component
public class DataLoader {
@Autowired
EmployeeRepository employeeRepository;
@PostConstruct
public void init() {
System.out.println("Database operations");
employeeRepository.save(new Employee("Pawel", 32));
find();
}
private void find() {
List pawels = employeeRepository.findByName("Pawel");
pawels.forEach(System.out::println);
}
}
W logach znajdziemy wpis:
Employee{id=1, name='Pawel', age=32}
Podobnie możemy utworzyć metody np. findByNameAndAge, findByAge, findByNameOrAge
Co w przypadku gdy chcemy utworzyć metodę, która wyszuka nam pracowników z imieniem zaczynającym się na literę „A”?
Możemy dodać deklarację metody findByNameStartingWith do interfejsu repozytorium i automat nam wygeneruję co trzeba. Jak widać Spring Data ma rozwiązanie na wszystko, ale na potrzeby tego wpisu załóżmy, że nie ma powyższej funkcjonalności i musimy dodać do naszego repozytorium własne zapytanie JPA. Robimy takie rzeczy za pomoca adnotacji @Query przy deklaracji metody w interfejsie EmployeeRepository
public interface EmployeeRepository extends JpaRepository{ List findByName(String name); @Query("Select e from Employee e WHERE e.name like 'P%'") List myOwnQuery(); }
Wówczas wywołanie myOwnQuery() wywoła na bazie zapytanie JPQL zawarte jako parametr dla adnotacji @Query.
@Component
public class DataLoader {
@Autowired
EmployeeRepository employeeRepository;
@PostConstruct
public void init() {
System.out.println("Database operations");
employeeRepository.save(new Employee("Pawel", 32));
find();
}
private void find() {
List pawels = employeeRepository.myOwnQuery();
pawels.forEach(System.out::println);
}
}
Oczywiście do tak utworzonych zapytań możemy przesyłać parametry, robi się to w następujący sposób:
public interface EmployeeRepository extends JpaRepository{ List findByName(String name); @Query("Select e from Employee e WHERE e.name like CONCAT(:firstLetter,'%')") List findByFirstLetter(@Param("firstLetter") String letter); }
@Component
public class DataLoader {
@Autowired
EmployeeRepository employeeRepository;
@PostConstruct
public void init() {
System.out.println("Database operations");
employeeRepository.save(new Employee("Pawel", 32));
find();
}
private void find() {
List pawels = employeeRepository.findByFirstLetter("P");
pawels.forEach(System.out::println);
}
}
Co ponownie zwróci nam wszystkich pracowników z imieniem zaczynającym się na literę P, a będzie to jeden pracownik o imieniu ‚Pawel’.
To są tylko podstawowe przykłady użycia modułu Spring Data, będącego częścią składową Spring Framework, a już one pokazują jaka moc w nim drzemie i jak bardzo przycina ilość kodu potrzebnego do komunikacji z bazą danych.
Kod przykładu dostępny jest na platformie gitub.
The post Spring Data – @Query appeared first on Dev Foundry.
]]>Czytaj dalej...Optional i Java – nie tylko isPresent i get
The post Optional i Java – nie tylko isPresent i get appeared first on Dev Foundry.
]]>Wraz ze wszystkimi dobrodziejstwami Javy 8 dotarł do nas długo oczekiwany Optional – czyli wrapper na inny obiekt, który informuje nas czy obiekt ów tam się znajduje, czy może jednak nie. W najogólniejszym opisie miał on służyć do zastąpienia zwracania null pustym Optional właśnie – i tak przykładowa metoda find(employee.getId()) powinna nam zwracać nie obiekt o danym id bądź null, lecz obiekt typu Optional, w którym może się znajdować dany obiekt, bądź pustego Optionala, gdy nie znajdzie danego obiektu, dzięki temu unikniemy uwielbianego przez wszystkich NullPointerException.

Programistyczna brać radośnie zaczęła go stosować i codebase na całym świecie zalała fala
Optionalemployee = employeeRepository.find("Pawel"); if(employee.isPresent()) { employee.get().giveRiseTo(); }
będąca odpowiednikiem
Employee employee = employeeRepository.find("Pawel");
if(employee != null) {
employee.giveRiseTo();
}
W przypadku wersji z Optional mamy trochę więcej kodu, jednak już przez samo jego użycie w ten prosty sposób mamy zysk – korzystający z funkcji zwracającej obiekt opcjonalny wprost informujemy świat, że obiektu może tam nie być i klient musi sobie jakoś z tym poradzić. No i nie natknie się on na „null-niespodziankę”.
Jednak Optional to nie tylko rozbudowana wersja if’a.
Zacznijmy jednak od początku – czyli jak utworzyć obiekt tego typu.
Opcje mamy aż trzy – metody statyczne klasy Optional .of(), .ofNullable() i .empty().
.of() zwraca Optional z obiektem podanym jako argument,.ofNullable() robi to samo co of, z tą różnicą, że jeśli przesłany jako argument metody obiekt jest nullem, to zwraca ona pustego Optionala,.empty() zwraca Optionala pustego.Tutaj też pojawia się pewien haczyk – jeśli do .of() prześlemy obiekt będący nullem… to dostaniemy optionala wypełnionego, nie pustego, ale obiektem, po rozpakowaniu będzie… null! Więc właśnie zastawiliśmy śliczną pułapkę na przyszłe pokolenia programistów, które odziedziczą nasz kod.
Przejdźmy do kodu, stwórzmy repozytorium pracowników z metodą find, która zwraca pracownika na podstawie imienia, opakowanego w Optional
public class EmployeeRepository {
private static Map employees = new HashMap<>();
static {
employees.put("Pawel", new Employee("Pawel", 30));
}
private EmployeeRepository() { }
public static Optional find(String name) {
return Optional.ofNullable(employees.get(name));
}
}
Klasa Employee jest prostym obiektem domenowym
public class Employee {
private String name;
private int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
}
I teraz w głównej klasie aplikacji możemy pobrać optionala…
public class App {
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Pawel");
}
}
Mamy już nasz obiekt, możemy go więc wykorzystać. Takim podstawowym sposobem jest formułka – .isPresent() -> .get()
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Pawel");
if(employee.isPresent()) {
Employee emp = employee.get();
System.out.println(emp.getName());
}
}
Co wypisze nam imie pracownika.
isPresent() zwróci nam boolean w zależności od tego, czy Optional jest pusty, czy nie. Mamy do dyspozycji również jego lustrzane odbicie – .isEmpty(). Używamy powyżej też metody .get(), która zwróci nam obiekt opakowany w Optional. Należy tu się mieć na baczności, ponieważ jeśli wywołamy na pustym obiekcie .get() zostanie rzucony nam runtime exception, stąd też zawsze należy pamiętać o poprzedzeniu wywołania tej metody sprawdzeniem, czy Optional na pewno jest wypełniony.
Tyle z popularnych podstaw, czas przejść do rzeczy ciekawszych. Po pierwsze powyższe możemy zapisać za pomocą jednej linijki.
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Pawel");
employee.ifPresent(emp -> System.out.println(emp.getName()));
}
Metoda ifPresent() przyjmuje jako argument interfejs funkcyjny Consumer o typie takim samym jak typ Optionala. Consumer posiada jedna metodę – accept, która przyjmuje obiekt i nie zwraca nic. Czyli krótko mówiąc bierze to co jest w Optionalu i coś z tym robi. Jeśli Optional jest pusty to nic się nie dzieje.
Dodatkowo do dyspozycji mamy znany i lubiane z pracy ze strumieniami metody .filter() i .map(), które w wersji dla Optionala nie zwracają strumienia, lecz Optional danego typu. Na przykład:
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Pawel");
Optional employeeName = employee.map(Employee::getName);
employeeName.map(String::toUpperCase).ifPresent(System.out::println);
}
Co robi map to zmienia nam jeden typ obiektu na drugi (korzysta wewnątrz z interfejsu funkcyjnego Function). W naszym wypadku po przemapowaniu pracownika na jego imie dostajemy z Optional – Optional, który następnie możemy ponownie zmapować, by imie pracownika wypisać finalnie wielkimi literami. Dodatkowo umożliwiło nam to korzystanie z referencji do metod. Oczywiście całość możemy (a nawet powinniśmy) zapisać w jednym wyrażeniu.
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Pawel");
employee
.map(Employee::getName)
.map(String::toUpperCase)
.ifPresent(System.out::println);
}
Metoda .filter() sprawdza, czy obiekt w naszym optionalu spełnia dany warunek, możemy rozbudować nasz łańcuch wywołań o wypisanie imienia wielką literą, tylko jeśli nasz pracownik ma ukończone 30 lat.
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Pawel");
employee.
filter(emp -> emp.getAge()>=30)
.map(Employee::getName)
.map(String::toUpperCase)
.ifPresent(System.out::println);
}
Filter przyjmuje jako argument interfejs Predicate, który bierze obiekt o danym typie i zwraca nam boolean – czyli true bądź false.
Pozytywną ścieżkę mamy opanowaną, a co gdy dostaniemy pusty Optional, w którymś momencie… korzystać z .isPresent()?
Na szczęście nie ma takiej potrzeby, ponieważ mamy do dyspozycji metody .orElse(), .orElseGet() oraz .orElseThrow(). Pierwsze dwa z nich są bardzo podobne – jako argument podajemy „domyślną” wartość, gdy Optional będzie pusty. Różnica jest taka, że .orElse() przyjmuje obiekt wprost, natomiast .orElseGet obiekt typu Supplier. Trzecia z metod rzuca po prostu wyjątkiem.
Gdybyśmy chcieli rzucić wyjątkiem jeśli nie znajdziemy pracownika o danym imieniu możemy zrobić to tak:
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Jacek");
employee
.filter(emp -> emp.getAge()>=30)
.map(Employee::getName)
.map(String::toUpperCase)
.orElseThrow(()-> new RuntimeException("Brak odpowiedniego pracownika"));
}
Zmieniliśmy imię pracownika na nieistniejącego – powyższy program rzuci nam RuntimeExcepion. Dużym minusem orElsów jest to, że zwracają nam zawsze obiekt jeśli jednak taki istnieje i wszystko się powiedzie. Z tego wynika, że nie możemy użyć .map().ifPresent().orElseThrow(), bądź na przykład w trakcie wykonywania łańcucha wstrzyknąć domyślnej wartości i na niej wykonywać pozostałe operacje.
Dlatego też jeśli chcemy wpisać imie, które otrzymamy musimy pobrać wynikowego Stringa z optionala i dopisać dodatkowa linijkę.
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Pawel");
String employeeName = employee
.filter(emp -> emp.getAge() >= 30)
.map(Employee::getName)
.map(String::toUpperCase)
.orElseThrow(() -> new RuntimeException("Brak odpowiedniego pracownika"));
System.out.println(employeeName);
}
Dzięki temu zyskujemy pewność, że ten String na pewno istnieje i nie musimy robić nullchecków.
W Javie 9 pojawiły sie trzy nowe metody – .or(), .ifPresentOrElse() i .stream().
Ostatnia z nich jest dość „prosta” – zmienia obiekt opakowany w Optional (jeśli istnieje) w stream, a jeśli nie istnieje, to otrzymujemy pusty strumień. Pozostałe dwie są dla nas o wiele ciekawsze.
.or() wypełnia lukę, o jakiej pisałem powyżej – pozwala przesłać domyślą wartość jeśli w którymś momencie dostaniemy pustego Optionala i kontynuować wykonywanie operacji na niej:
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Jacek");
employee
.or(() -> Optional.of(new Employee("Krzysztof", 40)))
.filter(emp -> emp.getAge() >= 30)
.map(Employee::getName)
.map(String::toUpperCase).ifPresent(System.out::println);
}
Dzięki użyciu .or() przesyłamy do łańcucha wywołań pracownika o imieniu „Krzysztof” jeśli nie znajdziemy pracownika o imieniu „Jacek”.
.ifPresentOrElse() natomiast przyjmuje implementacje dwóch interfejsów – Consumer oraz Runnable. Pierwszy jest odpalany jak standardowy .ifPresent(), natomiast czemu drugim jest Runnable, kojarzony z wątkami? Jest on interfejsem funkcyjnym z jedną metodą (run() ), która nie przyjmuje żadnych argumentów oraz nic nie zwraca. W przypadku .ifPresentOrElse() argument typu runnable jest odpalany, gdy Optional jest pusty – czyli nie mamy nic co możemy przesłać jako argument (a standardowy Consumer tego wymaga). Czyli Runnable ze swoja metoda void run() idealnie się wpasował w potrzebę.
public static void main(String[] args) {
Optional employee = EmployeeRepository.find("Jacek");
employee
.filter(emp -> emp.getAge() >= 30)
.map(Employee::getName)
.map(String::toUpperCase)
.ifPresentOrElse(
employeeName -> System.out.println(employeeName),
() -> System.out.println("Nie znaleziono pracownika")
);
}
Powyższy kawałek kodu wypiszę nam imie pracownika (wielkimi literami), jeśli dany pracownik istnieje, jeśli nie to na standardowe wyjście dostaniemy informację o braku pracownika.
To tyle, jeśli chodzi o użycie klasy Optional z mojej strony. Mam nadzieje, że po przeczytaniu tego artykułu, następnym razem, gdy przyjdzie Tobie z nim pracować (bo już na stałe zagościły w Javie) będziesz pamiętać o .map(), .ifPresent() i pozostałych, dzięki czemu zaoszczędzisz trochę pisania i Twój kod będzie czytelniejszy.
Kod aplikacji dostępny jest na githubie.
Jeśli ten artykuł przypadł Ci do gustu to zapraszam do zasubskrybowania bloga i dostawania na bieżąco informacji o nowych wpisach.
The post Optional i Java – nie tylko isPresent i get appeared first on Dev Foundry.
]]>