You are on page 1of 11

Beginning

Your Kotlin Adventure


Kotlin is great language that makes Android development easier, faster, and
much more pleasant. In this chapter, we will discuss what Kotlin really is and
look at many Kotlin examples that will help us build even better Android
applications. Welcome to the amazing journey of Kotlin, that will change the
way you think about writing code and solving common programming problems.

In this chapter, we will cover the following topics:

First steps with Kotlin


Practical Kotlin examples
Creating new Kotlin project in Android Studio
Migrating existing Java project to Kotlin
The Kotlin standard library (stdlib)
Why Kotlin is a good choice to learn
Say hello to Kotlin
Kotlin is a modern, statically typed, Android-compatible language that fixes
many Java problems, such as null pointer exceptions or excessive code
verbosity. Kotlin is a language inspired by Swift, Scala, Groovy, C#, and many
other languages. Kotlin was designed by JetBrains professionals, based on
analysis of both developers experiences, best usage guidelines (most important
are clean code and effective Java), and data about this language's usage. Deep
analysis of other programming languages has been done. Kotlin tries hard to not
repeat the mistakes from other languages and take advantage of their most useful
features. When working with Kotlin, we can really feel that this is a mature and
well-designed language.

Kotlin takes application development to a whole new level by improving code


quality and safety and boosting developer performance. Official Kotlin support
for the Android platform was announced by Google in 2017, but the Kotlin
language has been here for some time. It has a very active community and Kotlin
adoption on the Android platform is already growing quickly. We can describe
Kotlin as a safe, expressive, concise, versatile, and tool-friendly language that
has great interoperability with Java and JavaScript. Let's discuss these features:

Safety: Kotlin offers safety features in terms of nullability and


immutability. Kotlin is statically typed, so the type of every expression is
known at compile time. The compiler can verify that whatever property or
method that we are trying to access or a particular class instance actually
exists. This should be familiar from Java which is also statically typed, but
unlike Java, Kotlin type system is much more strict (safe). We have to
explicitly tell the compiler whether the given variable can store null values.
This allows making the program fail at compile time instead of throwing a
NullPointerException at runtime:
Easy debugging: Bugs can be detected much faster during the development
phase instead of crashing the application after it is released and thus
damaging the user experience. Kotlin offers a convenient way to work with
immutable data. For example, it can distinguish mutable (read-write) and
immutable (read-only) collections by providing convenient interfaces
(under the hood collections are still mutable).
Conciseness: Most of the Java verbosity was eliminated. We need less code
to achieve common tasks and thus the amount of boilerplate code is greatly
reduced, even comparing Kotlin to Java 8. As a result, the code is also
easier to read and understand (expressive).
Interoperability: Kotlin is designed to seamlessly work side by side with
Java (cross-language project). The existing ecosystem of Java libraries and
frameworks works with Kotlin without any performance penalties. Many
Java libraries have even Kotlin-specific versions that allow more idiomatic
usage with Kotlin. Kotlin classes can also be directly instantiated and
transparently referenced from Java code without any special semantics and
vice versa. This allows us to incorporate Kotlin into existing Android
projects and use Kotlin easily together with Java (if we want to).
Versatility: We can target many platforms, including mobile applications
(Android), server-side applications (backend), desktop applications,
frontend code running in the browser, and even build systems (Gradle).

Any programming language is only as good as its tool support. Kotlin has
outstanding support for modern IDEs such as Android Studio, IntelliJ Idea, and
Eclipse. Common tasks like code assistance or refactoring are handled properly.
The Kotlin team works hard to make the Kotlin plugin better with every single
release. Most of the bugs are quickly fixed and many of the features requested
by the community are implemented.

Kotlin bug tracker: https://youtrack.jetbrains.com/issues/KT


Kotlin slack channel: http://slack.kotlinlang.org/

Android application development becomes much more efficient and pleasant


with Kotlin. Kotlin is compatible with JDK 6, so applications created in Kotlin
run safely even on old Android devices that precede Android 4.

Kotlin aims to bring you the best of both worlds by combining concepts and
elements from both procedural and functional programming. It follows many
guidelines are described in the book, Effective Java, 2nd Edition, by Joshua
Bloch which is considered must read a book for every Java developer.

On top of that, Kotlin is open sourced, so we can check out the project and be
actively involved in any aspect of the Kotlin project such as Kotlin plugins,
compilers, documentations or Kotlin language itself.
Awesome Kotlin examples
Kotlin is really easy to learn for Android developers because the syntax is
similar to Java and Kotlin often feels like natural Java evolution. At the
beginning, a developer usually writes Kotlin code having in mind habits from
Java, but after a while, it is very easy to move to more idiomatic Kotlin
solutions. Let's look at some cool Kotlin features, and see where Kotlin may
provide benefits by solving common programming tasks in an easier, more
concise, and more flexible way. We have tried to keep examples simple and self-
explanatory, but they utilize content from various parts of this book, so it's fine if
they are not fully understood at this point. The goal of this section is to focus on
the possibilities and present what can be achieved by using Kotlin. This section
does not necessarily need to fully describe how to achieve it. Let's start with
a variable declaration:
var name = "Igor" // Inferred type is String
name = "Marcin"

Notice that Kotlin does not require semicolons. You can still use them, but they
are optional. We also don't need to specify a variable type because it's inferred
from the context. Each time the compiler can figure out the type
from the context we don't have to explicitly specify it. Kotlin is a strongly typed
language, so each variable has an adequate type:
var name = "Igor"
name = 2 // Error, because name type is String

The variable has an inferred String type, so assigning a different value (integer)
will result in compilation error. Now, let's see how Kotlin improves the way to
add multiple strings using string templates:
val name = "Marcin"
println("My name is $name") // Prints: My name is Marcin

We need no more joining strings using the + character. In Kotlin, we can easily
incorporate single variable or even whole expression into string literals:
val name = "Igor"
println("My name is ${name.toUpperCase()}")
// Prints: My name is IGOR
In Java any variable can store null values. In Kotlin strict null safety forces us to
explicitly mark each variable that can store nullable values:
var a: String = "abc"
a = null // compilation error

var b: String? = "abc"


b = null // It is correct

Adding a question mark to a data type (string versus string?), we say that
variable can be nullable (can store null references). If we don't mark variable as
nullable, we will not be able to assign a nullable reference to it. Kotlin also
allows to deal with nullable variables in proper ways. We can use safe call
operator to safely call methods on potentially nullable variables:
savedInstanceState?.doSomething

The method doSomething will be invoked only if savedInstanceState has a non-null


value, otherwise the method call will be ignored. This is Kotlin's safe way to
avoid null pointer exceptions that are so common in Java.

Kotlin also has several new data types. Let's look at the Range data type that
allows us to define end inclusive ranges:
for (i in 1..10) {
print(i)
} // 12345678910

Kotlin introduces the Pair data type that, combined with infix notation, allows us
to hold a common pair of values:
val capitol = "England" to "London"
println(capitol.first) // Prints: England
println(capitol.second) // Prints: London

We can deconstruct it into separate variables using destructive declarations:


val (country, city) = capitol
println(country) // Prints: England
println(city) // Prints: London

We can even iterate through a list of pairs:


val capitols = listOf("England" to "London", "Poland" to "Warsaw")
for ((country, city) in capitols) {
println("Capitol of $country is $city")
}

// Prints:
// Capitol of England is London
// Capitol of Poland is Warsaw

Alternatively, we can use the forEach function:


val capitols = listOf("England" to "London", "Poland" to "Warsaw")
capitols.forEach { (country, city) ->
println("Capitol of $country is $city")
}

Note that Kotlin distinguishes between mutable and immutable collections by


providing a set of interfaces and helper methods (List versus MutableList, Set
versus Set versus MutableSet, Map versus MutableMap, and so on):
val list = listOf(1, 2, 3, 4, 5, 6) // Inferred type is List
val mutableList = mutableListOf(1, 2, 3, 4, 5, 6)
// Inferred type is MutableList

Immutable collection means that the collection state can't change after
initialization (we can't add/remove items). Mutable collection (quite obviously)
means that the state can change.

With lambda expressions, we can use the Android framework build in a very
concise way:
view.setOnClickListener {
println("Click")
}

Kotlin standard library (stdlib) contains many functions that allow us to perform
operations on collections in simple and concise way. We can easily perform
stream processing on lists:
val text = capitols.map { (country, _) -> country.toUpperCase() }
.onEach { println(it) }
.filter { it.startsWith("P") }
.joinToString (prefix = "Countries prefix P:")
// Prints: ENGLAND POLAND
println(text) // Prints: Countries prefix P: POLAND
.joinToString (prefix = "Countries prefix P:")

Notice that we don't have to pass parameters to a lambda. We can also define our
own lambdas that will allow us to write code in completely new way. This
lambda will allow us to run a particular piece of code only in Android
Marshmallow or newer.
inline fun supportsMarshmallow(code: () -> Unit) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
code()
}

//usage
supportsMarshmallow {
println("This code will only run on Android Nougat and newer")
}

We can make asynchronous requests easily and display responses on the main
thread using the doAsync function:
doAsync {
var result = runLongTask() // runs on background thread

uiThread {
toast(result) // run on main thread
}
}

Smart casts allow us to write code without performing redundant casting:


if (x is String) {
print(x.length) // x is automatically casted to String
}

x.length //error, x is not casted to a String outside if block

if (x !is String)
return

x.length // x is automatically casted to String

The Kotlin compiler knows that the variable x is of the type String after
performing a check, so it will automatically cast it to the String type, allowing it
to call all methods and access all properties of the String class without any
explicit casts.

Sometimes, we have a simple function that returns the value of a single


expression. In this case, we can use a function with an expression body to
shorten the syntax:
fun sum(a: Int, b: Int) = a + b
println (sum(2 + 4)) // Prints: 6

Using default argument syntax, we can define the default value for each function
argument and call it in various ways:
fun printMessage(product: String, amount: Int = 0,
name: String = "Anonymous") {
println("$name has $amount $product")
}

printMessage("oranges") // Prints: Anonymous has 0 oranges
printMessage("oranges", 10) // Prints: Anonymous has 10 oranges
printMessage("oranges", 10, "Johny")
// Prints: Johny has 10 oranges

The only limitation is that we need to supply all arguments without default
values. We can also use named argument syntax to specify function arguments:
printMessage("oranges", name = "Bill")

This also increases readability when invoking the function with multiple
parameters in the function call.

The data classes give a very easy way to define and operate on classes from the
data model. To define a proper data class, we will use the data modifier before
the class name:
data class Ball(var size:Int, val color:String)

val ball = Ball(12, "Red")
println(ball) // Prints: Ball(size=12, color=Red)

Notice that we have a really nice, human readable string representation of the
class instance and we do not need the new keyword to instantiate the class. We
can also easily create a custom copy of the class:
val ball = Ball(12, "Red")
println(ball) // prints: Ball(size=12, color=Red)
val smallBall = ball.copy(size = 3)
println(smallBall) // prints: Ball(size=3, color=Red)
smallBall.size++
println(smallBall) // prints: Ball(size=4, color=Red)
println(ball) // prints: Ball(size=12, color=Red)

The preceding constructs make working with immutable objects very easy and
convenient.

One of the best features in Kotlin are extensions. They allow us to add new
behavior (a method or property) to an existing class without changing its
implementation. Sometimes when you work with a library or framework, you
would like to have extra method or property for certain class. Extensions are a
great way to add those missing members. Extensions reduce code verbosity and
remove the need to use utility functions known from Java (for example, the
StringUtils class). We can easily define extensions for custom classes, third-party
libraries, or even Android framework classes. First of all, ImageView does not have
the ability to load images from network, so we can add the loadImage extension
method to load images using the Picasso library (an image loading library for
Android):
fun ImageView.loadUrl(url: String) {
Picasso.with(context).load(url).into(this)
}

\\usage
imageView.loadUrl("www.test.com\\image1.png")

We can also add a simple method displaying toasts to the Activity class:
fun Context.toast(text:String) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}

//usage (inside Activity class)
toast("Hello")

There are many places where usage of extensions will make our code simpler
and more concise. Using Kotlin, we can fully take advantage of lambdas to
simplify Kotlin code even more.

Interfaces in Kotlin can have default implementations as long as they don't hold
any state:
interface BasicData {
val email:String
val name:String
get() = email.substringBefore("@")
}

In Android, there are many applications where we want to delay object


initialization until it is needed (used). To solve this problem, we can use
delegates:
val retrofit by lazy {
Retrofit.Builder()
.baseUrl("https://www.github.com")
.addConverterFactory(MoshiConverterFactory.create())
.build()
}

Retrofit (a popular Android networking framework) property initialization will


be delayed until the value is accessed for the first time. Lazy initialization may
result in faster Android application startup time since loading is deferred to when
the variable is accessed. This is a great way to initialize multiple objects inside a
class, especially when not all of them are always needed (for certain class usage
scenario, we may need only specific objects) or when not every one of them is
needed instantly after class creation.

All the presented examples are only a glimpse of what can be accomplished with
Kotlin. We will learn how to utilize the power of Kotlin throughout this book.

You might also like