Zastępujemy często używane idiomy z Google Guava
Dziś na tapetę trafia klasa Preconditions, która zawiera metody pozwalające na zastąpienie popularnych idiomów i konstrukcji służących, najczęściej, do sprawdzania poprawności parametrów.
Po co używać klasy Preconditions?
W ogólności klasa ta dostarcza metod pozwalających na zamianę konstrukcji typu:
Listing 1. Przykładowy kod bez użycia Preconditions
public void method(String param1, Integer param2) {
if (param1 == null)
throw new NullPointerException("Param1 can not be null");
if (param2 == null)
throw new NullPointerException("Param2 can not be null");
if (param1.isEmpty())
throw new IllegalArgumentException("Param 1 can not be empty");
if (param2 > 0)
throw new IllegalArgumentException("Param 2 can not be
<p>na pozbawiony if-ów czytelniejszy kod.</p>
<p class="listing">Listing 2. Przykładowy kod używający <samp>Preconditions</samp></p>java
public void method(String param1, Integer param2) {
checkNotNull(param1, "Param1 can not be null");
checkNotNull(param2, "Param2 can not be null");
checkArgument(!param1.isEmpty(), "Param 1 can not be empty");
checkArgument(param2 > 0, "Param 2 can not be
<p>Istotna jest tutaj odpowiednia motywacja do takiej zmiany. Ponieważ nieprawidłowo zastosowana klasa może nieźle namieszać. </p>
<h4><samp>Preconditions</samp> to nie walidator</h4>
<p>Kluczowym elementem do prawidłowego zastosowania metod z klasy jest zrozumienie na jakiej zasadzie działają walidatory. Wiele osób popełnia pewien dość prosty, ale bardzo trudny do naprawienia na późniejszym etapie rozwoju aplikacji, błąd. Otóż zapamiętajcie sobie raz na zawsze</p>
<h1>WALIDATOR W PRZYPADKU WPROWADZENIA NIEPOPRAWNYCH DANYCH NIE MA PRAWA RZUCAĆ WYJĄTKIEM</h1>
<p>Dlaczego? Wyjątek jak sama nazwa wskazuje służy do informowania o sytuacji wyjątkowej, takiej której nie można przewidzieć w momencie pisania kodu albo nie można stworzyć prawidłowego i uniwersalnego sposobu obsługi takiej sytuacji. Wpisanie niepoprawnych danych przez użytkownika nie należy do takiej grupy. To, że ktoś podał np. kod pocztowy bez myślnika nie jest niczym wyjątkowym, niczym czego nie możemy obsłużyć czy przewidzieć. </p>
<p>Metody z klasy <samp>Preconditions</samp> wyrzucają wyjątki i nie nadają się do walidacji obiektów. Do czego zatem służą? Otóż służą do sprawdzenia stanu obiektu tam gdzie zazwyczaj używamy połączenia IF i THROW. Dobrym przykładem może być tu kontroler, do którego powinny trafić dane po przeciągnięciu przez walidator w wyższej warstwie. Nie możemy jednak założyć w kontrolerze, że dane te nie trafią do nas w jakiś "magiczny" sposób. Zatem wywołanie dodatkowego sprawdzenia już ze zwróceniem wyjątku jest ekwiwalentem stwierdzenia "koleś ale ty chyba zbłądziłeś z tą taczką kupy".</p>
<h5>Krótko o JSR-305</h5>
<p>Podobną rolę mogą pełnić adnotacje zebrane w ramach JSR-305. Jest tu jednak pewna ważna różnica. Adnotacje powstały z myślą o statycznej analizie kodu pod kątem błędów. Ich dodatkowe zastosowanie jako sposobu na sprawdzenie poprawności parametrów jest fajne lecz wymaga trochę więcej dodatkowej pracy. Generalnie możemy użyć implementacji <a href="http://beanvalidation.org/">Bean Validator 1.1</a> w postaci <a href="http://hibernate.org/validator/">Hibernate Validator 5.x</a> lecz jest to upierdliwe jeżeli nie dysponujemy kontenerem DI. </p>
<p>Po tym wstępie tradycyjny przegląd możliwości klasy.</p>
<h4>Klasa <samp>Preconditions</samp></h4>
<p>Metody występują zazwyczaj w trzech wersjach. W pierwszej przyjmują tylko obiekt albo warunek sprawdzany. W drugiej poza nim przyjmują też obiekt wiadomości. W trzeciej jako drugi argument jest przyjmowany <samp>String</samp> zawierający flagi formatowanie, a kolejne argumenty to wartości do podstawienia do tego napisu. Jest to równoważne użyciu <samp>String.format</samp>.</p>
<h5>Metoda <samp>checkArgument</samp></h5>
<p>Metoda ta przyjmuje jako pierwszy parametr wartość logiczną. Jeżeli będzie ona <samp>false</samp> to rzuca wyjątek <samp>IllegalArgumentException</samp>. </p>
<h5>Metoda <samp>checkElementIndex</samp></h5>
<p>Metoda ta jako pierwsze dwa argumenty przyjmuje indeks obiektu w tablicy, liście, napisie oraz długość tej tablicy, listy, napisu. W przypadku gdy pierwszy z argumentów jest większy bądź równy od drugiego rzuca <samp>IndexOutOfBoundsException</samp>. Jeżeli drugi argument jest negatywny rzuca <samp>IllegalArgumentException</samp>. Metoda nie posiada wersji z listą argumentów do formatowania wiadomości. </p>
<h5>Metoda <samp>checkNotNull</samp></h5>
<p>Jeżeli przekazana referencja jest <samp>null</samp> metoda rzuca NPE. </p>
<h5>Metoda <samp>checkPositionIndex</samp></h5>
<p>Bardzo podobna do wcześniejszej <samp>checkElementIndex</samp> z tą różnicą, że w tym przypadku pierwszy argument może być równy drugiemu. Zatem metoda sprawdza czy pierwszy argument należy do zbioru [0,drugi argument]. Rzuca <samp>IndexOutOfBoundsException</samp>.</p>
<h5>Metoda <samp>checkPositionIndexs</samp></h5>
<p>Metoda ta sprawdza czy wartość przekazana w pierwszym argumencie należy do zbioru [drugi argument, trzeci argument]. Jeżeli nie rzuca <samp>IndexOutOfBoundsException</samp>.</p>
<h5>Metoda <samp>checkState</samp></h5>
<p>Jako argument przyjmuje wartość logiczną. Jeżeli wartość ja jest fałszywa to rzuca <samp>IllegalStateException</samp>.</p>
<h4>Kluczowa sprawa - testy</h4>
<p>Stworzenie kodu, w którym zastąpimy własne IF-y wywołaniami metod i mówiąc najprościej IF-ami bibliotecznymi nie zwalnia nas z obowiązku napisania testów. Możemy jednak ominąć testy związane z naszymi wywołaniami (ograniczyć się do sprawdzenia czy metody są wołane) powodującymi błąd. Magia tego rozwiązania polega na wypchnięciu odpowiedzialności za przetestowanie prawidłowego działania metody do autorów biblioteki. Dla nas ważne jest tylko sprawdzenie czy podajemy prawidłowe parametry.</p>
<p>W ten sposób udało nam się stworzyć troszkę lepszy kod. Każdy nienapisany IF to maleńkie zwycięstwo w walce o jakość... yyy... ale to zabrzmiało...</p>
Kod jest dostępny na licencji MIT. Jednak niektóre rozwiązania mogą być objęte inną licencją. W takim przypadku jest, to zaznaczone. Artykuły są dostępne na licencji CC-BY.
Jeżeli spodobał ci się ten wpis, to podziel się nim z innymi lub wesprzyj autora.