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
Conferences
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

eBook
€8.99 €26.99
Paperback
€32.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
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
Estimated delivery fee Deliver to Malta

Premium delivery 7 - 10 business days

€32.95
(Includes tracking information)

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 Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Malta

Premium delivery 7 - 10 business days

€32.95
(Includes tracking information)

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 the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela