{"id":889,"date":"2016-03-08T17:15:00","date_gmt":"2016-03-08T15:15:00","guid":{"rendered":"http:\/\/invidit.de\/blog\/?p=889"},"modified":"2020-12-08T10:32:03","modified_gmt":"2020-12-08T08:32:03","slug":"lombok-macht-das-schon","status":"publish","type":"post","link":"https:\/\/invidit.de\/blog\/lombok-macht-das-schon\/","title":{"rendered":"Lombok macht das schon"},"content":{"rendered":"<p>Hallo Spa\u00df-Coder.<\/p>\n<p>Wer kennt sie nicht: Datenklassen, die ausschlie\u00dflich Attribute enthalten um Daten aufzunehmen und selbst keine Logik beinhalten? Sei es f\u00fcr die Entit\u00e4ten der Datenbanktabellen oder einfache Datentranfsfer-Objekte. Diese Klasse k\u00f6nnte echt \u00fcbersichtlich und aufger\u00e4umt sein, w\u00e4ren da nicht diese <em>Getter<\/em> und <em>Setter<\/em> der Attribute, eine Implementierung der <em>toString()<\/em>-Methode, <em>equals()<\/em> oder <em>hashCode()<\/em>.<\/p>\n<p>Damit wird die vermeintlich einfache Klasse doch wieder recht un\u00fcbersichtlich und aufgebl\u00e4ht. In diesem Artikel stellen wir eine Bibliothek vor, die es uns erm\u00f6glicht, auf das Wesentliche zu fokussieren.<\/p>\n<h1>Was macht Lombok?<\/h1>\n<p>Das Projekt Lombok<sup>[1]<\/sup> stellt eine Java-Bibliothek zu Verf\u00fcgung, die uns erm\u00f6glicht den Code deutlich aufger\u00e4umter zu gestalten und die \u00fcblichen erforderlichen Methoden einfach durch Annotationen generieren zu lassen. Wie das aussehen kann, m\u00f6chten wir euch anhand von ein paar Beispielen verdeutlichen. Dazu verwenden wir unser kleines TicTacToe Spiel, welches wir auch <a href=\"http:\/\/invidit.de\/blog\/anleitung-zum-gluecklichsein\/\">in anderen Artikeln <\/a>bereits als Beispiel herangezogen hatten.<\/p>\n<h2>Geben und Nehmen<\/h2>\n<p>Unsere Entities sollen Daten tragen. Diese sind per Konvention zun\u00e4chst einmal als <span style=\"color: #800080;\">private<\/span> markiert. Damit wir doch Zugriff darauf haben, verwenden wir <em>Getter<\/em> und <em>Setter<\/em>. Im Normalfall k\u00f6nnen die nicht viel und verschmutzen unseren sch\u00f6nen Code.<\/p>\n<p>Schauen wir doch mal, was Lombok in diesem Fall f\u00fcr uns tun kann:<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Natural Pure Java<\/strong><\/td>\n<td><strong>Mit Lombok-Magie<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true\">public class Player {\n\n\tprivate String name;\n\tprivate String symbol;\n\tprivate MoveStrategy strategy;\n\n\tpublic Player() {\n\t\tthis.name = \"\";\n\t\tthis.strategy = null;\n\t\tthis.symbol = \"?\";\n\t}\n\t\n\t[...]\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\tpublic String getSymbol() {\n\t\treturn this.symbol;\n\t}\n\t\n\tpublic int getNextMove(GameState state) {\n\t\treturn this.strategy.getNextPosition(state);\n\t}\n}<\/pre>\n<\/td>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true\">public class Player {\n\n\t@Getter @Setter\n    private String name;\n    @Getter\n\tprivate String symbol;\n    private MoveStrategy strategy;\n\n\tpublic Player() {\n\t\tthis.name = \"\";\n\t\tthis.strategy = null;\n\t\tthis.symbol = \"?\";\n\t}\n\t\n\t[...]\n\n\tpublic int getNextMove(GameState state) {\n\t\treturn this.strategy.getNextPosition(state);\n\t}\n}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Durch die beiden einfachen Annotationen <em>@Getter<\/em> und <em>@Setter<\/em> lassen sich in diesem Beispiel 10 Zeilen Code sparen. Das sch\u00f6ne daran ist, dass nun gut sichtlich wird, dass die Methode <em>getNextMove()<\/em> kein klassischer Getter ist, sondern \u00fcber eine Strategie ein bestimmtes Verhalten erzeugt (dazu kommen wir in einem anderen Artikel noch). So erkennen wir den wichtigen Teil unseres Codes viel schneller.<\/p>\n<h2>Nullen sind hier nicht erlaubt!<\/h2>\n<p>Frei nach dem Prinzip <em>fail fast<\/em> wollen wir oft die Eingangsparameter unserer Methoden pr\u00fcfen. Die h\u00e4ufigste Pr\u00fcfung ist dabei die Pr\u00fcfung darauf, dass der \u00fcbergebene Parameter nicht <em>null<\/em> ist.<\/p>\n<p>Auch hier schauen wir mal, wie Lombok uns das Leben vereinfacht:<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Natural Pure Java<\/strong><\/td>\n<td><strong>Mit Lombok-Magie<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true\">public class Player {\n\n\t[...]\n\t\n\tpublic Player(PlayerData playerData) {\n        if(playerData == null) {\n            throw new NullPointerException(\"playerData\");\n        }\n\t\tthis.name = playerData.getName();\n\t\tthis.symbol = playerData.getSymbol();\n\t\tthis.strategy = playerData.getStrategy();\n\t}\n\n\t[...]\n}<\/pre>\n<\/td>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true \">public class Player {\n\t\n\t[...]\n\n\tpublic Player(@NonNull PlayerData playerData) {\n\t\tthis.name = playerData.getName();\n\t\tthis.symbol = playerData.getSymbol();\n\t\tthis.strategy = playerData.getStrategy();\n\t}\n\n\t[...]\n\n}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Auch hier reicht eine einfache Annotation. Wir erhalten eine NullPointerException und als Nachricht den Namen des betroffenen Parameters&#8230;und sparen 3 Zeilen Code&#8230;pro zu pr\u00fcfendem Parameter.<\/p>\n<p>Noch besser: Kombinieren wir z.B. die @Setter-Annotation mit der @NonNull-Annotation, k\u00fcmmert sich Lombok sogar gleich darum:<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Natural Pure Java<\/strong><\/td>\n<td><strong>Mit Lombok-Magie<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true\">public class Player {\n    private String name;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        if(name == null) {\n            throw new NullPointerException(\"name\");\n        }\n        this.name = name;\n    }\n\n    [...]\n\n}<\/pre>\n<\/td>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true\">public class Player {\n    @Getter @Setter @NonNull\n    private String name;\t\n\t\n    [...]\n\n}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Drei Annotations anstelle von 9 Zeilen Code, die in aller Regel immer gleich aussehen.<\/p>\n<h3>Vergleichende Objekte<\/h3>\n<p>Werfen wir auch noch einen Blick auf das Thema <em>equals<\/em> und <em>hashCode<\/em>, welches wir eingangs des Artikels angesprochen haben:<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Natural Pure Java\u00a0 (IDE-generiert)<\/strong><\/td>\n<td><strong>Mit Lombok-Magie<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true\">public class Player {\n\n    [...]\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n        Player player = (Player) o;\n        return Objects.equals(name, player.name) &amp;&amp;\n                Objects.equals(symbol, player.symbol);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name, symbol);\n    }\n}<\/pre>\n<\/td>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true \">@EqualsAndHashCode(exclude = {\"strategy\"})\npublic class Player {\n\n    [...]\n\n}\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Auf der einen Seite durch IntelliJ generierte <em>equals<\/em>&#8211; und <em>hashCode<\/em>-Methoden, bei denen die Variable <em>strategy<\/em> aus dem Vergleich ausgelassen wurde. Auf der anderen Seite die Klasse mit der Annotation <em>@EqualsAndHashCode<\/em>, sowie einer erg\u00e4nzenden Anweisung, welche Variablen ausgelassen werden sollen (in unserem Fall eben <em>strategy<\/em>). \u00dcbersichtlich, oder?<\/p>\n<h2>Und nun, alle zusammen&#8230;<\/h2>\n<p>Als letztes m\u00f6chten wir noch ein Beispiel f\u00fcr echte, dumme Datentransportobjekte verwenden. Diesmal nehmen wir als Beispiel nicht mehr die Klasse <em>Player<\/em>, die hatte ja durch die Delegation der Aufgabe an die \u00fcbergebene Strategie schon ein bisschen Intelligenz an Bord.<\/p>\n<p>Stattdessen muss diesmal die Klasse <em>PlayerData<\/em> als Beispiel herhalten. Diese besteht aus drei Eigenschaften, mit <em>Gettern<\/em>, einem <em>Konstruktor<\/em> mit allen Werten als \u00dcbergabeparameter, <em>equals<\/em>, <em>hashCode<\/em>, <em>toString<\/em>, alles was man eben so braucht, wenn man als Datentransportobjekt was auf sich h\u00e4lt.<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Natural Pure Java\u00a0 (teilweise IDE-generiert)<\/strong><\/td>\n<td><strong>Mit Lombok-Magie<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true\">public class PlayerData {\n    private final String name;\n    private final String symbol;\n    private final MoveStrategy strategy;\n\n    public PlayerData(String name, String symbol, MoveStrategy strategy) {\n        this.name = name;\n        this.symbol = symbol;\n        this.strategy = strategy;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public String getSymbol() {\n        return symbol;\n    }\n\n    public MoveStrategy getStrategy() {\n        return strategy;\n    }\n\n    @Override\n    public String toString() {\n        return \"PlayerData{\" +\n                \"name='\" + name + '\\'' +\n                \", symbol='\" + symbol + '\\'' +\n                \", strategy=\" + strategy +\n                '}';\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n        PlayerData that = (PlayerData) o;\n        return Objects.equals(name, that.name) &amp;&amp;\n                Objects.equals(symbol, that.symbol) &amp;&amp;\n                Objects.equals(strategy, that.strategy);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name, symbol, strategy);\n    }\n}<\/pre>\n<\/td>\n<td style=\"vertical-align: top;\">\n<pre class=\"lang:java decode:true \">@Data\npublic class PlayerData {\n\tprivate final String name;\n    private final String symbol;\n    private final MoveStrategy strategy;\n}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Ein Wort:<em> @Data<\/em>. Reicht oder? \ud83d\ude09<\/p>\n<h1>Und sonst?<\/h1>\n<p>Die Projektseite enth\u00e4lt eine sehr gute (englischsprachige) Beschreibung der Funktionalit\u00e4t, weshalb wir hier nicht alle einzeln beschreiben, sondern euch einladen, einfach mal durchzuschauen, was hinter Lombok steckt und was es sonst noch kann.<\/p>\n<h1>Unsere Erfahrungen mit Lombok<\/h1>\n<p>Kleine Klassen auch wirklich klein und \u00fcbersichtlich zu halten funktioniert mit Lombok sehr gut. Auch wenn sicherlich jede Entwicklungsumgebung Getter und Setter mittlerweile per Knopfdruck generiert, stehen sie dennoch im Code und bl\u00e4hen diesen unn\u00f6tig auf. Der Blick in die annotierte &#8211; beinahe leere &#8211; Klasse ist etwas gew\u00f6hnungsbed\u00fcrftig, beschleunigt allerdings auch das Arbeiten und lenkt unsere Aufmerksamkeit st\u00e4rker auf das Wesentliche &#8211; n\u00e4mlich die umzusetzenden Anforderungen.<\/p>\n<h2>Verwendung und Einrichtung<\/h2>\n<p>Wir haben Lombok bisher nur zusammen mit IntelliJ in Verbindung mit Maven verwendet. Damit dies reibungslos funktioniert, braucht es folgende Zutaten:<\/p>\n<ol>\n<li>Das Lombok-Plugin f\u00fcr IntelliJ\n<ul>\n<li>seit Version 2020.3 ist Lombok geb\u00fcndelt in IntelliJ enthalten<\/li>\n<li>F\u00fcr \u00e4ltere Versionen einfach wie alle Plugins installieren, ist unter &#8222;Lombok&#8220; im Plugin-Repository zu finden<\/li>\n<\/ul>\n<\/li>\n<li>Die Abh\u00e4ngigkeit zu Lombok in der pom.xml\n<pre class=\"lang:xhtml decode:true\">&lt;dependency&gt;\n\t&lt;groupId&gt;org.projectlombok&lt;\/groupId&gt;\n\t&lt;artifactId&gt;lombok&lt;\/artifactId&gt;\n\t&lt;version&gt;1.16.6&lt;\/version&gt;\n&lt;\/dependency&gt;<\/pre>\n<\/li>\n<li>In den Einstellungen ist die Verarbeitung von Annotationen zu aktivieren (Settings &gt; Build, Execution, Deployment &gt; Compiler &gt; Annotation Processors &gt; Enable Annotation Processing).<\/li>\n<\/ol>\n<p>Lombok funktioniert auch mit anderen IDEs, etwa Eclipse. Details dazu sind ebenfalls auf der <a href=\"https:\/\/projectlombok.org\/features\/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">Projektseite von Lombok <\/a>zu finden.<\/p>\n<h1>Zusammenfassung<\/h1>\n<p>In diesem Artikel haben wir euch eine Bibliothek vorgestellt, die das Leben eines Entwicklers vereinfachen kann und Java-Klassen aufger\u00e4umt und damit \u00fcbersichtlich h\u00e4lt. Es gibt keinen Grund Lombok nicht einmal auszuprobieren. Selbst wenn ihr euch nach einiger Zeit im Projekt daf\u00fcr entscheiden solltet, Lombok nicht mehr zu verwenden, k\u00f6nnt ihr die Annotationen <a href=\"https:\/\/projectlombok.org\/features\/delombok.html\" target=\"_blank\" rel=\"noopener noreferrer\">mit Hilfe von Delombok<\/a> sehr leicht wieder in &#8222;normalen&#8220; Java-Code \u00fcberf\u00fchren.<\/p>\n<p>Welche Bibliothek unterst\u00fctzt euch beim Sauberhalten eures Codes?<\/p>\n<p>Eure Spa\u00df-Coder<\/p>\n<p>Referenzen:<\/p>\n<ul>\n<li id=\"gs_cit0\" class=\"gs_citr\" tabindex=\"0\"><sup>[1]<\/sup> <a href=\"https:\/\/projectlombok.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/projectlombok.org\/<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Hallo Spa\u00df-Coder. Wer kennt sie nicht: Datenklassen, die ausschlie\u00dflich Attribute enthalten um Daten aufzunehmen und selbst keine Logik beinhalten? Sei es f\u00fcr die Entit\u00e4ten der Datenbanktabellen oder einfache Datentranfsfer-Objekte. Diese Klasse k\u00f6nnte echt \u00fcbersichtlich und aufger\u00e4umt sein, w\u00e4ren da nicht diese Getter und Setter der Attribute, eine Implementierung der toString()-Methode, equals() oder hashCode(). Damit wird [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":909,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[90],"tags":[],"_links":{"self":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/889"}],"collection":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/comments?post=889"}],"version-history":[{"count":22,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/889\/revisions"}],"predecessor-version":[{"id":1273,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/889\/revisions\/1273"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media\/909"}],"wp:attachment":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media?parent=889"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/categories?post=889"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/tags?post=889"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}