5 Kotlin Built-in Features Every Java Developer Should Know

3 min readMar 30, 2025

Companion Objects:

Companion objects are the objects whose attributes can be used in different Kotlin files/classes without object creation. This means whatever resides in the Companion object could be used globally. Companion objects can have functions and constants. For Java developers, think of it as “Static method”, where you do not have to create the object to use it in a separate method.

class Remote{
companion object {
const val globalVariable = "This is a global variable"
fun globalFunction(){
....
}
}

From the above example, you can use globalVariable and globalFunction can be used any Koltin file or class.

This is similar to Java’s static method:

class Remote{
public static String globalMethod(){
return "this is a global method";
}
}

Suspend functions:

Suspend function is part of Kotlin’s provision for asynchronous programming. Simply out, Suspending functions can be paused and resumed later without blocking the thread it is running on.
How to define a suspend function? Just add suspend keyword to your functions signature:

suspend fun asyncCall(val param: String){
delay(1000)
makeAPIcall()
...
}

Here the asyncCall does not actually delay for 1000 ms. It moves forward to execute the makeAPIcall() function.

Note:

Although suspend function is very easy to use, it has some drawbacks. For instance, from the above example if asyncCall is taking more than ~30 seconds, the function would automatically be timed out. You can also use custom time out for this, but that entirely depends on your use case.

Do note that, Suspending functions do not spawn new threads. It makes use of the existing threads available at that point of time from the thread pool.

RunBlocking :

RunBlocking is also Kotlin’s coroutine function. This should be used from a coroutine. Without any context, function wrapped with runBlocking will execute on the main thread.
With context this will spawn a new thread and blocks the current thread’s implementation until the task is completed.

class main{
fun doSomething()= runBlocking{
callSomething()
}
}

Here doSomething() does not have any context, so it runs on main thread by default.

class main{
fun doSomethingUpdated()= runBlocking{
launch(Dispatchers.Default){ callSomething() }
}
}

Now in doSomethingUpdated() has context, which means this will run on a new thread.

Note:

Do not use runBlocking everywhere, especially while using in mobile development. Mobile development often deals with single thread, so using runBlocking will block the only thread which is used. However, this can be used sparingly in web development.

RunCatching :

runCatching is used to replace the boring try-catch block. RunCatching is used to handle the exceptions gracefully.

try{
makeAPICall()
} catch(e: Exception){
println("Error occured due to $e")
}

Instead of this, you can replace this with runCatching:

runCatching{ makeAPICall() }
.onSuccess{ println("API call is successful") }
.onFailure{ println("API call failed!") }

Data class :

Data class in Kotlin is used for defining the data models or DTO. The best thing about data class in Kotlin is you do not have to create constructors, getters and setters to assign the values like you do for Java’s data models or DTOs:

Java’s example for DTO:

public class UserDTO {
private String name;
private String email;
private int age;

// Constructor
public UserDTO(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}

// Getters & Setters
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

// toString() method for debugging
@Override
public String toString() {
return "UserDTO{name='" + name + "', email='" + email + "', age=" + age + "}";
}
}

Now if we use Kotlin to define this:

data class UserDTO(
val name: String,
val email: String,
val age: Int
)

This shows that you can avoid a lot of verbose code!!

--

--

Aahlad kethineedi
Aahlad kethineedi

Written by Aahlad kethineedi

Software Developer. I enjoy reading about Tech and Finance.

No responses yet