Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Comparing Lombok and Kotlin

DZone's Guide to

Comparing Lombok and Kotlin

Kotlin has support for IDEs and build tools right out-of-the-box plus seamless Java interoperability. So, is Lombok still relevant?

· Java Zone
Free Resource

Try Okta to add social login, MFA, and OpenID Connect support to your Java app in minutes. Create a free developer account today and never build auth again.

I've known about Lombok for a long time, and I even wrote on how to create a new (at the time) @Delegate annotation. Despite this and even though I think it’s a great library, I’ve never used it in my projects. The reason for this is mostly because I consider setting up the Lombok agent across various IDEs and build tools too complex for my own taste in standard development teams.

In comes Kotlin, which has support for IDEs and build tools right out-of-the-box, plus seamless Java interoperability. So, I was wondering whether Lombok would still be relevant. In this article, I’ll check if Kotlin offers the same feature as Lombok and how. My goal is not to downplay Lombok’s features in any way, but to perform some fact-checking to let you decide what’s the right tool for you.

The following assumes readers are familiar with Lombok’s features.

Lombok Snippet Kotlin equivalent
val
val e = new ArrayList<String>();
val e = ArrayList<String>()
@NonNull
public void f(@NonNull String b) {
    ....
}
fun f(val b: String) {
  ...
}
Kotlin types can be either nullable i.e.String<?> or not i.e.String. Such types do no inherit from one another.
@Cleanup
@Cleanup
InputStream in =
    new FileInputStream("foo.txt")
FileInputStream("foo.txt").use {
  // Do stuff here using 'it'
  // to reference the stream
}
  • use() is part of Kotlin stdlib
  • Referencing the stream is not even necessary
@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor No equivalent as class and constructor declaration are merged
@Getter
public class Foo {
    @Getter
    private String bar;
}
class Foo() {
  var bar:String? = null
    private set
}
  • Generates a private setter instead of no setter
  • Not idiomatic Kotlin (see below)
public class Foo {
    @Getter
    private String bar;
    public Foo(String bar) {
        this.bar = bar;
    }
}
class Foo(val bar:String)
 Takes advantage of merging class and constructor declaration with slightly different semantics
@Setter
public class Foo {
    @Setter
    private String bar;
}
No equivalent but pretty unusual to just have a setter (does not favor immutability)
public class Foo {
    @Setter
    private String bar;
    public Foo(String bar) {
        this.bar = bar;
    }
}
class Foo(var bar: String)
@ToString No direct equivalent but included in data classes, see below
@EqualsAndHashCode
@Data
@Data
public class DataExample {
    private String name;
    private int age;
}
data class DataExample(
  var name: String,
  var age: Int)
@Value
@Value
public class ValueExample {
  String name;
  int age;
}
data class ValueExample(
  val name: String,
  val age: Int)
 Notice the difference between val and var with the above snippet
lazy=true
public class GetterLazyExample {
  @Getter(lazy=true)
  private Double cached = expensive();
}
class GetterLazyExample {
  val cached by expensive()
}
@Log
@Log
public class LogExample {
  public static void main(String... args) {
    log.error("Something's wrong here");
  }
}
No direct equivalent, but possible in many different ways
@SneakyThrows
@SneakyThrows
public void run() {
 throw new Throwable();
}
fun run() {
  throw Throwable()
}
There's no such thing as checked exceptions in Kotlin. Using Java checked exceptions requires no specific handling.
@Builder
@Builder
public class BuilderExample {
  private String name;
  private int age;
}

BuilderExample b = new BuilderExampleBuilder()
  .name("Foo")
  .age(42)
  .build();
class BuilderExample(
  val name: String,
  val age: Int)

val b = BuilderExample(
  name = "Foo",
  age = 42
)
 No direct equivalent, use named arguments instead.
@Synchronized
public class SynchronizedExample {
  private final Object readLock = new Object();
  @Synchronized("readLock")
  public void foo() {
    System.out.println("bar");
  }
}
It's possible to omit to reference an object in the annotation: Lombok will create one under the hood (and use it).
class SynchronizedExample {
  private val readLock = Object()
  fun foo() {
    synchronized(readLock) {
      println("bar")
    }
  }
}
synchronized() is part of Kotlin stdlib
Experimental features
Lombok Snippet Kotlin equivalent
@ExtensionMethod
class Extensions {
  public static String extends(String in) {
    // do something with in and
    return it;
  }
}

@ExtensionMethod(
  {String.class, Extensions.class}
)
public class Foor {
  public String bar() {
    return "bar".toTitleCase();
  }
}
fun String.extends: String {
  // do something with this and
  return it;
}

class Foo {
  fun bar = "bar".toTitleCase()
}
@Wither No direct equivalent, available through data classes
@FieldDefaults
class Foo(val bar: String = "bar")
@Delegate
No equivalent
@UtilityClass
@UtilityClass
public class UtilityClassExample {
  private final int CONSTANT = 5;
  public void addSomething(int in) {
    return in + CONSTANT;
  }
}
var CONSTANT = 5
fun addSomething(i: Int): Int {
  return i + CONSTANT
}
@Helper
public class HelperExample {
  int someMethod(int arg1) {
    int localVar = 5;
    @Helper class Helpers {
      int helperMethod(int arg) {
        return arg + localVar;
      }
    }
    return helperMethod(10);
  }
}
class HelperExample {
  fun someMethod(arg1: Int): Int {
    val localVar = 5
    fun helperMethod(arg: Int): Int {
      return arg + localVar
    }
    return helperMethod(10)
  }
}

In conclusion:

  • Lombok offers some more features.
  • Lombok offers some more configuration options, but most don’t make sense taken separately (e.g.data classes).
  • Lombok and Kotlin have slightly different semantics when a feature is common, so double-check if you’re a Lombok user willing to migrate.

Of course, this post completely left out Kotlin’s original features. This is a subject left out for future articles.

Build and launch faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:
java ,development ,interoperability ,lombok ,ides ,library

Published at DZone with permission of Nicolas Frankel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}