Projekt Lombok, czyli mniej kodu

Ile mniej? Dużo mniej. Jednak po kolei. W C# jeżeli tworzymy sobie obiekt reprezentujący jakieś dane to zazwyczaj robimy to tak:

Listing 1. klasa Customer w C#

using System;

public class Customer
{
    private int m_id = -1;

    public int ID
    {
        get
        {
            return m_id;
        }
        set
        {
            m_id = value;
        }
    }

    private string m_name = string.Empty;

    public string Name
    {
        get
        {
            return m_name;
        }
        set
        {
            m_name = value;
        }
    }
}

Generalnie można zdefiniować takie dziwne twory zamiast normalnych getterów i setterów.
W javie taka sama konstrukcja wygląda w następujący sposób:

Listing 2. klasa Customer w Javie

public class Customer {
	private long id;
	private String name;

	public long getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public void setId(long id) {
		this.id = id;
	}

	public void setName(String name) {
		this.name = name;
	}

}

Kodu jest trochę… jeżeli do tego dołożymy konstruktor (z założeniem, że settery zamieniamy na final), metody toString(), equals(), hashCode() to klasa nam tyje. Tyje bardzo ponieważ proste dwa pola „produkują” około 70 linii kodu. Zajebiście by było mieć feature podobny do tego z C#, czyli zdefiniować sobie bloki get i set… tyle tylko, że my piszemy w javie i jesteśmy lepsi. Nasze featury są bardziej zajebiste i generalnie bardziej tru Clean Code. My zrobimy to wszystko za pomocą JEDNEGO słowa. tak moi drodzy, te wszystkie nie fajne metody zamienimy na jedno słowo,a dokładnie na jedną adnotację, która „odwali” za nas brudną robotę związaną z tworzeniem tego kodu.

… a ósmego dnia stworzył Pan Lombok

Wykorzystamy do tego bibliotekę Lombok, która jest moim skromnym zdaniem najbardziej zajebistym rozwiązaniem w świecie Java od czasu pierwszej wersji Springa.
Dlaczego zapytacie… ano dlatego:

Listing 3. klasa Customer w Javie z Lombokiem

@Data
public class Customer {
	private long id;
	private String name;
}

Klasa z 20 linii „schudła” do 5. Do tego ma wszystkie wymagane w tej wersji funkcjonalności tzn. gettery i settery. Jeżeli zamienimy pola na final to otrzymamy jeszcze konstruktor, który będzie przyjmował parametry w kolejności deklaracji pól. Do tego nic, ale to nic się nie wyjebie. Ani Eclipse, ani NetBeans, ani Maven nie będa pyskować, że im kodu brakuje. Życie jest piękne…

No nie do końca oczywiście, ponieważ by to wszystko działało potrzeba Javy 6. Chyba jednak przesiadka na 6stkę to niska cena za ten piękny i czysty kod.

19 myśli na temat “Projekt Lombok, czyli mniej kodu

  1. W C# mozna isc o krok dalej i zdefiniowac przykladowa klase tak:

    public class Customer
    {
    public int ID { get; set; }
    public string Name { get; set; }
    }

  2. O właśnie… coś w ten deseń mi się po głowie szwendało. Wiedziałem, że jest nie wiedziałem jak wygląda.

  3. W C# chyba powinno być tak:

    class Customer
    {
    int ID { get; set; }
    string Name { get; set; }
    }

    W C# z tego co się orientuję klasy domyślnie są internal (widoczność na poziomie podzespołu/assembly). Reszta bodajże domyślnie jest prywatna, poza tymi geterami i seterami, które domyślnie są publiczne (co mniej więcej jest logiczne). No, ale może się mylę, bo C# dopiero się uczę od grudnia 2010, a w javie siedzę dłużej 🙂 Bardzo spodobał mi się projekt Lombok, tylko pasuje mi doczytać konkretne przypadki np. co kiedy chcę mieć tylko getera (ale to już pewnie na stronie projektu znajdę).

  4. Adnotacje @Getter i @Setter. @Date jest kompleksowa, bo dostarcza gettery, settery, konstruktor i kilka innych dupereli w ramach jednego rozwiązania.

  5. pytanie czy w taim przypadku
    public class Customer {
    public long id;
    public String name;
    }
    nie będzie „tak samo” dobre

  6. Podczas instalacji napisało mi, że w Netbeans 6.9 siedzi to już „out of the box”, tylko trzeba odpowiednie opcje włączyć w preferencjach. Adnotacji jest więcej, np. @Cleanup, która zamyka zasoby np. strumienie (zamiast close()). Nawet nie wiem czy jest to w obecnych buildach javy 7 (planowo ma być).

  7. @Mariusz
    pewnie dlatego, że biblioteka powinna sama rozpoznać w tym momencie że potrzebujemy getterów i setterów :). Wygodniejsza forma.

    A co do samego Lomboka, to czy da sie modyfikować zwracane wartości? Bo np. w C# moge sobie zrobić
    int somevalue;
    int Somevalue{ get { return somevalue * 2; } set {somevalue = value;} }

    Somevalue = 50;
    return Somevalue; <– zwróci nam 100

    czy da sie w Lomboku modyfikować zwracane/przypisywane wartości?

  8. co z refaktoryzacją takiego kodu?
    Czy IDE wspierają np. zmianę nazw zmiennych?

  9. @Pedro, w przypadku pól nie finalnych tak. W przypadku pól finalnych, które są lepsze, a dlaczego to inna dyskusja, oczywiście Lombok jest wygodniejszy.

    @Mariusz, co do NB to nie używam, a podałem info z ich strony tylko. Dzięki za prezentację.

    @Pilak, weź mi idź z tym kodem 😀 takie coś tylko w c#. Jeżeli ustawiam 50 to ma być 50, a nie 100. To jest błędny kod z samego założenia. Jeżeli chcesz podwajać wartość przy zwracaniu to powinieneś jasno to napisać i dodać odpowiednią metodę.

    @Kamil, co do refaktoryzacji to zmiana nazwy pola w Eclipse nie pociągała za sobą zmiany nazw metod (w Galileo przynajmniej), teraz pociąga. Trzeba będzie sprawdzić.

  10. Lombok fajna zabawka jest, uprzedzam, ze tak wygenerowanych metod nie da sie owijac za pomoca AspectJ …

  11. @Leszek, ale chyba tylko w przypadku weaveringu w czasie kompilacji, bo w czasie uruchomienia powinno działać.

  12. @Koziolek
    nie no, co Ty mówisz 😀 przecież to jest połowa sensu istnienia akcesorów w C#. Może i podałem dosyć niefortunny przykład, no ale może jakiś inny, bardziej ksiązkowy:
    masz temperature w jednej zmiennej i możesz sobie stworzyć kilka akcesorów zwracajacych ją w różnych systemach:
    int temp;
    int temp_cel{ get { … } set {…} }
    int temp_fahr{ get { … } set {…} }
    int temp_kelv{ get { … } set {…} }

  13. @pilak, a to ja teraz wiem dlaczego jak pod XP wpisywało się A to system robić C… Swoją drogą jest to jedno z dziwniejszych rozwiązań…

  14. niestety nie moge edytować:
    poza tym: walidacja! dzięki temu nie musimy sie martwić tworzeniem dodatkowych metod walidujących nam zmienne i ich wywoływaniem, możemy zawsze po prostu przypisywac od razu jakąś wartość pod zmienną:
    int temp;
    int Temp{ get { return temp; } set {if(value > 0)temp = value;} else MessageBox(„blad walidacji”) }

  15. @pilak, jeszcze nie testowałem, bo mam obecnie remont na głowie i kompa „z doskoku”, ale w Javie można walidować pola za pomocą adnotacji.
    Swoją drogą testowanie getterów i setterów czy aby na pewno prawidłowo działają to już lekkie przegięcie. Wolę zrobić to za pomocą adnotacji, aspectj i walidatorów.

  16. ale walidacja pól w Java przez adnotacje to przez jakiś framewrok/dodatek?? czy przez czystą Jave?
    mógłbyś wrzucić jakiś przykład?

Napisz odpowiedź

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax