Hello, Kotlin!
I was working as a java software engineer for more than 4 years. Recently I joined a firm that uses Kotlin instead of Java and I have been learning Kotlin for the past few weeks.
Learning Kotlin has been fun and interesting. Also, I feel it is fairly easy for a Java developer to learn Kotlin because the syntax is almost similar but Kotlin is less verbose than Java. From my post, I want to share with you some cool features I learned about Kotlin.
Background
Kotlin is an open-source, statically-typed programming language that features both object-oriented and functional programming paradigms. It is the primary development language in Android.
Now let’s dive into some unique features in Kotlin.
Single Type System
A type system is a set of rules that determine the types of a programming language construct.
Kotlin comes along with a very powerful typing system. Unlike Java, Kotlin does not have primitive types. Hence, Kotlin’s type system is solely on objects.
Following are the built-in types in Kotlin.
Other than above, users can define their own types by means of Classes, Interfaces, Enums.
Type Inference
Kotlin is a strongly typed language that supports Type Inference. Kotlin compiler can automatically identify the data type of the variable or the return-type of a function even if you don’t explicitly specify it.
For example, in Kotlin you can declare a variable in 2 ways.
var num : Int = 2
var num = 2
Note that in the second method, you didn’t have to specify the type of the variable because Kotlin is able to infer the type based on the value assigned to the variable.
This is the same case for the return type of functions.
Smart Casts
Kotlin compiler can perform type casts automatically in the following cases.
- Casting from a supertype to a subtype
val object: Any = "test string"
if(object is String) {
// Here, object is automatically casted to String sub-type.
println(object.length)
}
- Casting from nullable types to their non-nullable counterpart
var firstName: String? = "test string"
if(firstName != null) { // Smart cast.
print(firstName.length)
}
Null safety
In Kotlin, types are non-null by default. To allow a variable to hold null, we can declare a variable with the nullable operator (?
).
var firstName: String = null // This will give compilation errorvar firstName: String? = null // Ok
Now, Kotlin compiler will warn us whenever we try to access variables declared as nullable.
Elvis Operator
The Elvis operator (?:
) is designed specifically to handle null cases. It will return a non-null value or a default value when the variable is null.
val name = firstName ?: "Empty"
You can also throw an exception if the variable is null.
val name = firstName ?: throw Exception("Invalid name")
Top-level Functions & Variables
Top-level functions are functions inside a Kotlin package that are defined outside of any class, object, or interface definition. These functions can be invoked directly, without the reference to a class or an object. Top-level variables are the same as top-level functions. Variables are defined outside a class definition in Kotlin.
fun main() {
println("Hello, Kotlin!")
}
In Kotlin, variables are of two types.
- Read-Only
val
the keyword is used for read-only variables. This is similar to thefinal
keyword in Java meaning the variable cannot be reassigned once initialized. - Mutable
var
the keyword is used for mutable variables in Kotlin. When a variable is defined as var, it is possible to re-assign its value in a latter part of the code.
Single Expression Definitions
Kotlin gives us the capability to define functions as a single expression for direct operations. Basically, a single-expression function is a function where a single expression is assigned to the function, and the expression’s evaluated value is returned when this function is called.
fun getGreeting() = "Hello, Kotlin"
The above is a single expression function that takes no arguments and return “Hello, Kotlin” string whenever it is called.
String Templates
String templates in Kotlin are String literals that can contain embedded expressions.
val message = "Hello $variable"
Unlike in Java, a String template can contain logic as well.
val message = "Hello, ${if(variable != null) variable else "Unknown"}"
Named Arguments
Kotlin allows you to specify the names of arguments that you’re passing to the function. This can be helpful when a function has many arguments.
fun fun_name(name1: data_type, name2: data_type )
Default Arguments
you can provide default values to parameters in the function definition. When invoking the function, you can omit passing arguments if they are not different from the default ones.
fun printGreeting(greeting:String = "Hello", name:String ="Kotlin") {
println("$greeting, $name")
}
This allows to configure and re-use functions and objects by leveraging these default and named arguments syntax.
Companion Objects
In the scenario where you do not want to give direct access to the instantiation of a particular class, you can define a companion object inside that class. By declaring a companion object, you can access the properties and functions of the original class using the class name without instantiation. This is useful when implementing the factory design pattern in Kotlin.
class CompanionClass {
companion object CompanionObject {
}
}
val object = CompanionClass.CompanionObject
Data classes
Data classes are defined for the purpose of holding data. The Kotlin compiler automatically generates the following functions for them.
toString()
equals()
hashCode()
copy()
componentN()
Example of a data class declaration.
data class Employee (
val id: String,
val name: String?
)
Extensions
Kotlin provides the ability to extend a class with new functionality without having to inherit from the class. You can extend functions as well as properties of a class.
This is highly useful when you want to incorporate new functions/properties for a class from a third-party library that you cannot modify.
For extending properties, initializers cannot be used. You have to override the getters/setters of those properties. You can also define new properties for existing classes.
Higher-Order Functions
A higher-order function is a function that takes functions as parameters or returns a function. By default, Kotlin functions are first-class. First-class functions can be stored in variables and data structures and can be passed as arguments to and returned from other higher-order functions.
Function Types
In Kotlin, function types are used to store functions as variables. An example is shown below.
val greet = fun() { println("Hello, Kotlin!") }
I hope you got a high-level overview of some of the useful features of Kotlin. For detailed information please refer the official Kotlin documentation. Thank you for reading!