Wybór języka

Dopasowanie wzorców - początek

Java 14 zawiera wiele nowości. Jedną z nich (jako preview feature) jest dopasowywanie wzorców z instanceof (ang. pattern matching with instanceof). Ludzie programujący w językach wspierających paradygmat funkcyjny, np. w Scali, w Kotlinie (o Haskellu nie wspominając), w pierwszym odruchu widzą oczyma duszy swojej od razu piękne wyrażenie match / when, wyłuskiwanie danych, strażniki, dekonstruktory w obiektach stowarzyszonych itd. Apetyt mamy wielki. Od czasu Javy 9 i wydań co 6 miesięcy raczej przeszliśmy na metodę małych kroczków (lub, wedle uznania, powolnego gotowania żaby). I pierwszym takim małym kroczkiem, który jawnie zawiera nazwę “dopasowanie wzorców” jest JEP 305: Pattern Matching for instanceof (Preview). (Inna sprawa czy wyrażenia switch nie są wcześniejszą próbą rozpalenia ognia pod tą żabą, ale w nazwie JEPy nic o “dopasowywaniu” nie mają.)

Dopasowanie po typie

W mojej ocenie ten JEP poza bycia miłym dobrego początkiem pozwala na eliminację zbędnego i “oczywistego kodu”. Rzućmy okiem™ na poniższy kod, w którym sprawdzamy, czy object to Integer i jeśli tak, to podwajamy go:

1if (object instanceof Integer) {
2    Integer integer = (Integer) object;
3    int doubled = integer * 2;
4    //tutaj coś dalej robimy z doubled...
5}

Linia 2. z powyższego przykładu jest dla wielu osób dość kontrowersyjna oraz (bądźmy szczerzy) stanowi powód, by twierdzić, że “Java jest przegadana”. Coś może być na rzeczy, bo skoro już w pierwszej linii stwierdziliśmy, że to musi być Integer, to czy to rzutowanie rzeczywiście jest takie konieczne? Nie można wykorzystać object od razu w linii 2. jak Integer. “No przecież wiem już, że to jest Integer, wpuściłeś mnie w ten if, o co jeszcze ci chodzi??!!1jeden”

Na ratunek od Javy 14 śpieszy wspomniany wcześniej JEP 305. Dzięki niemu powyższy kod możemy teraz zapisać tak:

1 if (object instanceof Integer integer) {
2     
3     int doubled = integer * 2;
4     //tutaj coś dalej robimy z doubled...
5 }
6 

Co się stało się z drugą linią? Ano rzutowanie nie jest teraz już potrzebne. Teraz zamiast rzutowania wystarczy zapis instanceof <Klasa> dokończyć nazwą, która w bloku będzie nazwą zmiennej dla obiektu, jeśli przejdzie on dopasowanie do <Klasy>. W naszym przypadku object został z powodzeniem dopasowany do Integer, dlatego w bloku będzie widoczny jako Integer integer. Taki jakby “alias po rzutowaniu”. I rzutowanie nie jest już potrzebne.

Podbijamy stawkę

To nie koniec atrakcji. Do akcji wkracza bowiem wykorzystanie dopasowanego obiektu już w warunku if. Załóżmy taką “potrzebę biznesową”, że podwajamy tylko liczby ujemne. Po staremu trzeba to napisać tak:

1if (object instanceof Integer) {
2    Integer integer = (Integer) object;
3    if (integer < 0) {
4        int doubled = integer * 2;
5        //tutaj coś dalej robimy z doubled...
6    }
7}

W takim wypadku, poza znanym nam już rzutowaniem z linii 2., trzeba jeszcze zagnieździć kolejne sprawdzenie. Zaczyna się robić paskudnie, prawda? Można ten kod “czyścić”, można wydzielać metodę do podwajania itd. Albo można wykorzystać JEP 305 jeszcze bardziej i zapisać to tak:

1if (object instanceof Integer integer && integer < 0) {
2
3
4    int doubled = integer * 2;
5    //tutaj coś dalej robimy z doubled...
6    
7}

Tym razem zniknęły dwie/trzy linie (zależy jak liczyć i formatować kod), ale przede wszystkim zniknęło nam zagnieżdżenie kolejnego bloku! (Celowo zostawiłem puste linie dla lepszej czytelności przykładu i unaocznienia absencji tychże linii. Normalnie nikt tak nie będzie pisał…)

Parafrazując: chcemy podwajać nasz obiekt, jeśli pasuje do wzorca: “to jest liczba całkowita i do tego ujemna”. Stąd ten JEP nazywa się “dopasowywanie do wzorca z instanceof”.

W kolejnych wersjach Javy czekają nas bardziej wysublimowane formy dopasowań, z wyłuskiwaniem i innymi atrakcjami. Do tego czasu zachęcam do zabawy tym, co już jest. Na przykład tym przykładem.

O tym, jak moim zdaniem nie wykorzystywać dopasowania wzorców z instanceof, napisałem w kolejnym wpisie.

Wybór języka