Kotlin Functional Programming Features

This post is part of a series of posts about why I’m considering Kotlin for my new projects where I would normally choose Java. If you haven’t read the other posts, check them here: Let’s talk about Kotlin?

Igor Leal
3 min readFeb 12, 2018
Image from Unsplash (https://unsplash.com/@ikukevk)

If you are a Java programmer and is nowadays enjoying all the features that Java 8 brought to you, you will certainly love what Kotlin has to offer within this subject.

No need for “it”

Starting with something simple. When you use any functional feature, you don’t need to specify the item you are working with the “it” name, unless you want to call it something special. Here’s an example of a function that makes all Strings in a list uppercase, without needing to say “it”:

fun myForEachUsage(myList: List<String>): List<String> =  myList.map { it.toUpperCase() }

But… if you like to name your iterations, just go ahead…

fun myForEachUsage(myList: List<String>): List<String> =  myList.map { myString -> myString.toUpperCase() }

Pre-defined functions

Java 8 brought us some functions like .map, .forEach, .reduce, .filter, .anyMatch, etc. What Kotlin did to go beyond? You know know when you use the .filter to filter the empty results of a list, when you want to filter but the the index of the items you filtered or when you want to run a forEach but you need the index of the item you are at some point? Kotlin already pre-implemented a lot of these functions.

This is the difference between what Java 8 brought and what Kotlin brought:

One thing that is not really related to functional features but it is a combination of it and a great readability, you can see in this example. Let’s suppose you have a list of expenses a person had from your database. Let’s call this list databaseExpenseList.

var databaseExpenseList = getExpensesFromDatabase(userId)

Now I want to return return the expenses of the last 6 months in my API. What would my service look like in Kotlin?

First of all, I create a list of 6 items and then generate a list of 6 dates, starting today and going 6 months back.

fun getLastSixMonthsExpense(userId: Long) {
var databaseExpenseList = getExpensesFromDatabase(userId)
val date = Date.from(Instant.now())
(0..5).map { date.toInstant().atOffset(ZoneOffset.UTC).plusMonths((-1 * it).toLong()) }
}

Now I need to map again for each item, getting the expense of that month. In this example I retrieve from the database e map of “yyyy-mm” -> expense.

fun getLastSixMonthsExpense(userId: Long): List<myResponseVO> {
var databaseExpenseList = getExpensesFromDatabase(userId)
val date = Date.from(Instant.now())
val sdf = SimpleDateFormat("yyyy-mm")

return (0..5)
.map { date.toInstant().atOffset(ZoneOffset.UTC).plusMonths((-1 * it).toLong()) }
.map { myResponseVO(sdf.format(it), databaseExpenseList.findLast { expense -> expense.date == sdf.format(it) }!!.value) }
}

The problem here is that if this user has no expense in that specific month, a Null Pointer error will occur. That’s because I assumed tat the findLast will always return a value with the !! expression. To fix that I just use a Null Safe and an Elvis Operator. So, if this user has no expense in that month, I assume the expected value is zero.

fun getLastSixMonthsExpense(userId: Long): List<myResponseVO> {
var databaseExpenseList = getExpensesFromDatabase(userId)
val date = Date.from(Instant.now())
val sdf = SimpleDateFormat("yyyy-mm")

return (0..5)
.map { date.toInstant().atOffset(ZoneOffset.UTC).plusMonths((-1 * it).toLong()) }
.map { myResponseVO(sdf.format(it), databaseExpenseList.findLast { expense -> expense.date == sdf.format(it) }?.value ?: 0.0) }
}

This is a code that puts together the readability and simplicity of Kotlin. Enabling you to go one step forward towards functional programming in an easy way if you are coming from object oriented programming in Java.

And the best news

All these features available on Kotlin do not require Java 8. You can have an environment with Java 6 or any higher and still get all this benefits.

--

--