From Java to Kotlin - Functions, Varargs & Default Parameters

Kotlin functions are defined using the fun keyword with optional parameters and a return value (with a exception [Single Expressions]).

fun double(x: Int): Int { }

// calling member functions use the dot notation
Sample().foo()

Single Expressions functions

They mustn’t declare a return type.

fun concat1(a: String, b: String) = a + b

// written in regular style, this would be
fun concat2(a: String, b: String): String {
  return a + b
}

Such functions can use a shortened syntax that omits the braces and uses the = symbol before the expression rather than the return keyword.

Parameters

The parameter list must always be present, even if no parameters are defined.

fun hello(): String = "hello world"

fun hello(name: String, location: String): String =
    "hello to you $name at $location"

Top level Functions

They’re functions that exists outside of any class, object or interface and are directly defined inside a file.

They’re specially useful for defining helper or utility functions. Use top level functions when it does not make sense to group them with other function or inside any class. In Java, they’d be static functions inside helper classes.

Local functions

Local functions are useful when we want to hide functions that are just used as implementation details of a larger function. This reduces duplication. We could also achieve a similar effect by defining a member function as private

fun printArea(width: Int, height: Int): Unit {
  fun calculateArea(width: Int, height: Int): Int = width * height
  val area = calculateArea(width, height)
  println("The area is $area")
}

In Java, a large function or method might be broken down by calling several support functions declared in either the same class or a helper class.

A local function is not accessible to the code outside. Local functions can access the parameters and variables defined in the outer scope.

Named Arguments

When calling a method, you can specify the names of some arguments you’re passing for it to be more readable.

string.regionMatches(thisOffset = 14, length = 6, ignoreCase = true)

They also allow the argument order to be changed to suit the caller.

Default Parameters

Function parameters can have default values, which are used when a corresponding argument is omitted.

When invoking a function with default parameters, we can omit some or all of the parameters, but once a parameter is omitted, all the following parameters must be omitted as well

// function declaration
fun divide(divisor: BigDecimal, scale: Int = 0,
  roundingMode: RoundingMode = RoundingMode.UNNECESSARY): BigDecimal {
}

// all this calls are valid
divide(BigDecimal(12.34))
divide(BigDecimal(12.34), 8)
divide(BigDecimal(12.34), 8, RoundingMode.HALF_DOWN)

Varargs and Spread Operator

In Kotlin it’s possible to have varargs as a middle argument in a function. This is solved with named parameters.

// declaration
fun multiprint(prefix: String, varargs strings: String, suffix: String): Unit {
}

// invoke
multiprint("Start", "a", "b", "c", suffix = "End")

If you already had an array and want to pass this array as the middle varargs argument, we need to pass the spread operator *

val strings = arrayOf("a", "b", "c")
multiprint("Start", *strings, suffix = "End")

Extension Functions

An extension function is a function that can be called as a member of a class but is defined outside of it. For example, maybe you’ve always wished String had a reverse() function but subclassing String is messy.

The type of the instance that the function will be used on is called the receiver type.

// declaration
fun String.lastChar(): Char = this.get(this.length - 1)

// usage
print("Kotlin".lastChar())

Rules

  1. You can directly access methods and properties from the class you’re extending.
  2. Extension functions don’t have access to private or protected members of the class.
  3. When you define it, it doesn’t automatically become available across your entire project, You need to import it, just like any other class or function. import strings.lastChar
  4. They cannot override existing functions but can be used to overload functions
  5. They’re usually declared at the top level, but we can define them inside classes as members