Diversity w polskim IT
Grzegorz Szymecki
Comarch
Grzegorz SzymeckiSoftware Developer @ Comarch

Mało znane, a przydatne funkcje Javy

Poznaj 7 funkcji Javy, których prawdopodobnie nie znasz, a ułatwią Ci życie.
23.11.20224 min
Mało znane, a przydatne funkcje Javy

Pracując jako programiści, latami szlifujemy swoje umiejętności, poznajemy nowe technologie, uczymy się nowych metodyk, napotykamy nowe frameworki i środowiska. Ciągły napływ wiedzy sprawia, że zaniedbujemy rozwój w dziedzinie podstawowego narzędzia, jakim się posługujemy, którym jest język programowania. Warto trochę zwolnić i odkryć albo przypomnieć sobie mniej znane funkcjonalności, których na co dzień w kodzie nie znajdziemy, a których znajomość na pewno nam się przyda.

Comparator to nie jest już prosty interface

Możliwe, że wielu osobom umknął fakt rozbudowy interface’u Comparator wraz z pojawieniem się Javy 8. Zaszyty został w nim zbiór statycznych oraz domyślnych metod, z których pomocą jesteśmy w stanie w zwięzły sposób skonstruować obiekt z kilkoma kryteriami porównywania. Wykorzystując wspomniane metody, łącząc je w łańcuchy wywołań, możemy pisać czysty kod, bez potrzeby tworzenia własnych implementacji wspomnianego interface’u. To rozwiązanie znajduje zastosowanie m.in. w strumieniach oraz implementacjach metody compareTo z interface’u Comparable.

Comparator<Article> articlesComparator = Comparator
        comparing(Article::getTitle)
        thenComparing(Article::getCreationTime);

Jak nie zostać zaskoczonym przez przekroczenie zakresu liczby całkowitej

Dużym problemem w Javie przy pracy na prostych typach liczbowych jest domyślny mechanizm wykrywania sytuacji, gdzie przekroczony został zakres ich wartości. W następstwie może to prowadzić do trudnych do zidentyfikowania nieprawidłowości w działaniu aplikacji. Jedynym skutkiem takiego błędu jest niewłaściwa wartość liczbowa, co wykrywane jest zwykle przez przypadek, a znalezienie przyczyny wymaga solidnej analizy ze strony programistów.

Wraz z wprowadzeniem Javy w wersji 8 zostaliśmy wyposażeni w narzędzia pomagające uniknąć takich problemów. Modyfikacjom uległa klasa Math, którą wzbogacono o zestaw statycznych metod posiadających w nazwie słowo „exact” wykonujących podstawowe operacje na typach numerycznych, rzucających ArithmeticException w przypadku wystąpienia wspomnianej sytuacji.

int x = Integer.MAX_VALUE;
int y = 1;
int result = Math.addExact(x, y);

// java.lang.ArithmeticException: integer overflow

Generyczna „kombinacja” typów

To jedna z najstarszych funkcjonalności na tej liście. Na temat typów generycznych oraz sposobów ich wykorzystania napisano już wiele artykułów. Sprawiają one nie tylko, że kod staje się uniwersalny, ale także pozwalają uniknąć wielu problemów już na etapie jego pisania. Konkretyzuje się je z użyciem słowa kluczowego „extends”, po którym dopisuje się wybrany typ. Tutaj dochodzimy do kluczowej kwestii, o której wielu programistów zapomina. Możemy przecież rozwinąć drugą składową, tworząc kombinację typów scalanych przez ampersand „&”. Istnieje tu jednak pewne ograniczenie. Do grupy może wchodzić maksymalnie jedna, opcjonalna klasa oraz kilka interface’ów.

public class Article implements PagesNumberProvider, CreationTimeProvider, Serializable {
    // ...
}

public class GenericMethodInvoker {

    public <T extends PagesNumberProvider & CreationTimeProvider> boolean perform(T objectToProcess) {
        // ...
    }

}

Article article = new Article(...);
boolean result = new GenericMethodInvoker().perform(article);

Długie liczby w czytelnej formie

Wszystko, co poprawia czytelność pisanego kodu, zasługuje na pochwałę. Zgodzi się z tym każdy doświadczony programista. Często jednak determinują to niepozorne funkcjonalności. Jedną z nich jest wprowadzona w Javie 7 możliwość użycia „podkreślników” przy zapisywaniu wartości liczbowych. Skromny dodatek ma ogromny wpływ na czytelność kodu. Bardzo często o nim zapominamy, a w rzeczywistości jego potencjał wydaje się nie zawsze w pełni wykorzystywany. Mając przed oczami dwa zapisy 1000000000 oraz 1_000_000_000 bez dwóch zdań, głowa szybciej przyswoi ten, zapisany w drugiej formie.

int number01 = 1000000000;
int number02 = 1_000_000_000

Statystyki na wyjściu strumieni

Strumienie zaraz po wprowadzeniu odcisnęły piętno na sposobie obsługi zbiorów danych w Javie. Pozwalają zwięźle zapisywać sekwencje operacji z zastosowaniem interfejsów funkcyjnych. Kod, który kiedyś był bardzo rozbudowany, teraz można zmieścić w zgrabnej, czytelniejszej formie.

Jedną z najczęściej używanych metod, kończących pracę na strumieniu, jest „collect”, która między innymi występuje w wersji, gdzie jako parametr przyjmuje interface Collector. Obiekt dostarczamy tutaj zazwyczaj z użyciem fabryki Collectors, która posiada zbiór rzadko wykorzystywanych metod, rozpoczynających się od słowa summarizing, dostarczających obiekty statystyk dla wartości liczbowych. Ich mała popularność wiąże się z tym, że rzadko spotykane są sytuacje, gdy takie rozwiązanie jest przydatne, co nie zmienia faktu, że warto zdawać sobie sprawę z dostępności takiej funkcjonalności.

IntSummaryStatistics statistics = Stream.of(article01, article02)
        .collect(Collectors.summarizingInt(Article::getPagesNumber));

// IntSummaryStatistics{count=2, sum=211, min=95, average=105,500000, max=116}

Uproszczenie dla operujących na bitach

Teraz czas na temat, który może ułatwić życie osobom mającym często do czynienia z operacjami na bitach. Z pomocą przychodzi klasa BitSet, która w aktualnej formie przedstawiona została wraz z wprowadzeniem Javy 1.4. Używając jej, można zrezygnować z czystych wartości numerycznych, modyfikowanych przez operatory bitowe na rzecz obiektów i metod w nich zawartych. BitSet to w rzeczywistości wektor złożony z wartości boolean. Wyróżniają go metody typowe dla operacji na bitach jak „and”, „or” czy „xor”. Po więcej szczegółów odsyłam do dokumentacji.

BitSet bits01 = BitSet.valueOf(new byte[]{1, 0, 1});
BitSet bits02 = BitSet.valueOf(new byte[]{0, 1, 1});
bits01.xor(bits02);

Objects - mała klasa, wielkie możliwości

Java w wersji 7 dostarczyła nam klasę pomocniczą o nazwie Objects. Jej popularność jest zdecydowanie odwrotnie proporcjonalna do możliwości. Zapewnia nam proste rozwiązania powszechnie spotykanych problemów oraz sprawia, że nasz kod staje się dużo bardziej przyjazny dla oka. Podstawowy zbiór jej metod pozwala m.in. obliczyć hash code dla instancji wybranej klasy bądź całego zbioru, czy też wykonać compare dla dwóch obiektów. W późniejszych wersjach Javy klasa została rozszerzona o metody sprawdzające, czy referencja nie jest nullem.

articles.stream()
        .map(Article::getCreationTime)
        .filter(Objects::nonNull)
        .collect(Collectors.toSet());

Podsumowanie

Jak widzicie Java, poza „oklepanymi” funkcjonalnościami, posiada także takie, które nie są zbytnio popularne w powszechnie spotykanym kodzie. Ich znajomość nie jest obowiązkowa, natomiast znacznie ułatwia i przyspiesza pracę, a jak wiadomo, współcześnie czas jest wartością deficytową. Mam nadzieję, że chociaż jedna z powyższych porad zostanie przez Was wykorzystana i pomoże Wam w pracy.

<p>Loading...</p>