Kurs Java

Java 8 - Wprowadzenie

Java 8 ujrzała światło dzienne 14 marca 2014 roku. Rozwiązania, które przyniosła ze sobą, zmieniły sposób programowania w tym języku. Wprowadzenie modelu opartego na interfejsach funkcyjnych i strumieniowym przetwarzaniu danych pozwoliło na znaczną redukcję ilości kodu. Umiejętne stosowanie nowych rozwiązań powoduje, że kod jest bardziej zwięzły, a w wielu wypadkach staje się zbliżony do języka, którym posługujemy się na co dzień.

Każda kolejna wersja Javy jest jedynie rozwinięciem nowego modelu programowania wprowadzonego w wersji ósmej. Nie znaczy to jednak, że zmiany te są mało istotne. Wręcz przeciwnie. Wiele z nich jest doskonałym uzupełnieniem ósemki, a inne wprowadzają udogodnienia jeszcze bardziej poprawiające komfort pracy z kodem. Z tego powodu dwa ostatnie rozdziały naszego kursu poświęcone są wszystkim nowościom, jakie dotychczas pojawiły się w Javie od wersji 9 do 14.

Co nowego w Javie 8

W Javie 8 wprowadzono wiele całkiem nowych rozwiązań. Oto ich lista wraz z krótkimi zajawkami. Każdy z tematów szeroko rozwijamy w kolejnych rozdziałach kursu:
  • Wyrażenia lambda

    Sposób na budowę bardziej zwięzłego i czytelnego kodu, poprzez definiowanie samych parametrów oraz ciała metody. Taką skróconą formę kodu możemy przypisać do zmiennej, a nawet przesłać do innej metody. Wynika to z tego, że wyrażenie lambda jest obiektem, co prawda bez tak zwanej tożsamości, ale jednak obiektem (więcej o tożsamości w odpowiednim rozdziale). Obrazowo mówiąc, możemy stworzyć obiekt samej operacji do wykonania i taką operację zapisać lub przesłać w inne miejsce programu. Uruchomienie operacji może nastąpić w praktycznie dowolnym miejscu kodu.
    << lista parametrów->  << ciało wyrażenia >>


    Załóżmy, że mamy interfejs Item z jedną bezparametrową metodą getDescription:
    public interface Item {     
        String getDescription();
    } 
    
    Na bazie takiego interfejsu możemy stworzyć obiekt, ale nie za pomocą słowa kluczowego new, lecz za pomocą wyrażenia lambda. Lista parametrów wyrażenia (przy braku parametrów metody wpisujemy tylko puste nawiasy) odpowiada parametrom metody, a ciało wyrażenia zawiera to, co znajduje się w ciele metody. Jest to zupełnie nowy sposób dostarczenia implementacji interfejsu. Ważne jest, aby taki interfejs miał tylko jedną metodę abstrakcyjną.
    public class Start {
    
        public static void main (String[] args) {
    
            Item item = () -> "This is description for MovieItem";
            String description = item.getDescription();
            System.out.println(description);
        }
    }
    
    Wynik wykonania kodu:
    Java 8 Wynik wykonania kodu - Nowości w Javie 8
    W ten sposób tworzymy obiekt (item) definiujący metodę do wykonania bez faktycznego jej uruchamiania. Uruchomienie metody następuje dopiero w wybranym przez nas momencie (item.getDescription()). Nie musi to być następna linia kodu. Taki obiekt możemy przekazać do innych metod w innych klasach i dopiero tam go uruchomić.

    Wszystkie detale dotyczące tego rodzaju interfejsów, jak i samych wyrażeń lambda wyjaśniamy w dedykowanych rozdziałach.

  • Interfejsy funkcyjne

    Wyrażenia lambda mają swój typ i jest nim interfejs funkcyjny (podobnie jak obiekt item ma swój typ i jest nim Item). O typach mówiliśmy już w rozdziale Interfejs jako typ danych, więc jeśli nie pamiętasz o co chodzi, to zachęcamy do przejrzenia jeszcze raz tamtego rozdziału.

    Interfejsy funkcyjne pozwalają na definiowanie różnych rodzajów obiektów, na przykład z jednym parametrem i jedną wartością zwracaną, albo z dwoma parametrami i jedną wartością zwracaną, a także kilka innych kombinacji.

    I tak na przykład wyrażenie lambda z naszego interfejsu Item jest typu Supplier, który jest interfejsem funkcyjnym bez parametrów i z jedną wartością zwracaną. Skoro tak jest, to możemy w kodzie podmienić nasz interfejs i wprowadzić tam typ Supplier, a kod nadal będzie się kompilował. Jedyna rzecz, o której musimy pamiętać, to określenie parametru typu (w tym przypadku String), ponieważ supplier oczekuje, że powiemy mu z jakim typem obiektu będzie pracował.
    import java.util.function.Supplier;
    
    public class Start {
    
        public static void main (String[] args) {
            
            Supplier<String> descriptionSupplier = () -> "This is description for MovieItem";
            System.out.println(descriptionSupplier.get());
        }
    }
    
    Wynik wykonania kodu:
    Java 8 Wynik wykonania kodu - Nowości w Javie 8 - Dalej
    Java 8 wprowadza cały szereg interfejsów funkcyjnych. Wszystkie dokładnie omawiamy w ramach kursu.

  • Referencje do metod

    Referencja do metody jest alternatywną i zarazem skrótową formą zapisu wyrażenia lambda. Także umożliwia zadeklarowanie metody, jaka ma być wywołana na obiekcie, bez faktycznego jej uruchamiania. Niestety nie zawsze możemy jej użyć w zastępstwie wyrażenia lambda. Więcej szczegółów w tym obszarze poznasz w dalszej części kursu.
    public class Start {
    
        public static void main (String[] args) {
            
            Item item = () -> "This is description for MovieItem";
            Supplier<String> descriptionSupplier = item::getDescription;
            System.out.println(descriptionSupplier.get());
        }
    }   
    
    Wynik wykonania kodu:
    Java 8 Wynik wykonania kodu - Wprowadzenie
  • Strumienie

    W Javie 8 pojawia się nowy interfejs Stream, który pozwala na wygodne i efektywne przetwarzanie danych. Strumienie same w sobie nie przechowują danych, a jedynie pozwalają na ich sekwencyjne przetwarzanie. Zerknijmy na bardzo prosty przykład:
    import java.util.Arrays;
    import java.util.List;
    
    public class Start {
    
        public static void main(String[] args) {
        	
            List<String> moviesTitles = Arrays.asList("Parasite", "Joker", "Irlandczyk"); 
            moviesTitles.stream().forEach(movie -> System.out.println(movie));		
        }
    }
    
    Wynik wykonania kodu:
    Java 8 Wynik wykonania kodu - Wprowadzenie 2
    Widzimy listę z tytułami filmów. Następnie na tej liście wywołujemy metodę stream, która to zwraca strumień do danych zawartych w liście. Jedną z metod dostępnych w strumieniach jest metoda forEach, której zadaniem jest przechodzenie po kolejnych obiektach i wykonanie na nich określonej operacji. Metoda jako argument przyjmuje wyrażenie lambda.

    Powyższy przykład jest naprawdę trywialny. Strumienie to potężny mechanizm, za pomocą którego wykonujemy całe mnóstwo operacji w Javie. Poświęcimy temu tematowi aż 6 całych rozdziałów w tym kursie. W kilku kolejnych rozdziałach strumienie pojawią się również przy okazji omawiania innych tematów.

  • Wrapper Optional

    Wrapper, czyli klasa opakowująca inną klasę. W przypadku klasy Optional opakowywana jest wartość, która może być pusta lub nie. Takie rozwiązanie pozwala zastąpić sprawdzanie, czy obiekt jest nullem, czy też nie. Zobaczmy to na prostym przykładzie:
    import java.util.Optional;
    
    public class Start {
    
        public static void main(String[] args) {
        	
            String movie = "Parasite"; 		
            Optional<String> movieOptional = Optional.of(movie);
            if (movieOptional.isPresent()) {
                System.out.println(movieOptional.get());
            }	
        }
    }
    
    Wynik wykonania kodu:
    Java 8 Wynik wykonania kodu - Wprowadzenie 3
    Tworzymy obiekt klasy Optional, który zawiera w sobie referencję do obiektu filmu. Następnie sprawdzamy, czy obiekt jest dostępny w opakowaniu, a jeśli tak, zwracamy ten obiekt. Oczywiście, powyższy przykład jest nieco infantylny, gdyż dobrze widać, że tuż przed sprawdzeniem, tworzymy obiekt movie ("Parasite"). Warto jednak pamiętać, że w większości przypadków, w realnym kodzie, wcale nie jest to takie oczywiste. Na przykład wtedy, gdy dostajemy obiekt klasy Optional jako wynik wywołania konkretnego algorytmu. Bez sprawdzenia nie jesteśmy w stanie określić, czy w środku znajduje się obiekt, czy nie.

    Ten temat jest tak ważny, że poświeciliśmy mu aż 15 stron w specjalnie dedykowanym rozdziale.

  • Nowa obsługa dat

    Powiemy sobie o tym więcej w rozdziałach poświęconych datom, jednak już teraz warto wiedzieć, że daty od Javy 8 są definiowane z rozbudowaną obsługą stref czasowych, a także umożliwiają wykorzystanie wielu dodatkowych, bardzo praktycznych metod. Spójrz:
    import java.time.LocalDateTime;
    
    public class Start {
    
        public static void main(String[] args) {
        	
            LocalDateTime localDateTime = LocalDateTime.now();
            System.out.println(localDateTime);
            System.out.println(localDateTime.plusDays(7).minusHours(3));
        }
    }
    
    Wynik wykonania kodu:
    Java 8 Wynik wykonania kodu - Wprowadzenie 5
    Najpierw pobieramy datę w strefie czasowej naszego systemu (LocalDateTime.now()), potem drukujemy ją na konsoli, a następnie dodajemy do niej 7 dni oraz odejmujemy 3 godziny. Wydruk pokazuje zmodyfikowaną datę.

Oprócz tematów z powyższej listy opiszemy kilka innych zmian, jak na przykład nowe metody w kolekcjach i mapach. Przedstawimy też ciekawe, złożone rozwiązania, takie jak tworzenie własnej biMapy. Zapraszamy!
Masz pytanie dotyczące tego rozdziału? Zadaj je nam!
Masz pytanie dotyczące prezentowanego materiału?
Coś jest dla Ciebie niejasne i Twoje wątpliwości przeszkadzają Ci w pełnym zrozumieniu treści?
Napisz do nas maila, a my chętnie znajdziemy odpowiednie rozwiązanie.
Najciekawsze pytania wraz z odpowiedziami będziemy publikować pod rozdziałem.
Nie czekaj. Naucz się programować jeszcze lepiej.
kursjava@javappa.com

Stale się rozwijamy, a więc bądź na bieżąco!
Na ten adres będziemy przesyłać informacje o ważniejszych aktualizacjach, a także o nowych materiałach pojawiających się na stronie.
Polub nas na Facebooku:
Nasi partnerzy: stackshare
Javappa to również profesjonalne usługi programistyczne oparte o technologie JAVA. Jeśli chesz nawiązać z nami kontakt w celu uzyskania doradztwa bądź stworzenia aplikacji webowej powinieneś poznać nasze doświadczenia.
Kliknij O nas .


Pozycjonowanie stron: Grupa TENSE