lombokで快適Java生活 | サイバーエージェント 公式エンジニアブログ

どうもこんにちは、社内ではJava嫌いで有名になってしまった oinume です。最近Javaに慣れすぎてむしろスクリプト言語が苦手になってきています。今回は「これがあればJavaでの開発もそんなにストレスないかもなぁ」と思える個人的な3種の神器のひとつである lombok を紹介します。

lombokってなに?

一言でいうとJavaの野暮ったいgetter/setterメソッドなどを自動的に生成してくれるソフトウェアです。例えば @Data アノテーションをつけて以下のようにメンバー変数を定義するだけで、lombokがgetter/setter/equals/hashCode/toStringのメソッドをコンパイル時に生成してくれます。

package sample;

import lombok.Data;

@Data
public class User {

    private int id;
    private String name;
    private String email;

    public static void main(String[] args) {
        User user = new User();
        user.setId(1);
        user.setName("oinume");
        user.setEmail("oinume@example.com");

        System.out.println(user);
        // --> User(id=1, name=oinume, email=oinume@example.com)
    }
}

どうでしょう?使ってみたくなってきませんか?

インストール

lombokはコンパイル時にメソッドなどを生成するため、EclipseなどのIDEを使っている場合はインストールが必要です。JREがインストール済みの環境であれば、lombok のサイトから lombok.jar をダウンロードしてダブルクリックすればインストーラーが立ち上がるので、下記のようにEclipseを選択して下さい。

eclipse.iniに下記の行が追加されていれば問題なくインストールされています。

-javaagent:lombok.jar
-Xbootclasspath/a:lombok.jar

また、実際にJavaプロジェクトから@Dataなどのlombokのアノテーションを使うにはpom.xmlなどに以下の依存関係を追加しておいて下さい。

pom.xml

    <dependencies>
        <dependency>
            <groupid>org.projectlombok</groupid>
            <artifactid>lombok</artifactid>
            <version>0.11.8</version>
        </dependency>
    </dependencies>

この設定が完了した状態で先程の User.java をEclipseで表示すると右側のOutlineに自分では定義していないgetter/setterメソッドなどがあることが確認できると思います。

なお、今回掲載したソースコードはGitHubに上がっているので、これをcloneすればすぐにlombok を試せます。

もう少し詳しく

lombokでは @Data アノテーションをつけると、getter/setter以外にもおなじみの

  • toString()
  • equals()
  • hashCode()

メソッドも併せて定義してくれます。例えば「getter だけを定義したい」というような時は、下記のように @Getter アノテーションを使います。

package sample;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
public class User2 {
    @Getter
    private int id;
    @Getter
    private String name;

    public static void main(String[] args) {
        User2 user2 = new User2(1, "oinume");
        System.out.println("name = " + user2.getName());
    }
}

@DataはAll in oneなアノテーションだと思ってもらえればよいでしょう。lombokのfeaturesには使用可能なアノテーションが全て記載されており、それをつけた場合にどういうコードが生成されるかも書いてあるので興味のある方は読んでみて下さい。(@Delegateや@SneakyThrowsなど便利そうなアノテーションがあります)

lombokで生成されたコードが見たい

コンパイルされたクラスファイルをデコンパイルしてもいいのですが、もっと簡単な方法があります。

java -jar /path/to/lombok.jar delombok -p src/main/java/sample/User.java

を実行することで、lombokを通したあとのコードが出力されるので、lombokがどのようなコードを生成しているかがわかります。先ほどのUser.java の場合は以下のように出力されました。

// Generated by delombok at Fri Jun 28 23:00:50 JST 2013
package sample;

public class User {
    private int id;
    private String name;
    private String email;

    public static void main(String[] args) {
        User user = new User();
        user.setId(1);
        user.setName("oinume");
        user.setEmail("oinume@example.com");
        System.out.println(user);
    }

    @java.lang.SuppressWarnings("all")
    public User() {

    }

    @java.lang.SuppressWarnings("all")
    public int getId() {
        return this.id;
    }

    @java.lang.SuppressWarnings("all")
    public String getName() {
        return this.name;
    }

    @java.lang.SuppressWarnings("all")
    public String getEmail() {
        return this.email;
    }

    @java.lang.SuppressWarnings("all")
    public void setId(final int id) {
        this.id = id;
    }

    @java.lang.SuppressWarnings("all")
    public void setName(final String name) {
        this.name = name;
    }

    @java.lang.SuppressWarnings("all")
    public void setEmail(final String email) {
        this.email = email;
    }

    @java.lang.Override
    @java.lang.SuppressWarnings("all")
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (!(o instanceof User)) return false;
        final User other = (User)o;
        if (!other.canEqual((java.lang.Object)this)) return false;
        if (this.getId() != other.getId()) return false;
        final java.lang.Object this$name = this.getName();
        final java.lang.Object other$name = other.getName();
        if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
        final java.lang.Object this$email = this.getEmail();
        final java.lang.Object other$email = other.getEmail();
        if (this$email == null ? other$email != null : !this$email.equals(other$email)) return false;
        return true;
    }

    @java.lang.SuppressWarnings("all")
    public boolean canEqual(final java.lang.Object other) {
        return other instanceof User;
    }

    @java.lang.Override
    @java.lang.SuppressWarnings("all")
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + this.getId();
        final java.lang.Object $name = this.getName();
        result = result * PRIME + ($name == null ? 0 : $name.hashCode());
        final java.lang.Object $email = this.getEmail();
        result = result * PRIME + ($email == null ? 0 : $email.hashCode());
        return result;
    }

    @java.lang.Override
    @java.lang.SuppressWarnings("all")
    public java.lang.String toString() {
        return "User(id=" + this.getId() + ", name=" + this.getName() + ", email=" + this.getEmail() + ")";
    }
}

まとめ

Scalaを使おう!