Dopasowanie wzorców - początek

softwaregarden.dev 4 lat temu

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żeli 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ć, iż “Java jest przegadana”. Coś może być na rzeczy, bo skoro już w pierwszej linii stwierdziliśmy, iż 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ż, iż 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żeli 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ą”, iż 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żeli 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.

Idź do oryginalnego materiału