Paweł Ćwik – Dev Foundry http://devfoundry.pl programowanie • java • spring • kursy Thu, 13 May 2021 15:17:56 +0000 pl-PL hourly 1 https://wordpress.org/?v=5.0.16 http://devfoundry.pl/wp-content/uploads/2018/05/cropped-DEVfoundry_SYMBOL_512x512-32x32.png Paweł Ćwik – Dev Foundry http://devfoundry.pl 32 32 Modyfikatory dostępu w języku Java http://devfoundry.pl/modyfikatory-dostepu-w-jezyku-java/ http://devfoundry.pl/modyfikatory-dostepu-w-jezyku-java/#respond Mon, 06 Jul 2020 13:40:10 +0000 http://devfoundry.pl/?p=1190 Jednym z częstych pytań dla osób starających się o pozycję junior java developera jest pytanie o modyfikatory dostępu, jakie są dostępne w języku Java oraz jak zachowuję się domyślny z nich. 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 ...

Czytaj dalej...Modyfikatory dostępu w języku Java

The post Modyfikatory dostępu w języku Java appeared first on Dev Foundry.

]]>
Jednym z częstych pytań dla osób starających się o pozycję junior java developera jest pytanie o modyfikatory dostępu, jakie są dostępne w języku Java oraz jak zachowuję się domyślny z nich.

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.

]]>
http://devfoundry.pl/modyfikatory-dostepu-w-jezyku-java/feed/ 0
Różnice pomiędzy final, finally, a finalize http://devfoundry.pl/roznice-pomiedzy-final-finally-a-finalize/ http://devfoundry.pl/roznice-pomiedzy-final-finally-a-finalize/#respond Thu, 16 Apr 2020 08:04:03 +0000 http://devfoundry.pl/?p=1206 Jednym z pytań pojawiających się podczas rozmowy kwalifikacyjnej na pozycje młodszego programisty jest to, o różnice pomiędzy działaniami słów kluczowych 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 ...

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.

]]>
Jednym z pytań pojawiających się podczas rozmowy kwalifikacyjnej na pozycje młodszego programisty jest to, o różnice pomiędzy działaniami słów kluczowych 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.

]]>
http://devfoundry.pl/roznice-pomiedzy-final-finally-a-finalize/feed/ 0
Praca z Optional w Hibernate http://devfoundry.pl/optional-hibernate/ http://devfoundry.pl/optional-hibernate/#comments Wed, 12 Feb 2020 11:35:38 +0000 http://devfoundry.pl/?p=967 Typ 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. Problem z typami opcjonalnymi 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; ...

Czytaj dalej...Praca z Optional w Hibernate

The post Praca z Optional w Hibernate appeared first on Dev Foundry.

]]>
Typ 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.

Problem z typami opcjonalnymi

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.


Jeśli chcesz prześledzić rozwiązanie krok po kroku w formie wideo, to zapraszamy na nasz kanał na YouTube.


Rozwiązanie

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.

]]>
http://devfoundry.pl/optional-hibernate/feed/ 1
GitHub – Podstawy http://devfoundry.pl/github-podstawy/ http://devfoundry.pl/github-podstawy/#comments Mon, 17 Sep 2018 09:40:08 +0000 http://devfoundry.pl/?p=741 W tym wpisie omówimy podstawy GitHub, czyli najpopularniejszej obecnie platformy do przechowywania i upubliczniania swojego kodu. Zobaczymy jak wrzucić tam swój kod i jakie możliwości oferuje sama platforma. GitHub jest miejscem, w którym możemy przechowywać nasze repozytoria gitowe ( git + hub 🙂 ) , 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 ...

Czytaj dalej...GitHub – Podstawy

The post GitHub – Podstawy appeared first on Dev Foundry.

]]>
W tym wpisie omówimy podstawy GitHub, czyli najpopularniejszej obecnie platformy do przechowywania i upubliczniania swojego kodu. Zobaczymy jak wrzucić tam swój kod i jakie możliwości oferuje sama platforma. GitHub jest miejscem, w którym możemy przechowywać nasze repozytoria gitowe ( git + hub 🙂 ) , 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.

Utworzenie lokalnego repozytorium Git

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.


Jeśli chcesz prześledzić zmiany krok po kroku w formie wideo, to zapraszamy na nasz kanał na YouTube.


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

Podstawy GitHub

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:

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

Dokonywanie zmian

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.

]]>
http://devfoundry.pl/github-podstawy/feed/ 6
Zapis i odczyt plików w Java 7+ http://devfoundry.pl/zapis-i-odczyt-plikow-w-java-7/ http://devfoundry.pl/zapis-i-odczyt-plikow-w-java-7/#respond Wed, 15 Aug 2018 11:57:33 +0000 http://devfoundry.pl/?p=660 Historycznie praca z plikami w Javie nie była niczym przyjemnym – duża ilość kodu związanego z buforami, brak wygodnego API dostępowego do samych plików, już nie wspominając o operacjach na nich. Na szczęście wszystkie te bolączki przestały istnieć, kiedy wprowadzona została Java 7 wraz z pakietem zmian pod egidą NewIO 2. Java 8 wraz ze strumieniami tylko polepszyła dobry stan rzeczy. Jako że post jest pisany w odpowiedzi na życzenie jednego z naszych czytelników, to jako przykład weźmiemy przypadek użycia zaproponowany przez ...

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.

]]>
Historycznie praca z plikami w Javie nie była niczym przyjemnym – duża ilość kodu związanego z buforami, brak wygodnego API dostępowego do samych plików, już nie wspominając o operacjach na nich. Na szczęście wszystkie te bolączki przestały istnieć, kiedy wprowadzona została Java 7 wraz z pakietem zmian pod egidą NewIO 2. Java 8 wraz ze strumieniami tylko polepszyła dobry stan rzeczy. Jako że post jest pisany w odpowiedzi na życzenie jednego z naszych czytelników, to jako przykład weźmiemy przypadek użycia zaproponowany przez Niego. Mianowicie: mamy plik tekstowy zawierający informację o obiekcie, następnie wczytujemy ten plik, tworzymy nowy obiekt na jego podstawie, modyfikujemy go, a finalnie zapisujemy jako nowy plik, tym razem w formacie JSON.

NewIO 2 – odczyt pliku w Java 7

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 +
                '}';
    }

}

Jeśli chcesz prześledzić zmiany krok po kroku w formie wideo, to zapraszamy na nasz kanał na YouTube.


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.

]]> http://devfoundry.pl/zapis-i-odczyt-plikow-w-java-7/feed/ 0 Multicatch wyjątków w języku Java http://devfoundry.pl/multicatch-wyjatkow-w-jezyku-java/ http://devfoundry.pl/multicatch-wyjatkow-w-jezyku-java/#respond Wed, 18 Jul 2018 07:08:13 +0000 http://devfoundry.pl/?p=468 W tym wpisie pokażę jak można przechwytywać wiele wyjątków naraz, gdy chcemy je obsługiwać w ten sam sposób. Jest to tak zwany multicatch i jest on dostępny również w Javie, począwszy od wersji 7. 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); } } Jeśli chcesz ...

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.

]]>
W tym wpisie pokażę jak można przechwytywać wiele wyjątków naraz, gdy chcemy je obsługiwać w ten sam sposób. Jest to tak zwany multicatch i jest on dostępny również w Javie, począwszy od wersji 7.

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);
   }
}

Jeśli chcesz prześledzić zmiany krok po kroku w formie wideo, to zapraszamy na nasz kanał na YouTube.


Multicatch przed Javą 7

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.

Multicatch i Java 7+

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.

Podsumowanie

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.

]]>
http://devfoundry.pl/multicatch-wyjatkow-w-jezyku-java/feed/ 0
Spring Data – @Query http://devfoundry.pl/spring-data-query/ http://devfoundry.pl/spring-data-query/#comments Wed, 20 Jun 2018 06:50:45 +0000 http://devfoundry.pl/?p=222 Jednym z głównych modułów frameworka Spring jest moduł Spring Data, dzięki któremu możemy zminimalizować niemal do zera ilość tak zwanego „boiler-plate” kodu przy tworzeniu znanych z Domain Driven Design repozytoriów. DDD jest podejściem do tworzenia obiektowego modelu naszej aplikacji, natomiast repozytoria są to klasy, które odpowiadają za pobieranie obiektów domenowych z zewnętrznego źródła danych, dodatkowo również tam umieszcza się różnorakie metody odpowiadające za zwracanie obiektów spełniających dane kryteria. Mówiąc jeszcze prościej – repozytoria odpowiadają za obsługę operacji typu CRUD (zestawu ...

Czytaj dalej...Spring Data – @Query

The post Spring Data – @Query appeared first on Dev Foundry.

]]>
Jednym z głównych modułów frameworka Spring jest moduł Spring Data, dzięki któremu możemy zminimalizować niemal do zera ilość tak zwanego „boiler-plate” kodu przy tworzeniu znanych z Domain Driven Design repozytoriów. DDD jest podejściem do tworzenia obiektowego modelu naszej aplikacji, natomiast repozytoria są to klasy, które odpowiadają za pobieranie obiektów domenowych z zewnętrznego źródła danych, dodatkowo również tam umieszcza się różnorakie metody odpowiadające za zwracanie obiektów spełniających dane kryteria. Mówiąc jeszcze prościej – repozytoria odpowiadają za obsługę operacji typu CRUD (zestawu podstawowych operacji bazodanowych – Create, Read, Update, Delete) dla danego obiektu domenowego.

Utworzenie projektu

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


Jeśli chcesz prześledzić zmiany krok po kroku w formie wideo, to zapraszamy na nasz kanał na YouTube.


Utworzenie obiektu domenowego i repozytorium

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.

Proste wyszukiwania bazodanowe

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

Własne metody wyszukiwania

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.

]]>
http://devfoundry.pl/spring-data-query/feed/ 4
Optional i Java – nie tylko isPresent i get http://devfoundry.pl/optional-java-pl/ http://devfoundry.pl/optional-java-pl/#comments Wed, 23 May 2018 15:59:43 +0000 http://devfoundry.pl/?p=165 Czym jest Optional? 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, ...

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.

]]>
Czym jest Optional?

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.

optional dev foundry blog programowanie java spring kursy


Jeśli chcesz prześledzić zmiany krok po kroku w formie wideo, to zapraszamy na nasz kanał na YouTube.


Programistyczna brać radośnie zaczęła go stosować i codebase na całym świecie zalała fala

Optional employee = 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.

Tworzenie

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");
    }
}

Podstawy

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.

Rzeczy ciekawsze

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 OptionalOptional, 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()?

Gdy Optional jest pusty

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.

Java 9

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.

Podsumowanie

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.

]]>
http://devfoundry.pl/optional-java-pl/feed/ 2