DEV Community

Florian Röser
Florian Röser

Posted on • Edited on

Kotlin for Java Developers (Part 2)

Kotlin for Java Developers (Part 1) covers

  • Data classes
  • Null safety
  • Immutability by default

This part continues on the key differences that a Java developer should be aware of when switching from Java to Kotlin. Part 2 of the series covers

  • Using new Keyword
  • Utilise Extension Functions
  • Use when Instead Of if Or switch

Using new Keyword

This is a rather small section, but I've confusion about this topic several times. In Kotlin, you don't need the new keyword to instantiate an object. The object creation is simpler, as Kotlin automatically understands that you want to create a new instance of a class.

Java way:

MyClass myClass = new MyClass();
Enter fullscreen mode Exit fullscreen mode

Kotlin way:

val myClass = MyClass()
Enter fullscreen mode Exit fullscreen mode
  • You simply call the class constructor directly, like you would with a function call.
  • val is used to declare an immutable variable that will hold the reference to the object (see immutability in part 1).

Utilise Extension Functions

Extension functions are a powerful feature, which allows you to add new functionality to existing classes without modifying their source-code! This is particularly useful when you need to enhance the capabilities of libraries or classes that you don't control, or when you want to avoid subclassing or writing utility classes.

Example 1: Extension functions on strings

Java way:
In Java, you might create a utility class with a static method to add functionality to a class.

public class MyStringUtils {
  public static boolean isValidEmail(String email) {
    return str != null && str.contains("@"); // Simplified email validation
  }
}
Enter fullscreen mode Exit fullscreen mode

to use this, you would have to call it as a static method:

String email = "test@example.com";
boolean isValid = MyStringUtils.isValidEmail(email);
Enter fullscreen mode Exit fullscreen mode

Kotlin way:
In Kotlin, you can add a new function to the String class to check if a string is a valid email address.

fun String.isValidEmail(): Boolean {
    return this.contains("@") // Simplified email validation
}
Enter fullscreen mode Exit fullscreen mode

or even shorter:

fun String.isValidEmail() = this.contains("@")
Enter fullscreen mode Exit fullscreen mode

The this keyword refers to the object the extension function is called on. You can call this function on any
String object:

val email = "test@example.com"
val isValid = email.isValidEmail() // direct call on the string object to the extension function
Enter fullscreen mode Exit fullscreen mode

This makes the code much cleaner and more readable as it avoids the boilerplate code of utility classes or inheritance.

Example 2: Extension functions on collections

E.g. if you want a filter function to only retrieve odd numbers from a list.

Java way:

import java.util.List;
import java.util.stream.Collectors;

public class MyListUtils {
    public static List<Integer> getOddNumbers(List<Integer> numbers) {
        return numbers.stream()
                      .filter(n -> n % 2 != 0)
                      .collect(Collectors.toList());
    }
}
Enter fullscreen mode Exit fullscreen mode

and you would call it like this

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
List<Integer> oddNumbers = MyListUtils.getOddNumbers(numbers);
Enter fullscreen mode Exit fullscreen mode

Kotlin way:

fun List<Int>.getOddNumbers() = this.filter { it % 2 != 0 }
Enter fullscreen mode Exit fullscreen mode

and you would call it directly on the list:

val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
val oddNumbers = numbers.getOddNumbers()
Enter fullscreen mode Exit fullscreen mode

Why use extension functions?

  • Cleaner code: Extension functions allow you to write code as if the function is part of an existing class, making you code-base look more natural and reduce boilerplate code.
  • Reusability: You can write reusable functionality outside the class itself

References


Use when Instead Of if Or switch

The when expression in Kotlin can be thought of as an advanced version of the switch statement in Java, that is much more powerful and can also replace the if-else statement. A key difference is, that the when expression is not limited to checking the equality as in Java, but can handle a wide range of conditions, like types, ranges and even arbitrary expressions.

Example 1: Using when instead of if-else

Java way:

int x = 2;
String result;

if (x == 1) {
    result = "One";
} else if (x == 2) {
    result = "Two";
} else if (x == 3) {
    result = "Three";
} else {
    result = "Unknown";
}
System.out.println(result);
Enter fullscreen mode Exit fullscreen mode

Kotlin way:

val x = 2
val result = when (x) {
    1 -> "One"
    2 -> "Two"
    3 -> "Three"
    else -> "Unknown"
}
println(result)
Enter fullscreen mode Exit fullscreen mode

Example 2: Using when instead of switch

Again the same java example:

int x = 2;
String result;

switch (x) {
    case 1:
        result = "One";
        break;
    case 2:
        result = "Two";
        break;
    case 3:
        result = "Three";
        break;
    default:
        result = "Unknown";
}
System.out.println(result);
Enter fullscreen mode Exit fullscreen mode

And the Kotlin equivalent:

val x = 2
val result = when (x) {
    1 -> "One"
    2 -> "Two"
    3 -> "Three"
    else -> "Unknown"
}
println(result)
Enter fullscreen mode Exit fullscreen mode

In Kotlin, there is no need for break statements, as the when expression automatically breaks after the first match.

Example 3: Using when with ranges

Kotlin's when expression can be used with ranges or collections:

val x = 5
val result = when (x) {
    in 1..10 -> "Between 1 and 10"
    !in 11..20 -> "Outside 11 - 20"
    else -> "Other"
}
Enter fullscreen mode Exit fullscreen mode

Example 4: Checking Types

You can also use when to check the type of an unknown object, similar to instanceof in Java:

fun checkType(obj: Any): String {
    return when (obj) {
        is String -> "String"
        is Int -> "Int"
        is Double -> "Double"
        else -> "Unknown"
    }
}

println(checkType("Hello")) // Prints "String"
println(checkType(42)) // Prints "Int"
println(checkType(3.14)) // Prints "Double"
println(checkType(true)) // Prints "Unknown"
Enter fullscreen mode Exit fullscreen mode

References:


Interested in the next article?
Here is Part 3 of the series.

Top comments (0)