Weekend with Kotlin: Everything you need to know to get started with Kotlin — Part II of III

Faheem un nisa
BYJU’S Exam Prep Engineering
6 min readApr 1, 2019

So we meet again!

This articles assumes that you have given ..

..its fair share of time and focus. This time around, let’s delve into the pool of functions and constructors and objects and companion objects and what not; let’s make programming great again!

…6. Lambda Expressions:

A lambda expression is an anonymous function: a function without name. These functions are passed immediately as an expression without declaration.

A lambda expression is enclosed inside curly braces.

fun main(args: Array<String>) {val greeting = { println("Hello!")}// invoking function
greeting()
}

Output:

Hello!

Here, a lambda expression is assigned to variable greeting. The expression doesn’t accept any parameters and doesn’t return any value in this program.

Then, the function (lambda expression) is invoked as:

greeting()

Example:

fun main(args: Array<String>) {
val product = { a: Int, b: Int -> a * b }
val result = product(9, 3)
println(result)
}

Output:

27

7. Functions & Default values:

Functions in Kotlin are declared using the fun keyword:

fun double(x: Int): Int {
return 2 * x
}
fun powerOf(number: Int, exponent: Int) { … }

Default Arguments

Function parameters can have default values, which are used when a corresponding argument is omitted. This allows for a reduced number of overloads compared to other languages:

fun read(b: Array<String>, off: Int = 0, len: Int = b.size) { … }

Overriding methods always use the same default parameter values as the base method. When overriding a method with default parameter values, the default parameter values must be omitted from the signature:

open class A {
open fun foo(i: Int = 10) { … }
}
class B : A() {
override fun foo(i: Int) { … } // no default value allowed
}

Named arguments: Function parameters can be named when calling functions. This is very convenient when a function has a high number of parameters or default ones.

fun reformat(str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ‘ ‘) {

}

Call this using default arguments:

reformat(str)

Or pass arguments:

reformat(str, true, true, false, ‘_’)

With named arguments we can make the code much more readable:

reformat(str,
normalizeCase = true,
upperCaseFirstLetter = true,
divideByCamelHumps = false,
wordSeparator = ‘_’
)

We can pass only selective arguments:

reformat(str, wordSeparator = ‘_’)

When a function is called with both positional and named arguments, all the positional arguments should be placed before the first named one. For example, the call f(1, y = 2) is allowed, but f(x = 1, 2) is not.

Variable number of arguments(vararg) can be passed in the named form by using the spread operator:

fun foo(vararg strings: String) { … }foo(strings = *arrayOf(“a”, “b”, “c”))

Nested Functions

Kotlin supports local functions, i.e. a function inside another function:

fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: Set<Vertex>) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v, visited)
}

dfs(graph.vertices[0], HashSet())
}

High Order Functions

Functions that can be passed as arguments to other functions or can return a function are called higher-order functions.

Often, lambda expressions are passed to higher-order function (rather than a typical function) for convenience.

The empty parenthesis suggest that, the passed anonymous function doesn’t accept any parameters.

fun callMe(greeting: () -> Unit) {
greeting()
}
fun main(args: Array<String>) {
callMe({ println("Hello!") })
}

If the lambda expression accepts only one parameter, you can refer the argument by using keyword it.

You can replace

val selectedPerson = people.maxBy({ person -> person.age })

with

val selectedPerson = people.maxBy({ it.age })

Extension Functions

Kotlin Extension Functions are a way of extending the abilities of a class. They help in adding functions to a class without actually inheriting the class.

Example:

fun main(args: Array) {
var a=8
var b=6
var calc:Calculator = Calculator()
println(calc.add(a,b))
println(calc.subtract(a,b))
println(calc.multiply(a,b))
}
// multiply is an extension function to the class Calculator
fun Calculator.multiply(a: Int, b: Int): Int{
return a*b
}

Extension functions are resolved statically during compile time based on the type of object we are calling the function upon, i.e., in the above example, we have created an object calc of type Calculator, and called multiply function using calc.multiply. As we have already declared calc of type Calculator, compiler checks if there is an extension function called multiply for the class type of calc.

Let’s see another example of Toast class in Android. To make the call easy to this Toast from any class which extends the Context class directly or indirectly, we can create an extension method of Context class which will do the exact same.

fun Context.showToast(text: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, text, duration).show()
}
//to call this method from any context extending class
showToast(“Hello”)

7. Return Types

When a function returns a single expression, the curly braces can be omitted and the body is specified after a = symbol:

fun double(x: Int): Int = x * 2

is the same as

fun double(x: Int) = x * 2

If a function does not return any useful value, its return type is Unit. Unit is a type with only one value - Unit. It is the same as void in Java.

The Unit return type declaration is also optional.

Functions with block body must always specify return types explicitly, unless it’s intended for them to return Unit, in which case it’s optional. Kotlin does not infer return types for functions with block bodies because such functions may have complex control flow in the body, and the return type will be non-obvious to the reader (and sometimes even for the compiler).

fun addNumbers(num1:Int=2, num2:Int=3):Int{var x: Int
//do something
//do something more
return x
}

8. Companion Objects

In Kotlin, unlike Java or C#, classes do not have static methods. In most cases, it’s recommended to simply use package-level functions instead.

If you need to write a function that can be called without having a class instance but needs access to the internals of a class, you can write it as a member of an object declarations inside that class.

class MyClass {
companion object { }
}
val x = MyClass.Companion

9. Singleton

How about we start with a face-off this time?

Java

public class Singleton {

private static Singleton instance = null;

private Singleton(){
}

private synchronized static void createInstance() {
if (instance == null) {
instance = new Singleton();
}
}

public static Singleton getInstance() {
if (instance == null) createInstance();
return instance;
}
}

Kotlin

object Singleton

Yes, that’s it! Kotlin’s representation of a Singleton class requires the object keyword only. Hence a Singleton class in Kotlin can be defined without the use of a class. An object class can contain properties, functions and the init method; the constructor method is NOT allowed.
A singleton object can be defined inside a class but not inside an inner class.

An object cannot be instantiated in the way a class is instantiated: an object gets instantiated when it is used for the first time.

object Singletonfun main(args: Array<String>) {
print(Singleton.javaClass)
}
//Following is printed in the console.
//class Singleton

The javaClass is auto-generated by the singleton class and prints the equivalent name for the Java class name.

Object initialization is similar to lazy initialization of kotlin properties. In the below code, object isn’t initialized since it isn’t used.

class A {object Singleton
{
init {
println(“Singleton class invoked.”)
}
var name = “Kotlin Objects”
fun printName()
{
println(name)
}
}init {
println(“Class init method. Singleton name property”)
}
}
//Console:
//Class init method

Objects have much more to use than just being a Singleton class.

--

--