Introduction to Kotlin for Java Developers

Photo by Nathan Dumlao on Unsplash

TL;DR

Some Highlights:

  • Kotlin Compiler (kotlinc) converts .kt to bytecode as .class.
  • JRE + Kotlin Runtime Library is required at runtime and for distribution.
  • Everything is a class in Kotlin (no primitive types).
  • You can declare top level methods or constants (no need to belong to a class).
  • There is a single kotlin package and you do not have to import it or any other package else then your own implementations.
  • No semicolon!
  • Package names and path in your class’s first line does not need to match (i.e. your class’s physical location may be different).

Variable Declarations, Properties and Backing Fields

class Student(var name: String, val id: Int) {
}
class Student(val firstName, isBoarding: Boolean = false) {
}
val student1 = Student("Bob", 12)
val student2 = Student("Laura", 14)
class Student(val firstName, isBoarding: Boolean = false) {
var isBoarding = isBoarding
get() {
println("hello getter!")
return field
}
set(value) {
println("hello setter!")
field = value
}
}
student1 = student2
student1.name = "Mark"

Access Modifiers

  • public, private, protected, internal (in a module)
  • Kotlin classes are public and final by default
  • Class name can be different from its file name (unlike Java)
  • Class can be private but everything is visible if they are in the same file even if you declare as private.
  • private -> compiled to -> package private
  • internal -> compiled to -> public
Kotlin in Action — Manning Publications

String Templates

Raw Strings (Triple Quoted Strings)

"""C:\"""
"""a
b
c""".trimMargin()

Function Basics

fun printStudentNames(vararg students: Student) {
for (student in students) {
println(student.firstName)
}
}
printStudentNames(*students)

Single Expression Functions

fun myOperation(param1: Int, param2: Int, resultLabel: String) : String = "$resultLabel: ${param1 + param2 * 5}"
fun myOperation(param1: Int, param2: Int, resultLabel: String) = "$resultLabel: ${param1 + param2 * 5}"

Extension Functions

fun String.replaceLetterRWithT(): String =  this.replace('r', 't')
"my car".replaceLetterRWithT()

Inline Functions

inline fun higherOrderFunction(functionName: (name: String)->Unit, name: String){
println("In higher order function")
println("Calling received function...")
functionName(name)
}

fun main() {
higherOrderFunction({ name: String ->
println("Inside lambda function")
println("Say hello to $name")
}, "Ninja")
}

Companion Object

class UtilClass {
companion object {
fun maskString(str: String): String{
...
}
}
}

Singleton

object Teacher {
...
}

Inheritance

open class Animal() {
open fun run()
}
class Rabbit(): Animal() {
override fun run()
}

Checked / Unchecked Exception

Ternary Operator ( condition ? then : else )

val max = if (a > b) a else b
val color = if (condition) {
println("hello1")
1
}
else {
println("hello2")
2
}
println(num)

When

val color = "blue"
when (color) {
"pink" -> println("flamingo")
"blue" -> println("car")
"yellow" -> println("sunflower")
else -> println("none of them")
}

For Loop

for (int i=0; i<n; i++) {
...
}
for (i in 1..5) {
...
}
for (i in 1..20 step 5) {
...
}
for (i in 20 downTo 10) {
...
}
for (i in 20 downTo 10 step 5) {
...
}
for (i in 1 until 10) {
// excluding 10
}

ForEach

colors.forEach { println(it) }
colors.forEachIndexed { index, value -> println("$value-$index") }

Lambda Expressions

run { println("hi from lambda!" }
students.minBy { it.grade }
students.minBy(Student::grade)

Receivers

with(StringBuilder()) {
for (i in 1..100) {
append(i)
append("-")
}
}.toString()
StringBuilder().apply() {
for (i in 1..100) {
append(i)
append("-")
}
}.toString()
var m = 1 
m = m.also { it + 100 }.also { it + 200 }
println(m)
//prints 1
val student: Student = getStudent().also {
print(it.name)
print(it.grade)
}

Labels

myLoop@ for (i in 1..100) {
...
for (j in 1..100) {
for (k in 1..100) {
// break @myLoop
// continue@myLoop
}
}
}
students.forEach myLambda@ {
if (it.name == name) {
println("found you!")
return @myLambda
}
}

“static” and “new” Keywords

Referential and Structural Equity

Null References

val str: string? = null

Null Related Checks

var direction = direction[coordinate] ?: Direction(0, 0)
directions[coordinate]?.moveRight()
var direction = direction[coordinate]!!
str?.let { println(it) }
return if( myVar.isCondition() ) doSthWith(myVar) else null
return doSthWith(myVar).takeIf { it.isCondition() }
var str1: string? = null
var str2 = "hello"
println(str1 == str2)

Smart Casting

if (teacher is Employee)
var newEmployee = teacher
val x: String? = y as? String
int myInt = 10;
long myLong = myInt;

Try/Catch Expressions

return try {
Integer.parseInt(str)
} catch (e: NumberFormatException) {
0
} finally {
println("fin")
}

Main Method

static void main(String[] args) {   
System.out.println("Hello World");
}
fun main(args : Array<String>) {
println("Hello World")
}

Void vs. Unit

Arrays

val myArr = arrayOf("a", "b", "c")
val myLongArr = arrayOf<Long>(1, 2, 3, 4)
val allZeroArr = Array(20){0}
val evenNumbersArr = Array(16){i -> i*2}
val mixedArr = arrayOf("hello", 12, BigDecimal(10.5), 'a')
val nullArr = arrayOfNulls<Int?>(5)

Lists

val emptyList = emptyList<String>()val notNullList = listofNotNull("hello", "world", null, "again") 
// if you print this array, you will not see "null" value
arrayListOf(1, 2, 3)
mutableListOf<Int>(1, 2, 3)
listOf("1", "2", "3").toMutableList()
listOf(*arrayOf("a", "b", "c"))
intArrayOf(1, 2, 3, 4, 5).toList()

Maps

mapOf(1 to Student("Alan")
2 to Student("Kim")
3 to Student("Michael"))
mutableMapOf<String, Student> ("Hi" to Student("Diana"))hashMapOf("hi" to "hello", "bye" to "goodbye").put("abbr." to "abbreviation")

Sets

setOf(10, 20, 30).plus(20) // no duplicates!
setOf(10, 20, 30).minus(40) // no exceptions
setOf(10, 20, 30).average()
setOf(10, 20, 30).drop(2) // removes first 3 elements
mutableSetOf(1, 2, 3).plus(10) // does nothing

Collections & Collection Functions

listOf("1", "2", "3").last() // get last value
listOf("1", "2", "3").asReversed()
listOf("1", "2", "3").getOrNull(5) // get from index 5
listOf("1", "2", "3").max() // get max value
val A = listOf("a", "b", "c")
val B = listOf(1, 2, 3, 4)
val resultPairs = A.zip(B)
// returns value pairs with the length of smallest array
A + B // returns ["a", "b", "c", 1, 2, 3, 4]
A.union(B) // no duplicates; duplicates are removed
A.distinct()
B.filter { it % 2 != 0 }
studentMap.filter { it.value.grade > 70 }

arrayOf(1, 2, 3).map { it + 10 }
studentMap.map { it.value.grade }
studentMap.all { it.value.grade > 70 }
// checks if all matches condition
studentMap.any { it.value.grade < 20 }
// checks if any matches condition
studentMap.count { it.value.grade > 50 }
// counts how many matches condition
studentMap.values.find { it.grade > 50 }
// finds first match and returns it
studentMap.values.groupBy { it.grade > 50 } // returns mapstudentMap.values.sortedBy { it.grade }studentMap.toSortedMap() // order by key

Sequences

studentMap.asSequence().filter { it.value.grade > 50 }val sequence1 =listOf("blue", "red", "green", "grey").asSequence()
.filter { println("filtering $it"); it[0] == 'g' }
.map { println("mapping $it"); it.toUpperCase());
sequence1.toList()
sequence1.find { it.endsWith('e') }

Destructuring

val pair = Pair(5, "five")
val(firstValue, secondValue) = pair
for ((key, value) in mutableMap) {
...
}
class Student(val name: String, val grade: Int) {
operator fun component1() = name
operator fun component2() = grade
}
val(name, grade) = student

Enums

enum class Color { BLACK, BLUE, PINK, RED }

Data Class

student3 = student2.copy(firstName="Newton")

Comma Usage:

listOf("blue", "red", "green", "grey").asSequence()
.filter { println("filtering $it"); it[0] == 'g' }
.map { println("mapping $it");
enum class OrientationType(val key: Char) {

NORTH('N'),
SOUTH('S'),
EAST('E'),
WEST('W');

companion object {
fun getOrientationByKey(key: Char): OrientationType? = values().first { x -> x.key == key }
}
}

Implementation

Kotlin REPL (Read Eval and Print Loops)

Java Compliance and Interoperability

Nullability:

Kotlin Annotations:

I would love to change the world, but they won’t give me the source code | coding 👩🏼‍💻 | coffee ☕️ | jazz 🎷 | anime 🐲 | books 📚 | drawing 🎨

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Guide to Setup Kubernetes in AWS EKS using terraform and deploy sample applications

How I made my Simple and Robust Custom Serializable class in Java and Kotlin

Data Serialization in java and kotlin

CLI Tools & Last Pass CLI

Break into the Data Industry with SQL

Haskell Lens Operator Onboarding

Create Distributed, Scalable, Durable, and Highly Available Software— With Cadence

The Definitive Guide to Sassy💅

How to Authenticate your Elixir/Phoenix APIs using Guardian

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Nil Seri

Nil Seri

I would love to change the world, but they won’t give me the source code | coding 👩🏼‍💻 | coffee ☕️ | jazz 🎷 | anime 🐲 | books 📚 | drawing 🎨

More from Medium

Beginner’s Kotlin Practice: A Sample Project & Unit Tests (Java vs. Kotlin)

Kotlin for Java Developers

Kotlin vs Java Example: Part - 1 | Erselan Khan

Springboot Kotlin and Redis — Great partners