While Google is adding Kotlin as an official Android language, we're also expanding our research on this language. It’s developed by JetBrains, and the fact that these are the people behind a suite of IDEs, such as IntelliJ and ReSharper, really shines through in Kotlin. It’s pragmatic and concise and makes coding a satisfying and efficient experience.
Although Kotlin compiles to both JavaScript and soon machine code, I’ll focus on its prime environment, the JVM.
Please see my presentation to learn more!
2. Introduction
Kotlin is a JVM based language developed by JetBrains.
Kotlin was created with Java developers in mind and these are two very interesting
features for Android developers:
● Kotlin is very intuitive and easy to learn for Java developers
● We have total integration with Android Studio
3. Introduction
● It’s more expressive (You can write more with much less code)
● It’s safer (Kotlin is null safe)
● It’s functional (lambda expressions, the way it deals with collections)
● It makes use of extension functions
● It’s highly interoperable (you can continue using most libraries and code written
in Java, It’s even possible to create mixed projects)
4. Few facts
● Compatibility: Kotlin is fully compatible with JDK 6, fully supported in Android
Studio and compatible with the Android build system.
● Performance: A Kotlin application runs as fast as an equivalent Java one, thanks
to very similar bytecode structure.
● Interoperability: Kotlin is 100% interoperable with Java, allowing to use all
existing Android libraries in a Kotlin application.
● Footprint: Kotlin has a very compact runtime library. Kotlin runtime adds only a
few hundred methods.
● Compilation Time: Kotlin supports efficient incremental compilation.
6. Android Studio Support
Converting Java code to Kotlin.
public class KotlinExampleApp extends Application {
public static KotlinExampleApp app;
private AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
app = KotlinExampleApp.this;
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.netModule(new NetModule())
.weatherModule(new WeatherModule())
.build();
}
public AppComponent getAppComponent() {
return appComponent;
}
}
class KotlinExampleApp : Application() {
var appComponent: AppComponent? = null
private set
companion object {
var app: KotlinExampleApp
}
override fun onCreate() {
super.onCreate()
app = this@KotlinExampleApp
appComponent =
DaggerAppComponent.builder()
.appModule(AppModule(this))
.netModule(NetModule())
.weatherModule(WeatherModule())
.build()
}
}
class KotlinExampleApp : Application() {
var appComponent: AppComponent? = null
private set
companion object {
var app: KotlinExampleApp? = null
}
override fun onCreate() {
super.onCreate()
app = this@KotlinExampleApp
appComponent = DaggerAppComponent.builder()
.appModule(AppModule(this))
.netModule(NetModule())
.weatherModule(WeatherModule())
.build()
}
}
7. Classes declaration
By default, a class always extends from Any (similar to Java Object), but we can extend
any other classes.
open class Animal(name: String)
class Person(firstName: String, lastName: String) : Animal(firstName)
class Customer(val customerName: String = "defaultName") // default
value
Instantiation
val customer = Customer("Joe Smith")
8. Constructors
class Person constructor(firstName: String) {}
class Person(firstName: String) {}
class Customer(name: String) {
init {
logger.info("Customer initialized with value ${name}")
}
}
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
class Person(val firstName: String, val
lastName: String, var age: Int) { }
class Person(val name: String) {
constructor(name: String, parent: Person) :
this(name) {
parent.children.add(this)
}
}
9. Inheritance (Overriding Methods)
open class Base {
open fun v() {}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
open class AnotherDerived() : Base() {
final override fun v() {}
}
10. Inheritance
open class A {
open fun f() { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") } // interface members are 'open' by default
fun b() { print("b") }
}
class C() : A(), B {
// The compiler requires f() to be overridden:
override fun f() {
super<A>.f() // call to A.f()
super<B>.f() // call to B.f()
}
}
11. “Static methods”
There are No static methods in Kotlin.
In most cases, it's recommended to simply use package-level functions instead.
Companion object inside your class will make you able to call its members with the
same syntax as calling static methods in Java.
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
...
val instance = MyClass.create()
12. Basic Types
● Basic types such as integers, floats, characters or booleans still exist, but
they all act as an object
● There are no automatic conversions among numeric types
● Characters (Char) cannot directly be used as numbers. (use *.toInt())
● Bitwise arithmetical operations are a bit different. (“and” instead of “&”, “or”
instead of “|”)
● It's common practice in Kotlin is to omit variable types
● A String can be accessed as an array and can be iterated
13. Variables and Constants
var str = "String" // A String
var number = 25 //An Int
val a: Int = 23
val c: Context = activity
14. Properties
public class Person {
var name: String = ""
get() = field.toUpperCase()
private set(value) {
field = "Name: $value"
}
//...
}
15. Methods
private fun method1(a: Int): Int {
return a * a
}
private fun method2(a: Int): Int = a * a
private fun method3(a: Int) = a * a
private fun doSmth(): Unit {/* nothing here */}
16. Extension functions
● adds a new behaviour to a class
● even if we don’t have access to the source code
● we don’t need to pass the object as an argument
● we can implement it using this and all its public methods
fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, duration).show()
}
Usage
toast("Hello world!")
toast("Hello world!", Toast.LENGTH_LONG)
17. Data Classes
● Avoid the boilerplate we need in Java to create POJO
● They usually only provide plain getters and setters to access to their fields
● We get equals(), hashCode(), copy() for free
data class Forecast(
@SerializedName("date") val date: Date,
@SerializedName("temp") val temperature: Float,
@SerializedName("desc") val description: String) // that’s all the declaration
// copy but change smth
val f1 = Forecast(Date(), 27.5f, "Storming")
val f2 = f1.copy(temperature = 31f)
18. Declaration Destructuring
val f1 = Forecast(Date(), 27.7f, "Shiny day")
val (date, temperature, details) = f1
...
val otherVariable = date
val otherTemperature = temperature
for ((key, value) in map) {
Log.d("map", "key:$key, value:$value")
}
19. With
With allow you to use public functions and properties without specifying variable.
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
with(items[position]) { // WeatherDataDto object contains props temperature, humidity etc
holder!!.temperature!!.text = temperature.toString()
holder.humidity!!.text = humidity.toString()
holder.description!!.text = description
holder.windSpeed!!.text = windSpeed.toString()
Glide.with(this@MainActivity).load(iconUrl).into(holder.icon)
}
holder!!.itemView.setOnClickListener { itemClick(items[position]) }
}
20. Lambdas
Lambda expression is a simple way to define an anonymous function. Function that
receives an interface with a single function can be substituted by a lambda.
Before
public interface OnClickListener { void onClick(View v) }
...
view.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast.makeText(v.getContext(), "Click", Toast.LENGTH_SHORT).show();
} });
Now
fun setOnClickListener(listener: (View) -> Unit)
...
view.setOnClickListener({ view -> toast("Click")})
// can be simplified to
view.setOnClickListener { toast("Click") }
22. Functional operations
any (Returns true if at least one element matches the given predicate)
val list = listOf(1, 2, 3, 4, 5, 6)
assertTrue(list.any { it % 2 == 0 })
all (Returns true if all the elements match the given predicate)
assertTrue(list.all { it < 10 })
count (Returns the number of elements matching the given predicate)
assertEquals(3, list.count { it % 2 == 0 })
fold (Accumulates the value starting with an initial value and applying an operation from the first to the
last element in a collection)
assertEquals(25, list.fold(4) { total, next -> total + next })
forEachIndexed (Same as forEach, though we also get the index of the element)
list.forEachIndexed { index, value -> println("position $index contains a $value") }
23. Functional operations
dropWhile
Returns a list containing all elements except first elements that satisfy the given predicate.
assertEquals(listOf(3, 4, 5, 6), list.dropWhile { it < 3 })
filter
Returns a list containing all elements matching the given predicate.
assertEquals(listOf(2, 4, 6), list.filter { it % 2 == 0 })
take
Returns a list containing first n elements.
assertEquals(listOf(1, 2), list.take(2))
groupBy
Returns a map of the elements in original collection grouped by the result of given function
assertEquals(mapOf("odd" to listOf(1, 3, 5), "even" to listOf(2, 4, 6)), list.groupBy { if (it % 2 == 0) "even"
else "odd" })
24. Functional operations
elementAtOrNull
Returns an element at the given index or null if the index is out of bounds of this collection.
assertNull(list.elementAtOrNull(10))
sortBy
Returns a list of all elements, sorted by the specified comparator.
assertEquals(listOf(3, 7, 2, 5), unsortedList.sortBy { it % 3 })
plus
Returns a list containing all elements of the original collection and then all elements of the given
collection. Because of the name of the function, we can use the ‘+’ operator with it.
assertEquals(listOf(1, 2, 3, 4, 5, 6, 7, 8), list + listOf(7, 8))
And many more
25. Null safety in Kotlin
Being null considered the billion-dollar mistake by its own creator (Tony Hoare)
// this is Java and it will compile
Forecast forecast = null;
forecast.toString();
// this is Kotlin and it won’t compile
val forecast: Forecast? = null
forecast.toString()
// use !! if you a sure that this can’t be null
forecast!!.toString();
// use ?. if you hesitate
forecast?.toString();
26. Lazy
If you don’t want to declare variable as nullable but you can’t initialize it in
constructor use lateinit
class App : Application() {
companion object {
lateinit var instance: App
}
overrride fun onCreate() {
super.onCreate()
instance = this
}
}
27. Flow control (IF)
In Kotlin, if is an expression, i.e. it returns a value.
if branches can be blocks, and the last expression is the value of a block:
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
28. Flow control (WHEN)
when replaces the switch operator of C-like languages. In the simplest form
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x is neither 1 nor 2")
}
}
when {
x.isOdd() -> print("odd")
x.isEven() -> print("even")
else -> print("x is weird")
}
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("outside the range")
else -> print("none of the above")
}
29. For Loops
for iterates through anything that provides an iterator
for (item in collection) print(item)
for (i in array.indices) {
print(array[i])
}
for ((index, value) in array.withIndex()) {
println("at $index is $value")
}
30. Inconveniences
Code completion (variables declaration)
Java case
You need only type class name and
variable name comes by itself :)
Kotlin case
You should type everything :(