Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Kotlin Standard Library Cookbook
Kotlin Standard Library Cookbook

Kotlin Standard Library Cookbook: Master the powerful Kotlin standard library through practical code examples

Arrow left icon
Profile Icon Urbanowicz
Arrow right icon
€18.99 per month
Paperback Jul 2018 242 pages 1st Edition
eBook
€17.99 €26.99
Paperback
€32.99
Subscription
Free Trial
Renews at €18.99p/m
Arrow left icon
Profile Icon Urbanowicz
Arrow right icon
€18.99 per month
Paperback Jul 2018 242 pages 1st Edition
eBook
€17.99 €26.99
Paperback
€32.99
Subscription
Free Trial
Renews at €18.99p/m
eBook
€17.99 €26.99
Paperback
€32.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing
Table of content icon View table of contents Preview book icon Preview Book

Kotlin Standard Library Cookbook

Ranges, Progressions, and Sequences

In this chapter, we will cover the following recipes:

  • Exploring the use of range expressions to iterate through alphabet characters
  • Traversing through ranges using progression with a custom step value
  • Building custom progressions to traverse dates
  • Using range expressions with flow control statements
  • Discovering the concept of sequences
  • Applying sequences to solve algorithmic problems

Introduction

This chapter will focus on explaining the advantages of range expressions and sequences. These powerful data structure concepts offered by the Kotlin standard library can help you to improve the quality and readability of your code, as well as its safety and performance. Range expressions provide a declarative way of iterating through sets of comparable types using for loops. They are also useful for implementing concise and safe control flow statements and conditions. The Sequence class, as a missing supplement to the Collection type, provides a built-in lazy evaluation of its elements. In many cases, using sequences can help optimize data-processing operations and make the code more efficient in terms of computation complexity and memory consumption. The recipes covered in this chapter are going to focus on solving real-life programming problems. Moreover, at the same time, they are also going to explain how those concepts work under the hood.

Exploring the use of range expressions to iterate through alphabet characters

Ranges, provided by the Kotlin standard library, are a powerful solution for implementing iteration and conditional statements in a natural and safe way. A range can be understood as an abstract data type that represents a set of iterable elements and allows iteration through them in a declarative way. The ClosedRange interface from the kotlin.ranges package is a basic model of the range data structure. It contains references to the first and last elements of the range and provides the contains(value: T): Boolean and isEmpty(): Boolean functions, which are responsible for checking whether the specified element belongs to the range and whether the range is empty. In this recipe, we are going to learn how to declare a range that consists of alphabet characters and iterate through it in a decreasing order.

Getting ready

The Kotlin standard library provides functions that allow the declaration of ranges for the integral, primitive types, such as Int, Long, and Char. To define a new range instance, we can use the rangeTo() function. For example, we can declare a range of integers from 0 to 1000 in the following way:

val range: IntRange = 0.rangeTo(1000)

The rangeTo() function has also its own special operator equivalent, .., which allows the declaration of a range with a more natural syntax:

val range: IntRange = 0..1000

Also, in order to declare a range of elements in a decreasing order, we can use the downTo() function.

How to do it...

  1. Declare a decreasing range of alphabet characters:
'Z' downTo 'A'

2. Create a for loop to traverse the range:

for (letter in 'Z' downTo 'A') print(letter)

How it works...

As a result, we are going to get the following code printed out to the console:

ZYXWVUTSRQPONMLKJIHGFEDCBA

As you can see, there is also a downTo() extension function variant for the Char type. We are using it to create a range of characters from Z to A. Note that, thanks for the infix notation, we can omit the brackets while invoking the function—'Z' downTo 'A'.

Next, we are creating a for loop, which iterates through the range and prints out the subsequent Char elements. Using the in operator, we are specifying the object that is being iterated in the loop—and that's it! As you can see, the Kotlin syntax for the for loop is neat and natural to use.

Implementations of ranges of the primitive types, such as IntRange, LongRange, and CharRange, also contain Iterator interface implementations under the hood. They are being used while traversing the range using the for loop under the hood. In fact, the range implementing the Iterable interface is called a progression. Under the hood, the IntRange, LongRange, and CharRange classes inherit from the IntProgression, LongProgression, and CharProgression base classes, and they provide the implementations of the Iterator interface internally.

There's more...

There is also a convenient way to reverse the order of an already-defined progression. We can do so with the extension function provided for the IntProgression, LongProgression, and CharProgression types, which is called reversed(). It returns new instances of progressions with a reversed order of elements. Here is an example of how to use the reversed() function:

val daysOfYear: IntRange = 1..365
for(day in daysOfYear.reversed()) {
println("Remaining days: $day")
}

The preceding for loop prints the following text to the console:

Remaining days: 365
Remaining days: 364
Remaining days: 363

Remaining days: 2
Remaining days: 1

The Kotlin standard library offers also another handy extension function called until(), which allows the declaration of ranges that don't include the last element. It is pretty useful when working with classes that contain internal collections and don't provide elegant interfaces to access them. A good example would be the Android ViewGroup class, which is a container for the child View type objects. The following example presents how to iterate through the next indexes of any given ViewGroup instance children in order to modify the state of each of the children:

val container: ViewGroup = activity.findViewById(R.id.container) as ViewGroup
(0 until container.childCount).forEach {
val child: View = container.getChildAt(it)
child.visibility = View.INVISIBLE
}

The until() infix function helps to make the loop conditions clean and natural to understand.

See also

  • This recipe gave us an insight into how Kotlin standard library implementations of ranges for primitives are easy to work with. A problem can appear if we want to traverse non-primitive types using the for loop. However, it turns out we can easily declare a range for any Comparable type. This will be shown in the Building custom progressions to traverse dates recipe.
  • As you have noticed, we are using the in operator to specify the object that is being iterated in the loop. However, there are also other scenarios where the in and !in operators can be used together with ranges. We will investigate them in depth in the Using range expressions with flow control statements recipe.

Traversing through ranges using progression with a custom step value

Besides doing so for the Iterator instances, progressions implementations for integral types, such as the Int, Long, and Char types, also include the step property. The step value specifies the intervals between the subsequent elements of a range. By default, the step value of a progression is equal to 1. In this recipe, we are going to learn how to traverse a range of alphabet characters with a step value equal to 2. In the result, we want to have every second alphabet letter printed to the console.

Getting ready

The Kotlin standard library provides a convenient way of creating progression with a custom step value. We can do so using an extension function for progressions of integral types called step(). We can also benefit from the infix notation and declare a progression with a custom step, as follows:

val progression: IntProgression = 0..1000 step 100

If we were to use progression in the for loop, it would iterate 10 times:

val progression: IntProgression = 0..1000 step 100
for
(i in progression) {
println(i)
}

We could also achieve the same result by iterating with the while loop, as follows:

var i = 0
while (i <= 1000) {
println(i)
i += 100
}

How to do it...

  1. Declare a range of the Char type using the downTo() function:
'z' downTo 'a'
  1. Convert the range to a progression with a custom step value using the step() function:
'z' downTo 'a' step 2
  1. Use the forEach() function to iterate through the elements of the progression and print each of them to the console:
('z' downTo 'a' step 2).forEach { character -> print(character) }

How it works...

In the result, we are going to get the following code printed to the console:

zxvtrpnljhfdb

In the beginning, we declared a range containing all the alphabet characters in decreasing order with the downTo() function. Then, we transformed the range a the custom progression containing every second character with the step() function. Finally, we are using the Iterable.forEach() function to iterate through the next elements of the progression and print each of them to the console.

The step() extension function is available for the IntProgression, LongProgression, and CharProgression types. Under the hood, it creates a new instance of a progression copying the properties of the original one and setting up the new step value.

See also

  • Apart from iteration, range expressions are useful for defining flow control conditions. You can read more about this in the Using range expressions with flow control statements recipe.

Building custom progressions to traverse dates

Kotlin provides built-in support for ranges of primitive types. In the previous recipes, we worked with the IntRange and CharRange types, which are included in the Kotlin standard library. However, it is possible to implement a custom progression for any type by implementing the Comparable interface. In this recipe, we will learn how to create a progression of the LocalDate type and discover how to traverse the dates the easy way.

Getting ready

In order to accomplish the task, we need to start by getting familiar with the ClosedRange and Iterator interfaces. We need to use them to declare a custom progression for the LocalDate class:

public interface ClosedRange<T: Comparable<T>> {
public val start: T
public val endInclusive: T
public operator fun contains(value: T): Boolean {
return value >= start && value <= endInclusive
}
public fun isEmpty(): Boolean = start > endInclusive
}

The Iterator interface provides information about the subsequent values and their availability:

public interface Iterator<out T> {
public operator fun next(): T
public operator fun hasNext(): Boolean
}

The ClosedRange interface provides the minimum and maximum values of the range. It also provides the contains(value: T): Boolean and isEmpty(): Boolean functions, which check whether a given value belongs to the range and whether the range is empty respectively. Those two functions have default implementations provided in the ClosedRange interface. As the result, we don't need to override them in our custom implementation of the ClosedRange interface.

How to do it...

  1. Let's start with implementing the Iterator interface for the LocalDate type. We are going to create a custom LocalDateIterator class, which implements the Iterator<LocalDate> interface:
class DateIterator(startDate: LocalDate,
val endDateInclusive: LocalDate,
val stepDays: Long) : Iterator<LocalDate> {
private var currentDate = startDate
override fun hasNext() = currentDate <= endDateInclusive
override fun next(): LocalDate {
val next = currentDate
currentDate = currentDate.plusDays(stepDays)
return next
}
}
  1. Now, we can implement the progression for the LocalDate type. Let's create a new class called DateProgression, which is going to implement the Iterable<LocalDate> and ClosedRange<LocalDate> interfaces:
class DateProgression(override val start: LocalDate,
override val endInclusive: LocalDate,
val stepDays: Long = 1) :
Iterable<LocalDate>,
ClosedRange<LocalDate> {
override fun iterator(): Iterator<LocalDate> {
return DateIterator(start, endInclusive, stepDays)
}

infix fun step(days: Long) = DateProgression(start, endInclusive, days)
}
  1. Finally, declare a custom rangeTo operator for the LocalDate class:
operator fun LocalDate.rangeTo(other: LocalDate) = DateProgression(this, other)

How it works...

Now, we are able to declare range expressions for the LocalDate type. Let's see how to use our implementation. In the following example, we will use our custom LocalDate.rangeTo operator implementation in order to create a range of dates and iterate its elements:

val startDate = LocalDate.of(2020, 1, 1)
val endDate = LocalDate.of(2020, 12, 31)
for (date in startDate..endDate step 7) {
println("${date.dayOfWeek} $date ")
}

As a result, we are going to have the dates printed out to the console with a week-long interval:

WEDNESDAY 2020-01-01
WEDNESDAY 2020-01-08
WEDNESDAY 2020-01-15
WEDNESDAY 2020-01-22
WEDNESDAY 2020-01-29
WEDNESDAY 2020-02-05
...

WEDNESDAY 2020-12-16
WEDNESDAY 2020-12-23
WEDNESDAY 2020-12-30

The DateIterator class holds three properties—currentDate: LocalDate, endDateInclusive: LocalDate, and stepDays: Long. In the beginning, the currentDate property is initialized with the startDate value passed in the constructor. Inside the next() function, we are returning the currentDate value and updating it to the next date value using a given stepDays property interval.

The DateProgression class combines the functionalities of the Iterable<LocalDate> and ClosedRange<LocalDate> interfaces. It provides the Iterator object required by the Iterable interface by returning the DateIterator instance. It also overrides the start and endInclusive properties of the ClosedRange interface. There is also the stepDays property with a default value equal to 1. Note that every time the step function is called, a new instance of the DateProgression class is being created.

You can follow the same pattern to implement custom progressions for any class that implements the Comparable interface.

Using range expressions with flow control statements

Apart from iterations, Kotlin range expressions can be useful when it comes to working with flow control statements. In this recipe, we are going to learn how to use range expressions together with if and when statements in order to tune up the code and make it safe. In this recipe, we are going to consider an example of using the in operator to define a condition of an if statement.

Getting ready

Kotlin range expressions—represented by the ClosedRange interface—implement a contains(value: T): Boolean function, which returns an information if a given parameter belongs to the range. This feature makes it convenient to use ranges together with control flow instructions. The contains() function has also its equivalent operator, in, and its negation, !in.

How to do it...

  1. Let's create a variable and assign to it a random integer value:
val randomInt = Random().nextInt()
  1. Now we can check whether the randomInt value belongs to the scope of integers from 0 to 10 inclusive using range expressions:
if (randomInt in 0..10) {
print("$randomInt belongs to <0, 10> range")
} else {
print("$randomInt doesn't belong to <0, 10> range")
}

How it works...

We have used a range expression together with the in operator in order to define a condition for the if statement. The condition statement is natural to read and concise. In contrast, an equivalent classic implementation would look like this:

val randomInt = Random(20).nextInt()
if (randomInt >= 0 && randomInt <= 10) {
print("$randomInt belongs to <0, 10> range")
} else {
print("$randomInt doesn't belong to <0, 10> range")
}

No doubt, the declarative approach using the range and in operator is cleaner and easier to read, compared to classic, imperative-style condition statements.

There's more...

Range expressions can enhance use of the when expression as well. In the following example, we are going to implement a simple function that will be responsible for mapping a student's exam score to a corresponding grade. Let's say we have the following enum class model for student grades:

enum class Grade { A, B, C, D }

We can define a function that will map the exam score value, in the 0 to 100 % range, to the proper grade (A, B, C, or D) using a when expression, as follows:

fun computeGrade(score: Int): Grade =
when (score) {
in 90..100 -> Grade.A
in 75 until 90 -> Grade.B
in 60 until 75 -> Grade.C
in 0 until 60 -> Grade.D
else -> throw IllegalStateException("Wrong score value!")
}

Using ranges together with the in operator makes the implementation of the computeGrade() function much cleaner and more natural than the classic equivalent implementation using traditional comparison operators, such as <, >, <=, and >=.

See also

  • If you'd like to discover more about lambdas, the infix notation, and operator overloading, go ahead and dive into Chapter 2, Expressive Functions and Adjustable Interfaces

Discovering the concept of sequences

In terms of high-level functionalities, the Sequence and Collection data structures are nearly the same. They both allow iteration through their elements. There are also many powerful extension functions in the Kotlin standard library that provide declarative-style data-processing operations for each of them. However, the Sequence data structure behaves differently under the hood—it delays any operations on its elements until they are finally consumed. It instantiates the subsequent elements on the go while traversing through them. These characteristics of Sequence, called lazy evaluation, make this data structure quite similar to the Java concept, Stream. To understand all of this better, we are going to implement a simple data-processing scenario to analyze the efficiency and behavior of Sequence and contrast our findings with Collection-based implementation.

Getting ready

Let's consider the following example:

val collection = listOf("a", "b", "c", "d", "e", "f", "g", "h")
val transformedCollection = collection.map {
println("Applying map function for $it")
it
}
println(transformedCollection.take(2))

In the first line, we created a list of strings and assigned it to the collection variable. Next, we are applying the map() function to the list. Mapping operation allows us to transform each element of the collection and return a new value instead of the original one. In our case, we are using it just to observe that map() was invoked by printing the message to the console. Finally, we want to filter our collection to contain only the first two elements using the take() function and print the content of the list to the console.

In the end, the preceding code prints the following output:

Applying map function for a
Applying map function for b
Applying map function for c
Applying map function for d
Applying map function for e
Applying map function for f
Applying map function for g
Applying map function for h
[a, b]

As you can see, the map() function was properly applied to every element of the collection and the take() function has properly filtered the elements of the list. However, it would not be an optimal implementation if we were working with a larger dataset. Preferably, we would like to wait with the execution of the data-processing operations until we know what specific elements of the dataset we really need, and then apply those operations only to those elements. It turns out that we can easily optimize our scenario using the Sequence data structure. Let's explore how to do it in the next section.

How to do it...

  1. Declare a Sequence instance for the given elements:
val sequence = sequenceOf("a", "b", "c", "d", "e", "f", "g", "h")
  1. Apply the mapping operation to the elements of the sequence:
val sequence = sequenceOf("a", "b", "c", "d", "e", "f", "g", "h")
val transformedSequence = sequence.map {
println("Applying map function for $it")

it
}
  1. Print the first two elements of the sequence to the console:
val sequence = sequenceOf("a", "b", "c", "d", "e", "f", "g", "h")

val transformedSequence = sequence.map {
println("Applying map function for $it")
it
}
println(transformedSequence.take(2).toList())

How it works...

The Sequence-based implementation is going to give us the following output:

Applying map function for a
Applying map function for b
[a, b]

As you can see, replacing the Collection data structure with the Sequence type allows us to gain the desired optimization.

The scenario considered in this recipe was implemented identically—first, using List, then using the Sequence type. However, we can notice the difference in the behavior of the Sequence data structure compared to that of Collection. The map() function was applied only to the first two elements of the sequence, even though the take() function was called after the mapping transformation declaration. It's also worth noting that in the example using Collection, the mapping was performed instantly when the map() function was invoked. In the case of Sequence, mapping was performed at the time of the evaluation of its elements while printing them to the console, and more precisely while converting Sequence to the List type with the following line of code:

println(transformedSequence.take(2).toList())

There's more...

There is a convenient way of transforming Collection to Sequence. We can do so with the asSequence() extension function provided by the Kotlin standard library for the Iterable type. In order to convert a Sequence instance into a Collection instance, you can use the toList() function.

See also

  • Thanks to the feature of Sequence lazy evaluation, we have avoided needless calculations, increasing the performance of the code at the same time. Lazy evaluation allows the implementation of sequences with a potentially infinite number of elements and turns out to be effective when implementing algorithms as well.

  • You can explore a Sequence-based implementation of the Fibonacci algorithm in the Applying sequences to solve algorithmic problems recipe. It presents, in more detail, another useful function for defining sequences called generateSequence().

Applying sequences to solve algorithmic problems

In this recipe, we are going to get familiar with the generateSequence() function, which provides an easy way to define the various types of sequences. We will use it to implement an algorithm for generating Fibonacci numbers.

Getting ready

The basic variant of the generateSequence() function is declared as follows:

fun <T : Any> generateSequence(nextFunction: () -> T?): Sequence<T>

It takes one parameter called nextFunction, which is a function that returns the next elements of the sequence. Under the hood, it is being invoked by the Iterator.next() function, inside the Sequence class' internal implementation, and allows instantiation of the next object to be returned while consuming the sequence values.

In the following example, we are going to implement a finite sequence that emits integers from 10 to 0:

var counter = 10
val sequence: Sequence<Int> = generateSequence {
counter--.takeIf { value: Int -> value >= 0 }
}
print(sequence.toList())

The takeIf() function applied to the current counter value checks whether its value is greater or equal to 0. If the condition is fulfilled, it returns the counter value; otherwise, it returns null. Whenever null is returned by the generateSequence() function, the sequence stops. After the takeIf function returns the value, the counter value is post-decremented. The preceding code will result in the following numbers being printed to the console:

[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

The subsequent values of the Fibonacci sequence are generated by summing up their two preceding ones. Additionally, the two first values are equal to 0 and 1. In order to implement such a sequence, we are going to use an extended variant of the generateSequence() function with an additional seed parameter, declared as follows:

fun <T : Any> generateSequence(seed: T?, nextFunction: (T) -> T?): Sequence<T>

How to do it...

  1. Declare a function called fibonacci() and use the generateSequence() function to define a formula for the next elements of the sequence:
fun fibonacci(): Sequence<Int> {
return generateSequence(Pair(0, 1)) { Pair(it.second, it.first + it.second) }
.map { it.first }
}
  1. Use the fibonacci() function to print the next Fibonacci numbers to the console:
println(fibonacci().take(20).toList())

How it works...

As a result, we are going to get the next 20 Fibonacci numbers printed to the console:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]

The additional seed parameter in the generateSequence() provides a starting value. The nextFunction() function is applied to the seed while computing the second value. Later on, it is generating each following element using its preceding value. However, in the case of the Fibonacci sequence, we have two initial values and we need a pair of preceding values in order to compute the next value. For this reason, we wrapped them in Pair type instances. Basically, we are defining a sequence of Pair<Int, Int> type elements, and in each nextFunction() call, we are returning a new pair that holds the values updated accordingly. At the end, we just need to use the map() function to replace each Pair element with the value of its first property. As a result, we are getting an infinite sequence of integer types returning the subsequent Fibonacci numbers.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Get the most out of the Kotlin library to develop high-quality portable applications
  • Explore Kotlin’s powerful support for data processing and I/O operations
  • Discover ways to enhance your Android application development

Description

For developers who prefer a more simplistic approach to coding, Kotlin has emerged as a valuable solution for effective software development. The Kotlin standard library provides vital tools that make day-to-day Kotlin programming easier. This library features core attributes of the language, such as algorithmic problems, design patterns, data processing, and working with files and data streams. With a recipe-based approach, this book features coding solutions that you can readily execute. Through the book, you’ll encounter a variety of interesting topics related to data processing, I/O operations, and collections transformation. You’ll get started by exploring the most effective design patterns in Kotlin and understand how coroutines add new features to JavaScript. As you progress, you'll learn how to implement clean, reusable functions and scalable interfaces containing default implementations. Toward the concluding chapters, you’ll discover recipes on functional programming concepts, such as lambdas, monads, functors, and Kotlin scoping functions, which will help you tackle a range of real-life coding problems. By the end of this book, you'll be equipped with the expertise you need to address a range of challenges that Kotlin developers face by implementing easy-to-follow solutions.

Who is this book for?

This book is for software developers who are familiar with Kotlin’s basics and want to discover more advanced features and concepts, especially those provided by the Kotlin standard library. Experienced software developers familiar with the functional programming paradigm and other programming languages who want to switch to Kotlin will also find this book useful. It will also help Java developers looking to switch to Kotlin and integrate it into existing Java Virtual Machine (JVM) projects.

What you will learn

  • Work with ranges, progressions, and sequences in use cases
  • Add new functionalities to current classes with Kotlin extensions
  • Understand elements such as lambdas, closures, and monads
  • Build a REST API consumer with Retrofit and a coroutine adapter
  • Discover useful tips and solutions for creating Android projects
  • Explore the benefits of standard library features

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jul 30, 2018
Length: 242 pages
Edition : 1st
Language : English
ISBN-13 : 9781788837668
Vendor :
JetBrains
Category :
Languages :
Tools :

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing

Product Details

Publication date : Jul 30, 2018
Length: 242 pages
Edition : 1st
Language : English
ISBN-13 : 9781788837668
Vendor :
JetBrains
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 106.97
Learning Concurrency in Kotlin
€36.99
Kotlin Standard Library Cookbook
€32.99
Hands-On Design Patterns with Kotlin
€36.99
Total 106.97 Stars icon
Banner background image

Table of Contents

10 Chapters
Ranges, Progressions, and Sequences Chevron down icon Chevron up icon
Expressive Functions and Adjustable Interfaces Chevron down icon Chevron up icon
Shaping Code with Kotlin Functional Programming Features Chevron down icon Chevron up icon
Powerful Data Processing Chevron down icon Chevron up icon
Tasteful Design Patterns Adopting Kotlin Concepts Chevron down icon Chevron up icon
Friendly I/O Operations Chevron down icon Chevron up icon
Making Asynchronous Programming Great Again Chevron down icon Chevron up icon
Best Practices for the Android, JUnit, and JVM UI Frameworks Chevron down icon Chevron up icon
Miscellaneous Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is included in a Packt subscription? Chevron down icon Chevron up icon

A subscription provides you with full access to view all Packt and licnesed content online, this includes exclusive access to Early Access titles. Depending on the tier chosen you can also earn credits and discounts to use for owning content

How can I cancel my subscription? Chevron down icon Chevron up icon

To cancel your subscription with us simply go to the account page - found in the top right of the page or at https://subscription.packtpub.com/my-account/subscription - From here you will see the ‘cancel subscription’ button in the grey box with your subscription information in.

What are credits? Chevron down icon Chevron up icon

Credits can be earned from reading 40 section of any title within the payment cycle - a month starting from the day of subscription payment. You also earn a Credit every month if you subscribe to our annual or 18 month plans. Credits can be used to buy books DRM free, the same way that you would pay for a book. Your credits can be found in the subscription homepage - subscription.packtpub.com - clicking on ‘the my’ library dropdown and selecting ‘credits’.

What happens if an Early Access Course is cancelled? Chevron down icon Chevron up icon

Projects are rarely cancelled, but sometimes it's unavoidable. If an Early Access course is cancelled or excessively delayed, you can exchange your purchase for another course. For further details, please contact us here.

Where can I send feedback about an Early Access title? Chevron down icon Chevron up icon

If you have any feedback about the product you're reading, or Early Access in general, then please fill out a contact form here and we'll make sure the feedback gets to the right team. 

Can I download the code files for Early Access titles? Chevron down icon Chevron up icon

We try to ensure that all books in Early Access have code available to use, download, and fork on GitHub. This helps us be more agile in the development of the book, and helps keep the often changing code base of new versions and new technologies as up to date as possible. Unfortunately, however, there will be rare cases when it is not possible for us to have downloadable code samples available until publication.

When we publish the book, the code files will also be available to download from the Packt website.

How accurate is the publication date? Chevron down icon Chevron up icon

The publication date is as accurate as we can be at any point in the project. Unfortunately, delays can happen. Often those delays are out of our control, such as changes to the technology code base or delays in the tech release. We do our best to give you an accurate estimate of the publication date at any given time, and as more chapters are delivered, the more accurate the delivery date will become.

How will I know when new chapters are ready? Chevron down icon Chevron up icon

We'll let you know every time there has been an update to a course that you've bought in Early Access. You'll get an email to let you know there has been a new chapter, or a change to a previous chapter. The new chapters are automatically added to your account, so you can also check back there any time you're ready and download or read them online.

I am a Packt subscriber, do I get Early Access? Chevron down icon Chevron up icon

Yes, all Early Access content is fully available through your subscription. You will need to have a paid for or active trial subscription in order to access all titles.

How is Early Access delivered? Chevron down icon Chevron up icon

Early Access is currently only available as a PDF or through our online reader. As we make changes or add new chapters, the files in your Packt account will be updated so you can download them again or view them online immediately.

How do I buy Early Access content? Chevron down icon Chevron up icon

Early Access is a way of us getting our content to you quicker, but the method of buying the Early Access course is still the same. Just find the course you want to buy, go through the check-out steps, and you’ll get a confirmation email from us with information and a link to the relevant Early Access courses.

What is Early Access? Chevron down icon Chevron up icon

Keeping up to date with the latest technology is difficult; new versions, new frameworks, new techniques. This feature gives you a head-start to our content, as it's being created. With Early Access you'll receive each chapter as it's written, and get regular updates throughout the product's development, as well as the final course as soon as it's ready.We created Early Access as a means of giving you the information you need, as soon as it's available. As we go through the process of developing a course, 99% of it can be ready but we can't publish until that last 1% falls in to place. Early Access helps to unlock the potential of our content early, to help you start your learning when you need it most. You not only get access to every chapter as it's delivered, edited, and updated, but you'll also get the finalized, DRM-free product to download in any format you want when it's published. As a member of Packt, you'll also be eligible for our exclusive offers, including a free course every day, and discounts on new and popular titles.