Pisząc kod w javie i tworząc nowe klasy, często potrzebujemy napisać metody, które są praktycznie prawie takie same dla różnych klas. Na przykład, mając:
1public class User { 2private String username; 3private String email; 4}
Czyli zwykłą małą klasę trzymającą dane o użytkowniku, zapewne będziemy potrzebować utworzyć:
- konstruktory (domyślny i z parametrami)
- gettery i settery
- equals i hashcode
- toString
Zatem, nasza mała klasa rozrasta się z kilku linii do aż 60 (na rzecz czytelności artykułu, pominę wygenerowany przez IDE kod). Pomimo rozrostu, nie dodaliśmy żadnej logiki biznesowej. Nic to nie wniosło. Taki kod nazywamy boilerplate code – czyli kod, który nic nam nie wnosi, ale jest potrzebny do napisania, żeby aplikacja działała.
Lombok
Z pomocą przychodzi nam biblioteka lombok, która generuje owy boilerplate code na podstawie użytych adnotacji. Żeby zacząć korzystać z lomboka, dodajemy jego zależność:
1<dependency> 2<groupId>org.projectlombok</groupId> 3<artifactId>lombok</artifactId> 4</dependency>
Jeśli nie korzystamy ze Spring Boota, potrzebne nam będzie również dodanie wersji. Ekwiwalent 60 linijkowej klasy możemy zapisać teraz z pomocą kilku samowyjaśniających się adnotacji:
1@AllArgsConstructor 2@NoArgsConstructor 3@Getter 4@Setter 5@EqualsAndHashCode 6@ToString 7public class User { 8private String username; 9private String email; 10}
Jak widać, zaoszczędziliśmy wiele linijek kodu. Poszliśmy w stronę programowania deklaratywnego – mówimy, co chcemy mieć zrobione (używając adnotacji), a nie jak to ma być zrobione.
Przybyło jednak adnotacji – możemy użyć nawet „pewnego zbioru” adnotacji, jak np na poniższym przykładzie:
1@AllArgsConstructor 2@NoArgsConstructor 3@Data 4public class User { 5private String username; 6private String email; 7}
@Data zawiera w sobie @Getter, @Setter, @RequiredArgsConstructor, @ToString oraz @EqualsAndHashCode.
Również przydatną rzeczą jest @Builder – dzięki temu, będziemy mieć dostarczony builder pattern przy tworzeniu obiektów danej klasy.
Lombok – wady
No dobrze, nie mamy boilerplate kodu – czy są zatem jakieś wady?
Pierwszą, o której się pomyśli, to brak możliwości debugowania – nie postawisz breakpointa na adnotacji i nie zobaczysz parametrów metody. Okej – można wykonac proces tzw. delombok, i postawić breakpointa w wygenerowanym kodzie, ale wtedy cała zabawa zaczyna tracić sens. Mając zbiór adnotacji (potocznie, pejoratywnie, można to nazwać annotation driven development) łatwo pogubić się w tym gąszczu – np mając tak oznaczoną klasę:
1@Data 2@Value 3public class User { 4private final String username; 5private final String email; 6}
Nie od razu widzimy, które metody są wygenerowane, a które nie. Dopiero później możemy się przekonać, że @Value zawiera w sobie @AllArgsConstructor, @Data zawiera w sobie @RequiredArgsConstructor, natomiast w tym wszystkim brakuje nam... @NoArgsConstructor, czyli konstruktora domyślnego. Jaki może być tego skutek? Niektóre biblioteki do serializacji / deserializacji, jak np Jackson, wymagają konstruktora domyślnego – w przeciwnym wypadku, na konstruktor z parametrami należy nanieść stosowną adnotację. Niestety, wyjdzie to dopiero w runtimie...
Podsumowanie
Jak widać, stosowanie lomboka pozwala znacząco zredukować boilerplate code i tym samym przyspieszyć proces wytwarzania oprogramowania oraz zwiększyć czytelność kodu. Jednak nie zapominajmy o rozsądku, żeby pewnego dnia nie znaleźć się w gąszczu samych adnotacji, ponieważ w przypadku jakiegoś błędu, namierzenie jego przyczyny jest dużo trudniejsze.