Kotlin Features I miss most in Java – Kotlin vs Java

PLEASE find an updated version of this on my Medium: https://medium.com/@s1m0nw1/the-7-features-i-miss-most-when-going-back-to-java-after-spending-time-with-kotlin-2b3a35e0b13f.

Let's write an article that covers "Kotlin vs Java" topics - I want to tell you which Kotlin features I miss most when going back to Java.

My Life as a Java Dev

Although I'm a big supporter of the Kotlin programming language, I still do a lot of Java programming on a daily basis for my employer. Since I'm aware of the great functionalities of Kotlin, I'm often struggling with Java as it has some "pitfalls", requires additional boilerplate and misses many features.
In this post, I'd like to describe which Kotlin features I miss most when coding in Java.

new and Semicolon

Ever since I'm doing Kotlin, there are two things I always forget when coding in Java: the new keyword for constructor invocations and the annoying ; to complete statements. Kotlin doesn't have new and even semicolons are optional. I really appreciate this decision because it reduces the "syntactic noise".

Data classes

In Kotlin, data classes are used for simple data containers, representing JSON objects or returning compound objects from functions amongst other use cases. Of course, Java doesn't support this special type of classes yet. As a result, I often have to implement my own data class, which means a lot of boilerplate in Java.

One special use case is compound objects returned from functions. For example, let's imagine a function that needs to return two objects. In Kotlin we could use a data class, or simpler, a Pair directly. In Java, I tend to create a value object, which is a class with several final fields, each of which instantiated through the constructor. Similar to Kotlin, I don't implement getters and setters, but use the class's fields directly as public properties. Unfortunately, this is not what we learned as best practice and most Java code style checkers will complain about it. I do not see any encapsulation issues here and it's the least verbose approach in Java. The following shows such a compound object, the inner class Multi. In Kotlin this would be a one-liner.

public class MultiReturn {

    public static void main(String[] args) {
        new MultiReturn().useMulti();
    }

    public void useMulti() {
        Multi multi = helper();
        System.out.println("Multi with " + multi.count + " and " + multi.name);
    }

    private Multi helper() {
        return new Multi(2, "test");
    }

    private static class Multi {
        private final int count;
        private final String name;

        public Multi(int count, String name) {
            this.count = count;
            this.name = name;
        }
    }
}

Local Functions

In many situations, we tend to create private methods that are only used inside another single method in order to make this one more readable. In Kotlin, we can use local functions, i.e. functions inside functions (inside functions...), which enables some kind of scope. For me, this is a much cleaner approach, because the function is only accessible inside the function that actually uses the local one. Let's look at an example.


fun deployVerticles() {

    fun deploy(verticleClassName: String) {
        vertx.deployVerticle(verticleClassName, opt, { deploy ->
            LOG.info("$verticleClassName has been deployed? ${deploy.succeeded()}")
        })
    }

    deploy("ServiceVerticle")
    deploy("WebVerticle")
}

It's taken from a sample vert.x application and defines a local function that is reused twice afterward. A great way to simplify your code.

Single Expression Functions

We can create single expression functions in Kotlin, i.e. functions without an actual body. Whenever a function contains only a single expression, it can be placed after a = sign following the function declaration:


fun trueOrFalse() = Random().nextBoolean()

In Java, on the other hand, we always have to use a function body enclosed in {}, which ranges over at least three lines. This is also "syntactic noise" I don't want to see anymore. To be fair, Java 1.8 makes it possible to define lambdas which can also solve this, less readable though (Can also be applied to local functions):


public class SingleExpFun {

    private BooleanSupplier trueOrFalse = new Random()::nextBoolean;

    private boolean getNext(){
        return trueOrFalse.getAsBoolean();
    }
}

Default Parameters

One very annoying part of Java is the way methods have to be overloaded. Let's see an example:

public class Overloade
    public static void main(String[] args) {
        Overloader o = new Overloader();
        o.testWithoutPrint(2);
        o.test(2);
    }

    public void test(int a, boolean printToConsole) {
        if (printToConsole) System.out.println("int a: " + a);
    }

    public void testWithoutPrint(int a) {
        test(a, false);
    }

    public void test(int a) {
        test(a, true);
    }

}

We can see a class with a method test(int, boolean) that is overloaded for the default case and also a convenience method is available. For more complex examples, it can lead to a lot of redundant code, which is simpler in Kotlin by using default parameters.


fun test(a: Int, printToConsole: Boolean = true) {
    if (printToConsole) println("int a: " + a)
}

fun testWithoutPrint(a: Int) = test(a, false)

fun main(args: Array) {
    testWithoutPrint(2)
    test(2)
}

Calling multiple methods on an object instance (with)

Obviously, Kotlin is more functional than Java. It makes use of higher-order functions in incredibly many situations and provides many standard library functions that can be used as such. One of my favorites is with, which I miss a lot whenever I can't use Kotlin. The with function can be used to create scopes that actually increase the readability of code. It's always useful when you sequentially call multiple functions on a single object.


class Turtle {
    fun penDown()
    fun penUp()
    fun turn(degrees: Double)
    fun forward(pixels: Double)
}

with(Turtle()) {
    penDown()
    for(i in 1..4) {
        forward(100.0)
        turn(90.0)
    }
    penUp()
}

The great thing is the usage of lambdas with receiver, which you can read about in one of my other posts.

Null-Safety

Whenever I work with nullable types since the time I started with Kotlin, I actually miss the type system's tools to prevent null-related errors. Kotlin did a very good job by distinguishing nullable types from not-nullable ones. If you strictly make use of these tools, there is no chance you'll ever see a NullpointerException at runtime.

Lambdas and Collection Processing

Kotlin places a lot of value on its lambdas. As shown in the with example earlier, there's special syntax available for lambdas that makes its usage even more powerful. I want to underline that the way functions and especially lambdas are treated in the language makes it dramatically superior to Java. Let's see a simple example of Java's Streams, which were introduced along with lambdas in Java 1.8:

List list = people.stream().map(Person::getName).collect(Collectors.toList());

It's a rather simple example of a Stream that is used to get a list of names from a list of persons. Compared to what we did before 1.8, this is awesome. Still, it's too noisy compared to a real functional approach as pursued by Kotlin:

val list = people.map { it.name }

Or yet another example, in which salaries of employees are summed up to a total amount:

int total = employees.stream()
                      .collect(Collectors.summingInt(Employee::getSalary)));

So much simpler in Kotlin:

val total = employees.sumBy { it.salary }

The Kotlin examples show how simple it can be. Java isn't a functional language and has a hard time trying to adopt functional features like lambdas and streams as we can easily observe in the snippets. It really sucks to go back to Java, if you ever experienced the beauty of Kotlin. Have you ever tried to use Eclipse after being familiar with IntelliJ? You know what I mean then.

Wrap-up

In this short post, I presented you my top Kotlin features I always miss when coding in Java. It's just a selection of things, which will hopefully find their way into the Java language soon. But to be honest, there's no reason to always wait for Java, when there already is a much sweeter language available... I want to point out, that starting with Kotlin really made me a much better programmer because I began wondering about certain features in both languages and also try to find ways to use Kotlin-dedicated things in Java by finding workarounds like arranging my code differently.

I'd be interested in the features you like most, feel free to comment.
Also, if you like, have a look at my Twitter account and follow if you’re interested in more Kotlin stuff 🙂 Thanks a lot.

If you want to read more about Kotlin's beautiful features I recommend the book Kotlin in Action and my other articles to you.

15 thoughts on “Kotlin Features I miss most in Java – Kotlin vs Java

  • fnl

    aggregating and mapping over (Java or not) streams is not really the same as over containers. in other words, Java8 doesn’t have the ability to flatMap et al. an arbitrary container, unlike Kotlin or Scala.

  • Tom

    Thanks for your nice post. Helped me learn a bit more about Kotlin.

    Under “Default Parameters” section, I didn’t any overloaded method in Java class though. I thought a more comparable code would be as followed. Please correct me if I’m wrong.

    public class Overloader {
    public static void main(String[] args) {
    Overloader o = new Overloader();
    o.testWithoutPrint(2);
    o.testWithPrint(2);
    }

    public void test(int a, boolean printToConsole) {
    if (printToConsole) System.out.println("int a: " + a);
    }

    // overloaded method here
    public void test(int a) {
    test(a, true);
    }

    public void testWithoutPrint(int a) {
    test(a, false);
    }

    }

  • Markus Krüger

    Nice overview! Some nitpicks, though. While Java doesn’t have local functions, it does have local classes, which are only visible inside the block in which they are declared. Your local function example could be implemented in Java by making the function a method in a local class. If you’re not familiar with local classes, there’s a decent overview at https://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html.

    Another way to fake local functions in Java would be to use a lambda: declare a local variable Consumer deploy = (verticleClassName) -> { ... }; and invoke deploy.apply("ServiceVerticle"). Not as pretty, but still accomplishes the goal of encapsulating the function.

    Not sure what you mean when you say Java doesn’t have single expression functions. You can write BooleanSupplier trueOrFalse = new Random()::nextBoolean; in Java. No curly brackets required. Similarly, you could say IntUnaryOperator addTwo = i -> i + 2; for arbitrary single expressions.

    • This post does not describe things that are impossible in Java. For example, I’m aware of local classes, but who does actually do? It’s more common to define private methods for such scenarios. Why is that? Local classes look ugly inside methods, also the calls to methods in that class are more verbose.

      Regarding local functions: Fair enough, that’s a possibility. But actually I don’t like the clumsy lambda syntax in Java, especially how such a function is called: trueOrFalse.getAsBoolean();.

      • Markus Krüger

        I agree that local functions look better, and that Java’s lambda syntax has room for improvement. 🙂 Just wanted to point out the possibilities for readers that are stuck with Java.

  • I think it’s worth mentioning that Kotlin not only supports optional function arguments, but also named arguments like those of Python. This makes it possible to write a function like join(parts: List, delimiter: String = “, “, prefix: String = “[“, suffix: String = “]”) and call it with join(listOf(“foo”, “bar”), prefix = “(“, suffix = “)”), thus resulting in “[foo, bar]”.

Leave a Reply

Your email address will not be published. Required fields are marked *