Java
Lombok

Javaでコードを書くのがだるすぎたけどLombok使ったら思いのほか楽しかった

More than 5 years have passed since last update.

「Lombok、便利そうだけどまあそんなに使わないかなあ」と思ってたんだけど試しに使ってみたらかなり快感だったのでメモ。

Javaのだるさ

Javaでプログラムを書いているとよく「intのtype, Stringのnameというフィールドを持つだけの、特定の処理などは含まないHogeクラスを作ろう。まあ普通に文字列表現もあってequalsによる比較とかもできるように」のように思います。

Hoge.java
package org.hogel;

public class Hoge {

    private int type;
    private String name;

    public Hoge() {
    }

    public Hoge(int type, String name) {
        this.type = type;
        this.name = name;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public int hashCode() {
        return type + (name == null ? 0 : name.hashCode());
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        } else if (obj == null || !(obj instanceof Hoge)) {
            return false;
        }
        Hoge other = (Hoge) obj;
        if (type != other.getType()) {
            return false;
        }
        return name == other.getName() || name != null && name.equals(other.getName());
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        return builder.append("Hoge(type=").append(type).append(", name=").append(name).append(")").toString();
    }
}

うっ、だるい

なんてコードの長さでしょう。ディスプレイのサイズは有限なのです、こんな長いコードを表示するのには何年もかかってしまいます。

そうだ、困ったときのCommonsだ

Javaで困ったときはとりあえずApache Commonsを頼りにしましょう。

Commons Langという便利なライブラリにはこういった独自クラスを作るときに有用な機能が含まれています。

Hoge.java
package org.hogel;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;

public class Hoge {

    private int type;
    private String name;

    public Hoge() {
    }

    public Hoge(int type, String name) {
        this.type = type;
        this.name = name;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

    @Override
    public boolean equals(Object obj) {
        return EqualsBuilder.reflectionEquals(this, obj);
    }

    @Override
    public String toString() {
        // Hoge[type=1,name=a]のような形式で出力される
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}

hashCode, equals, toStringメソッドの中身がすべて一行になりました。ああしかしやっぱりめんどうです、めんどうなので 一々こんなクラス作るのをやめてListやらMapやらを組み合わせてしまおうか、なんて思ってしまいます。

そうだ、Lombokがある

さてここでLombok。百聞は一見にしかず。Lombokを使うと上述したコードがこんなことになります。

Hoge.java
package org.hogel;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Hoge {
    private int type;
    private String name;
}

おや、ほとんど何もなくなっていますね。でもこれで上に書いた2つのコードとほとんど同じ挙動をするのです。試しにこんなテストコードで実行してみます。

HogeTest.java
package org.hogel;

import org.junit.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;

public class HogeTest {
    @Test
    public void hogeBean() {
        Hoge a1 = new Hoge(1, "a");
        Hoge a2 = new Hoge(1, "a");
        Hoge b = new Hoge(2, "b");

        System.err.println("a1.getType(): "+ a1.getType());
        System.err.println("a1.getName(): "+ a1.getName());
        System.err.println();

        System.err.println("a1: " + a1);
        System.err.println("b: " + b);
        System.err.println();

        System.err.println("a1 == a2: " + (a1 == a2));
        System.err.println("a1 == b: " + (a1 == b));
        System.err.println();

        System.err.println("a1.equals(a2): " + a1.equals(a2));
        System.err.println("a1.equals(b): " + a1.equals(b));
        System.err.println();

        System.err.println("a1.hashCode(): " + a1.hashCode());
        System.err.println("a2.hashCode(): " + a2.hashCode());
        System.err.println("b.hashCode(): " + b.hashCode());
        System.err.println();

        assertThat(a1, is(a2));
        assertThat(a1, not(b));

        assertThat(a1.hashCode(), is(a2.hashCode()));
    }
}

定義もしていないコンストラクタやgetType、getNameなどを呼んでいます。それの実行結果がこうなります。

a1.getType(): 1
a1.getName(): a

a1: Hoge(type=1, name=a)
b: Hoge(type=2, name=b)

a1 == a2: false
a1 == b: false

a1.equals(a2): true
a1.equals(b): false

a1.hashCode(): 1089
a2.hashCode(): 1089
b.hashCode(): 1121

なんだか知らんがうまいこと動作していますね。Lombok、すげー。

IDEなしでJavaを書くなんてのはただの苦行ですし、Lombokは各IDEにも対応しています
lombok-intellij.png

詳細や更に便利な機能などはLombokのページでご確認ください。valなんて使いはじめるともうJavaなのかなんなのかわからなくなってきてとても楽しいと思います。