Kotlin - An Introduction

Last Friday (2016-06-24), I happened to come across and actually do some reading on Kotlin. I had heard the name once a week ago or so.

It's amazing!

Kotlin is a JVM language being actively developed by JetBrains (maker of IntelliJ). The IntelliJ IDE obviously has great support built-in for Kotlin. They have developed the language against Java 6 so far, and with 100% Java interoperability in mind. One current issue or con is if you use Annotation Processors like Lombok, Mapper, etc as there will be conflicts and confusion. This seems to be true for Groovy and other JVM languages as well (reasons for this are beyond the scope of this post).

Anyway, down to it. Based on a previous post from like a year ago, I will show below how a converted class looks going from Java to Kotlin. This example class is a Producer for an ElasticSearch Node Client.

Java

package com.brandonlamb.elasticsearch;

import org.elasticsearch.client.Client;  
import org.elasticsearch.common.settings.ImmutableSettings;  
import org.elasticsearch.common.settings.Settings;  
import org.elasticsearch.node.Node;  
import org.elasticsearch.node.NodeBuilder;  
import javax.annotation.PostConstruct;  
import javax.annotation.PreDestroy;  
import javax.enterprise.context.ApplicationScoped;  
import javax.enterprise.inject.Produces;  
import javax.inject.Inject;

@ApplicationScoped
public class ClientProducer {  
  private Client client;
  private final String hosts = "host1:9300, host2:9300";
  private final String clusterName = "my-cluster";

  @PostConstruct
  public void postConstruct() {
    final Settings settings = ImmutableSettings.settingsBuilder()
      .put("http.enabled", false)
      .put("client.transport.sniff", true)
      .put("cluster.name", clusterName)
      .put("discovery.zen.ping.unicast.hosts", hosts)
      .build();

    final Node node = NodeBuilder.nodeBuilder()
      .settings(settings)
      .client(true)
      .node()
      .start();

    client = node.client();
  }

  @Produces
  @ElasticSearchClient
  public Client getClient() {
    return client;
  }

  @PreDestroy
  public void preDestroy() {
    client.close();
  }
}

Kotlin

package com.brandonlamb.elasticsearch

import org.elasticsearch.client.Client;  
import org.elasticsearch.common.settings.ImmutableSettings;  
import org.elasticsearch.common.settings.Settings;  
import org.elasticsearch.node.Node;  
import org.elasticsearch.node.NodeBuilder;  
import javax.annotation.PostConstruct  
import javax.annotation.PreDestroy  
import javax.enterprise.context.ApplicationScoped  
import javax.enterprise.inject.Produces

@ApplicationScoped
class ClientProducer {  
  private lateinit var client: Client
  private val hosts = "host1:9300, host2:9300"
  private val clusterName = "my-cluster"

  @PostConstruct
  fun postConstruct() {
    val settings = ImmutableSettings.settingsBuilder()
      .put("http.enabled", false)
      .put("client.transport.sniff", true)
      .put("cluster.name", clusterName)
      .put("discovery.zen.ping.unicast.hosts", hosts)
      .build()

    val node = NodeBuilder.nodeBuilder()
      .settings(settings)
      .client(true)
      .node()
      .start()

    client = node.client()
  }

  @PreDestroy
  fun preDestroy() = client.close()

  @Produces
  @ElasticSearchClient
  fun produceClient(): Client = client
}

Given this particular example, you may think to yourself "there isn't much difference!". Take a closer look though and you will notice that we trimmed 4 lines and 133 characters, making it a bit more concise. This example doesn't really show how much you gain with Kotlin.

Let's take a look at another example, this one is a simple interface with a static method which takes a String with an expected CSV format 1,2,3 and returns a List of [1, 2, 3].

Java

package com.brandonlamb;

import java.util.Collections;  
import java.util.List;  
import java.util.stream.Collectors;  
import java.util.stream.Stream;  
import javax.validation.constraints.NotNull;

public interface CsvConverter {  
  @NotNull
  static List<Integer> toIntList(final String values) {
    if (values == null || "".equals(values)) {
      return Collections.emptyList();
    }

    return Stream
        .of(values.split(","))
        .map(Integer::parseInt)
        .collect(Collectors.toList());
  }
}

Kotlin

package com.brandonlamb

object CsvConverter {  
  fun toIntList(values: String?): List<Int> = if (values == null || values.length == 0)
    emptyList() else values.split(",").map { it.toInt() }
}

Now here we can see we trimmed 15 lines and 315 characters. Clearly here the Kotlin version is more concise.