Bin Uzayr S. Kotlin. The Ultimate Guide 2023
Bin Uzayr S. Kotlin. The Ultimate Guide 2023
Bin Uzayr S. Kotlin. The Ultimate Guide 2023
Kotlin is a versatile language with some interesting and cool features like compat-
ibility, low runtime, and efficient coding characteristics. The features that help dis-
tinguish Kotlin from other languages are its reliability, tool support, and interoper-
ability. It is a simplified version of Java that is much easier to deal with.
All of this indicates that there is already a high demand for Kotlin developers, and
that demand will continue to grow in the future. Furthermore, if you are looking to
build native Android apps, Kotlin is the language that you should be using.
Kotlin
The Ultimate Guide
Edited by
Sufyan bin Uzayr
First edition published 2023
by CRC Press
6000 Broken Sound Parkway NW, Suite 300, Boca Raton, FL 33487-2742
and by CRC Press
4 Park Square, Milton Park, Abingdon, Oxon, OX14 4RN
CRC Press is an imprint of Taylor & Francis Group, LLC
© 2023 Sufyan bin Uzayr
Reasonable efforts have been made to publish reliable data and information, but the author and
publisher cannot assume responsibility for the validity of all materials or the consequences of their use.
The authors and publishers have attempted to trace the copyright holders of all material reproduced in
this publication and apologize to copyright holders if permission to publish in this form has not been
obtained. If any copyright material has not been acknowledged please write and let us know so we may
rectify in any future reprint.
Except as permitted under U.S. Copyright Law, no part of this book may be reprinted, reproduced,
transmitted, or utilized in any form by any electronic, mechanical, or other means, now known or
hereafter invented, including photocopying, microfilming, and recording, or in any information
storage or retrieval system, without written permission from the publishers.
For permission to photocopy or use material electronically from this work, access www.copyright.com
or contact the Copyright Clearance Center, Inc. (CCC), 222 Rosewood Drive, Danvers, MA 01923,
978-750-8400. For works that are not available on CCC please contact mpkbookspermissions@tandf.
co.uk
Trademark Notice: Product or corporate names may be trademarks or registered trademarks and are
used only for identification and explanation without intent to infringe.
DOI: 10.1201/9781003308447
Typeset in Minion
by KnowledgeWorks Global Ltd.
Contents
Acknowledgments, xxi
About the Author, xxiii
v
vi ◾ Contents
ARRAYS IN KOTLIN27
Creating Arrays27
Arrays of the Primitive Type28
Elements of an Array Can Be Get and Set28
Array Length in Kotlin28
Loop through an Array29
Check if an Element Exists29
Distinct Values from the Array29
Dropping Elements from the Array30
Checking an Empty Array30
RANGES IN KOTLIN30
Creating Ranges Using the rangeTo() Function31
Creating the Ranges Using the .. Operator31
Creating the Ranges Using downTo() Operator31
step() Function in Kotlin32
Range of Characters in Kotlin32
reversed() Function in Kotlin32
until() Function in Kotlin32
The last, first, and step Elements33
Filtering Ranges33
Distinct Values in Range33
Range Utility Functions34
FUNCTIONS IN KOTLIN34
Built-in Functions in Kotlin34
User-Defined Functions34
Function Parameters35
Return Values35
Unit-Returning Functions36
Recursive Function in Kotlin36
Tail Recursion in Kotlin37
Higher-Order Functions38
viii ◾ Contents
COMPOSITION138
Substitution Principle of Liskov139
Antipatterns of Implementation Inheritance140
Inheritance of a Single Implementation 140
Tight Coupling141
Unnecessary Exposure of Superclass APIs141
Exploding Numbers of Subclasses142
Composition Refactoring143
UserMediator Class Is Being Refactored 143
From Composition to Aggregation144
Handling the Exposure Issue146
Composition over Inheritance147
The Kotlin Method 147
ENCAPSULATION149
POLYMORPHISM150
ENCAPSULATION AND PROCEDURAL PROGRAMMING
IN KOTLIN152
Example of Procedural Programming152
OOP153
Tips for Choosing between Procedural and OOP 153
Procedural 154
OOP and Encapsulation 154
Putting Everything Together 154
LAMBDA EXPRESSION184
Inference in Lambda Types185
Type Declaration in Lambdas185
it: Implicit Name of a Single-Parameter186
Returning a Value from a Lambda Expression187
ANONYMOUS FUNCTION187
Return Type and Parameters188
The Distinction between Lambda Expressions and
Anonymous Functions188
HIGHER-ORDER FUNCTIONS IN KOTLIN188
Higher-Order Function189
Returning a Function from a Higher-Order Function192
KOTLIN LOCAL FUNCTIONS193
SCOPE FUNCTION IN KOTLIN196
SCOPE FUNCTIONS197
Utilization of Scope Functions197
Scope Function Types198
Object References202
Return Values203
KOTLIN COLLECTIONS204
Types of Collections204
Immutable Collection 204
Mutable Collection 206
ArrayList IN KOTLIN207
listOf() IN KOTLIN211
Indexing List Elements in Kotlin212
The First and Last Elements212
Iteration Methods for Lists213
Sorting the List’s Elements214
The Functions contains() and containsAll() 215
setOf() in Kotlin216
Set Indexing217
Contents ◾ xv
Set Basics217
The Functions contains() and containsAll() 218
mutableSetOf() METHOD IN KOTLIN219
Set Indexing220
Set the First and Last Element221
Traversal in a mutableSet221
The Methods contains() and containsAll() 221
hashSetOf() IN KOTLIN222
hashSet Traversal224
Indexing in a hashSet224
The Functions contains() and containsAll() 224
mapOf () in Kotlin225
Map Size226
Empty Map226
Get Map Values227
Map Contains Keys or Values227
Two Values and the Same Key228
HashMap IN KOTLIN228
HashMap Functions Use229
HashMap Time Complexity232
String Interpolation278
Infer Types279
Semantic Test Naming280
Safe Operator?280
Elvis Throws281
List Literals in Annotations281
Collection Helpers282
No more .equals()283
Method Readability – Named Parameters284
HOW KOTLIN OUTPERFORMS JAVA IN SOLVING
LONG-STANDING SECURITY ISSUES285
Typing, Syntax, and Speed Compared285
Null Reference Exceptions Pose Security Risks286
Kotlin Has Everything That Java Needs287
Finally, There Is More to It Than Simply Null288
WHAT EXACTLY IS APPLICATION HARDENING?289
What Is the Purpose of Application Hardening?289
Is Our Application in Need of Hardening?289
Application Hardening Methods290
Benefits of Application Hardening291
Application Patches291
APPRAISAL, 319
BIBLIOGRAPHY, 357
INDEX, 363
Acknowledgments
There are many people who deserve to be on this page, for this book would
not have come into existence without their support. That said, some names
deserve a special mention, and I am genuinely grateful to:
xxi
About the Author
Sufyan bin Uzayr is a writer, coder, and entrepreneur with over a decade
of experience in the industry. He has authored several books in the past, per-
taining to a diverse range of topics, ranging from History to Computers/IT.
Sufyan is the Director of Parakozm, a multinational IT company spe-
cializing in EdTech solutions. He also runs Zeba Academy, an online
learning and teaching vertical with a focus on STEM fields.
Sufyan specializes in a wide variety of technologies, such as JavaScript,
Dart, WordPress, Drupal, Linux, and Python. He holds multiple degrees,
including ones in Management, IT, Literature, and Political Science.
Sufyan is a digital nomad, dividing his time between four countries. He
has lived and taught in universities and educational institutions around
the globe. Sufyan takes a keen interest in technology, politics, literature,
history, and sports, and in his spare time, he enjoys teaching coding and
English to young students.
Learn more at sufyanism.com.
xxiii
Chapter 1
IN THIS CHAPTER
➢➢ What is Kotlin?
➢➢ Major concepts
➢➢ Advantages and disadvantages
➢➢ Syntax and code basics
➢➢ Additional info
DOI: 10.1201/9781003308447-1 1
2 ◾ Kotlin: The Ultimate Guide
DISADVANTAGES OF KOTLIN
• Kotlin learning opportunities are limited: While most developers
are transitioning to Kotlin, a tiny number of developers are accessible
globally. It provides basic tools for learning programming languages
and answering numerous queries during the software development
process.
• Compilation time is longer: In several cases, Kotlin outperforms
Java, particularly during incremental constructions. Keep in mind
that when it comes to tidy building, Java will always create growth.
• Distinct from Java: While Kotlin and Java have certain similari-
ties, they also differ significantly. Mobile app developers who have
spent a considerable amount of time learning Kotlin cannot switch
to another programming language.
• Fewer Kotlin professionals to recruit: Despite Kotlin’s importance,
only a few programmers are now accessible in this industry. Any
mobile application developer who wants to work with Kotlin must be
well-versed in the language.
Android Development
Kotlin is the recommended language for Android development because it
allows developers to produce more concise, expressive, and secure code.
Android Studio, the official IDE for Android development, fully supports
6 ◾ Kotlin: The Ultimate Guide
it, so we can receive the same sort of code completion and type checking
to assist us in creating Kotlin code as we can with Java.
Because more people now access the Internet via mobile phones, most
companies must have a mobile presence. Because Android accounts for
more than 70% of the mobile phone market, Kotlin developers would be
in great demand even if they use Kotlin alone for Android development. It
may, however, be used for much more.
Data Science
Data Scientists have long used Java to crunch information, discover pat-
terns, and make predictions, so it seems to reason that Kotlin will find a
home in the field as well.
Data Scientists can utilize all of the normal Java libraries that they are
accustomed to using in Java projects, but they must develop their code in
Kotlin. Jupyter and Zeppelin, two tools that many Data Scientists regularly
utilize for data visualization and exploratory study, both support Kotlin.
Crash Course in Kotlin ◾ 7
KOTLIN’S ARCHITECTURE
A well-designed architecture is required for an application to grow its fea-
tures and meet the expectations of its end-user base. Kotlin has its own
proprietary architecture for allocating memory and generating high-qual-
ity outcomes for developers and end-users.
Coroutines and classes in Kotlin build the core, resulting in reduced
boilerplate code, improved speed, and enhanced efficiency. The Kotlin
compiler can respond differently in various contexts, most notably when
distinguishing between multiple types of languages.
Architecture in Kotlin.
• The first step is to include a “.kt” or kotlin file in the compiler’s path.
• In the second stage, the Kotlin compiler converts the code to
byte-code.
• In the third stage, the byte-code is loaded into the JVM and executed
by the JVM itself.
When two byte-code files execute on the JVM, they commence mutual
communication. This is how interoperability for Java, the feature of Kotlin,
was created.
When Kotlin targets JavaScript, it undergoes Kotlin to JavaScript
transformation.
8 ◾ Kotlin: The Ultimate Guide
• Persistence options include direct JDBC access, JPA, and the usage
of NoSQL databases via Java drivers. The kotlin-jpa JPA com-
piler plugin conforms Kotlin-compiled classes to the framework’s
requirements.
Let’s create a Kotlin environment with Intellij IDEA and run our first
Kotlin code.
• Install the most recent version of IntelliJ IDEA to get started.
JetBrains’ free Community Edition is available for download, https://
www.jetbrains.com/idea/download/#section=windows.
$ kotlinc firstpro.kt
Run the program now to view the output in the command-line compiler.
$kotlin firstpro.kt
Hello, Everyone
• Line 1: The first line is a comment that the compiler disregards. Comments
are added to programs to help readers comprehend the source code.
Kotlin accepts two types of comments:
• Single line comment:
// This is a single-line comment
The main() function is at the heart of any program. All Kotlin func-
tions begin with the fun keyword, then the function name (here
main), a list of parameters, an optional return type, then the func-
tion body ({…… .}).
The parameter – an array of strings and return units – is included
in the main function in this case. The unit type, equivalent to void in
Java, indicates that the function returns no value.
• Line 3: The third line is a statement that prints “Hello Everyone” to
the program’s standard output.
println("Hello Everyone")
• Number
• Character
• String
• Boolean
• Array
The following table lists all of the Kotlin number data types, the key-
words used to define their variable types, the amount of memory used by
the variables, and the value range stored in those variables.
Example:
fun main(args: Array<String>) {
val x: Int = 1000
val y: Double = 110.00
val fz Float = 110.00f
val a: Long = 1100000004
val b: Short = 100
val c: Byte = 1
println("Int Value is " + x)
println("Double Value is " + y)
println("Float Value is " + z)
println("Long Value is " + a )
println("Short Value is " + b)
println("Byte Value is " + c)
}
Example:
fun main(args: Array<String>) {
val escapedStrings : String = "I'm escaped
String!\n"
var rawStrings :String = """This is going to
be a
multiline string and will not have escape
sequence""";
print(escapedStrings)
println(rawStrings)
}
• toByte()
• toShort()
• toInt()
• toLong()
• toFloat()
• toDouble()
• toChar()
16 ◾ Kotlin: The Ultimate Guide
OPERATORS IN KOTLIN
An operator is a symbol that instructs the compiler to do particular math-
ematical or logical operations. Kotlin has a plethora of built-in operators,
including the following:
• Arithmetic Operators
• Relational Operators
• Assignment Operators
• Unary Operators
• Logical Operators
• Bitwise Operations
Example:
fun main(args: Array<String>) {
val a: Int = 50
val b: Int = 10
Crash Course in Kotlin ◾ 17
Example:
fun main(args: Array<String>) {
val a: Int = 50
val b: Int = 10
println("a > b = " + (a > b))
println("a < b = " + (a < b))
println("a >= b = " + (a >= b))
println("a <= b = " + (a <= b))
println("a == b = " + (a == b))
println("a != b = " + (a != b))
}
Example:
fun main(args: Array<String>) {
var a: Int = 50
a += 5
println("a += 5 = " + a )
a = 50;
a -= 5
println("a -= 5 = " + a)
a = 50
a *= 5
println("a *= 5 = " + a)
a = 50
a /= 5
println("a /= 5 = " + a)
a = 53
a %= 5
println("a %= 5 = " + a)
}
Example:
fun main(args: Array<String>) {
var a: Int = 50
var b:Boolean = true
println("+a = " + (+a))
println("-a = " + (-a))
println("++a = " + (++a))
println("--a = " + (--a))
println("!a = " + (!y))
}
Example:
fun main(args: Array<String>) {
var a: Boolean = true
var b:Boolean = false
println("a && b = " + (a && b))
println("a || b = " + (a || b))
println("!b = " + (!b))
}
Example:
fun main(args: Array<String>) {
var a:Int = 70
var b:Int = 15
var c:Int
c = a.shl(2)
println("a.shl(2) = " + c)
c = a.shr(2)
println("a.shr(2) = " + c)
c = a.and(b)
println("a.and(b) = " + c)
c = a.or(b)
println("a.or(b) = " + c)
c = a.xor(b)
println("a.xor(b) = " + c)
c = a.inv()
println("a.inv() = " + c)
}
BOOLEANS IN KOTLIN
We are often faced with a circumstance in which we must decide whether
to answer Yes or No, or whether to declare True or False. Kotlin features
a Boolean data type that can accept the values true or false to handle such
situations.
Example:
fun main(args: Array<String>) {
val isCold: Boolean = true
val isSummer: Boolean = false
println(isCold)
println(isSummer)
}
Example:
fun main(args: Array<String>) {
var a: Boolean = true
var b:Boolean = false
println("a && b = " + (a && b))
println("a || b = " + (a || b))
println("!b = " + (!b))
}
Example:
fun main(args: Array<String>) {
val a: Int = 50
val b: Int = 10
println("a > b = " + (a > b))
println("a < b = " + (a < b))
println("a >= b = " + (a >= b))
println("a <= b = " + (a <= b))
22 ◾ Kotlin: The Ultimate Guide
Boolean to String
To convert a Boolean object into its string form, use the toString() method.
This translation is required when assigning a true or false value to a
String variable.
STRINGS IN KOTLIN
In the Kotlin programming language, the string data type is used to hold a
string of characters. String values must be enclosed in double-quotes (“ ”)
or triple quotations (“““ ”””).
Kotlin supports two types of strings: Escaped String and Raw String.
• Escaped strings are stated within double quotes (“ ”) and may con-
tain escape characters such as ‘\n’, ‘\t’, ‘\b’, and so on.
Crash Course in Kotlin ◾ 23
• Raw strings are specified within triple quotes (“““ ”””) and can include
numerous lines of text without any escape characters.
Example:
fun main(args: Array<String>) {
val escapedStrings : String = "I escaped
String!\n"
var rawStrings :String = """This is going to
be a multiline
string and will
not have any escape sequence""";
print(escapedStrings)
println(rawStrings)
}
Example:
fun main(args: Array<String>) {
val name : String = "Sara AliKhan"
println("Name - $name") // Using the template
with variable name
println("Name length - ${name.length}") // Using
the template with expression.
}
String indices begin with 0; thus, if we want to access the fourth element
of a string, we need to provide an index as 3.
Example:
fun main(args: Array<String>) {
val name : String = "Sara AliKhan"
println(name[3])
println(name[5])
}
Example:
fun main(args: Array<String>) {
val name : String = "Sara AliKhan"
println("Length of name :" + name.length)
println("Length of name :" + name.count())
}
Example:
fun main(args: Array<String>) {
val name : String = "Sara AliKhan"
println("Index of last character in name :"
+ name.lastIndex)
}
Example:
fun main(args: Array<String>) {
val name : String = "Sara AliKhan"
println("The Upper case of name :" + name.
toUpperCase())
println("The Lower case of name :" + name.
toLowerCase())
}
Example:
fun main(args: Array<String>) {
var firstName : String = "Sara "
var lastName : String = "AliKhan"
println("The Full Name is :" + firstName +
lastName)
println("The Full Name is :" + firstName.
plus(lastName) )
}
Example:
fun main(args: Array<String>) {
var name : String = "Sara AliKhan"
println("Remove the first two characters from
name : " + name.drop(2))
println("Remove the last two characters from
name : " + name.dropLast(2))
}
26 ◾ Kotlin: The Ultimate Guide
Example:
fun main(args: Array<String>) {
var strg1 : String = "That's Ok"
var strg2 : String = "It's Alright"
println("strg1 : " + strg1)
println("strg2 : " + strg2)
}
Example:
fun main(args: Array<String>) {
var strg : String = "Meditation & Yoga are
synonymous with India"
println("The Index of Yoga in the string - " +
strg.indexOf("Yoga"))
}
Example:
fun main(args: Array<String>) {
var strg1 : String = "Apple"
var strg2 : String = "Apple"
println(strg1.compareTo(strg2))
}
Example:
fun main(args: Array<String>) {
var names : String = "Sara"
println(names.getOrNull(0))
println(names.getOrNull(2))
println(names.getOrNull(100))
}
Example:
fun main(args: Array<String>) {
var names : String = "Sara AliKhan"
println(names.toString())
}
ARRAYS IN KOTLIN
Arrays are used to store multiple items of the same data type, such as an
integer or string, in a single variable with a single variable name.
For example, if we need to hold the names of 1000 workers, rather than
establishing 1000 individual String variables, we may simply build a string
array with a size of 1000.
Kotlin, like any other modern programming language, supports arrays
and offers a comprehensive set of array characteristics and support meth-
ods for manipulating arrays.
Creating Arrays
In Kotlin, we use the arrayOf() method to build an array and insert the
values in a comma-separated list into it:
• byteArrayOf()
• charArrayOf()
• shortArrayOf()
• longArrayOf()
Example:
fun main(args: Array<String>) {
val fruits = arrayOf<String>("Grapes",
"Orange", "Kiwi", " Apple")
println( fruits [0])
println( fruits [3])
}
Example:
fun main(args: Array<String>) {
val fruits = arrayOf<String>("Grapes", "Orange",
"Kiwi", " Apple")
Crash Course in Kotlin ◾ 29
Example:
fun main(args: Array<String>) {
val fruits = arrayOf<String>("Grapes",
"Orange", "Kiwi", " Apple")
for( item in fruits ){
println( item )
}
}
Example:
fun main(args: Array<String>) {
val fruits = arrayOf<String>("Orange", " Apple
", "Grapes", "Banana")
if ("Apple" in fruits){
println( "The Apple exists in fruits" )
}else{
println( "The Apple does not exist in
fruits" )
}
}
Example:
fun main(args: Array<String>) {
val fruits = arrayOf<String>("Grapes",
"Orange", "Kiwi", " Apple ", "Grapes")
val distinct = fruits.distinct()
for( item in distinct ){
println( item )
}
}
Example:
fun main(args: Array<String>) {
val fruits = arrayOf<String>("Grapes",
"Orange", "Kiwi", " Apple ", "Grapes")
Example:
fun main(args: Array<String>) {
val fruits = arrayOf<String>()
println( "The Array is empty : " + fruits
.isEmpty())
}
RANGES IN KOTLIN
The range in Kotlin is defined by the two endpoint values included in the
range. Ranges in Kotlin are constructed with the rangeTo() method or by
Crash Course in Kotlin ◾ 31
utilizing the downTo or (..) operators. The main range operation is con-
tained, which is often used in the form of in and !in operators.
Example:
1..10 // The Range of integers starting from 1 to 10
a..z // The Range of characters starting from
the a to z
A..Z // The Range of capital characters
beginning from the A to Z
Because both ends of the range are always included, the 1..4 expression
corresponds to the numbers 1,2,3, and 4.
Example:
fun main(args: Array<String>) {
for ( numb in 1.rangeTo(4) ) {
println(numb)
}
}
Example:
fun main(args: Array<String>) {
for ( numb in 1..4 ) {
println(numb)
}
}
Example:
fun main(args: Array<String>) {
for ( numb in 4 downTo 1 ) {
println(numb)
}
}
Example:
fun main(args: Array<String>) {
for ( chr in 'a'..'d' ) {
println(chr)
}
}
Example:
fun main(args: Array<String>) {
for ( numb in (1..5).reversed() ) {
println(numb)
}
}
Example:
fun main(args: Array<String>) {
for ( numb in 1 until 5 ) {
println(numb)
}
}
Example:
fun main(args: Array<String>) {
println((6..10).first)
println((6..10 step 2).step)
println((6..10).reversed().last)
}
Filtering Ranges
The filter() method returns a list of elements that match a specified
predicate:
Example:
fun main(args: Array<String>) {
val x = 1..10
val y = x.filter { T -> T % 2 == 0 }
println(y)
}
Example:
fun main(args: Array<String>) {
val x = listOf(11, 11, 22, 44,4 4, 66, 10)
println(x.distinct())
}
34 ◾ Kotlin: The Ultimate Guide
Example:
fun main(args: Array<String>) {
val x = 1..10
println(x.min())
println(x.max())
println(x.sum())
println(x.average())
println(x.count())
}
FUNCTIONS IN KOTLIN
Kotlin is a statically typed language; functions play an essential part.
We are somewhat familiar with function. A function is a piece of
code written to execute a particular purpose. All current program-
ming languages provide functions, sometimes known as methods or
subroutines.
A function, in general, receives particular inputs called parameters,
performs specific actions on these inputs, and eventually returns a
value.
Example:
fun main(args: Array<String>) {
println("Hello, Everyone")
}
User-Defined Functions
Using the term fun, we can define our own function in Kotlin. A user-
defined function accepts one or more parameters, performs an action, and
returns the outcome as a value.
Crash Course in Kotlin ◾ 35
Syntax:
fun functionName(){
// body of the function
}
Once we’ve defined a function, we may call it as many times as we need to.
The following is a basic syntax for calling a Kotlin function:
functionName()
printHello()
}
fun printHello(){
println("Hello, Everyone")
}
Function Parameters
A user-defined function can accept Zero or more arguments. Parameters
are options that can use based on the situation. For example, the above-
defined function made no use of a parameter.
Below is an example of how to construct a user-defined function that
adds two numbers and prints their sum:
Return Values
A Kotlin function returns a value based on its parameters. Returning a
value is, once again, entirely voluntary.
36 ◾ Kotlin: The Ultimate Guide
Use the return keyword and provide the return type after the function’s
parentheses to return a value.
Here’s an example of a user-defined function that will add two numbers
and return the sum:
Unit-Returning Functions
If a function does not return useful value, its return type is Unit. Unit is a
type that has only one value which is Unit.
The declaration of the Unit return type is also optional. The preceding
code is equivalent to:
Syntax:
fun functionName(){
.....
Crash Course in Kotlin ◾ 37
functionName()
.....
}
Example:
fun main(args: Array<String>) {
val x = 4
val result = factorial(x)
println( result )
}
fun factorial(x:Int):Int{
val result:Int
if( x <= 1){
result = x
}else{
result = x*factorial(x-1)
}
return result
}
Higher-Order Functions
A higher-order function in Kotlin accepts another function as a parameter
and/or returns another function.
The following example is a function that accepts two integer arguments,
x and y, as well as another function operation as a parameter:
Syntax:
{variable with type -> body of function}
Example:
fun main(args: Array<String>) {
val upperCase = { str: String -> str.
toUpperCase() }
println( upperCase("hello, everyone") )
}
Example:
fun main(args: Array<String>) {
myFunction({println("The Inline function
parameter")})
}
inline fun myFunction(function:()-> Unit){
println("I'm inline function - A")
function()
println("I'm inline function - B")
}
• if expression
• if-else expression
• if-else-if ladder expression
• nested if expression
if Statement
If-statement is used to specify whether or not a block of statements should
be executed, i.e., if a specific condition is true, the statement or block
of statements should execute; else, the statement or block of statements
should not run.
Syntax:
if(condition) {
// code to run if condition is true
}
40 ◾ Kotlin: The Ultimate Guide
Flowchart:
Statement of if.
Example:
fun main(args: Array<String>) {
var c = 8
if(c > 0){
print("True, the number is positive")
}
}
if-else Statement
The if-else statement is comprised of two statements blocks. When the
condition is true, the ‘if’ statement is used to execute the code block; when
the condition is false, ‘else’ statement is used.
Syntax:
if(condition) {
// code to run if condition is true
}
Crash Course in Kotlin ◾ 41
else {
// code to run if condition is false
}
Flowchart:
Statement of if-else.
Example:
fun main(args: Array<String>) {
var a = 9
var b = 15
if(a > b){
print("Number 9 is larger than 15")
}
else{
println("Number 15 is larger than 9")
}
}
42 ◾ Kotlin: The Ultimate Guide
Syntax:
if(first-condition)
{
// code to run if the condition is true
}
else if(second-condition)
{
// the code to run if the condition is true
}
Crash Course in Kotlin ◾ 43
else
{
}
Flowchart:
Statement of if-else-if.
Example:
import java.util.Scanner
fun main(args: Array<String>) {
// to create object for scanner-class
val reader = Scanner(System.'in')
print("Enter number: ")
// to read next Integer-value
var numb = reader.nextInt()
var results = if ( numb > 0){
"$numb is a positive number"
}
else if( numb < 0){
"$numb is negative number"
}
44 ◾ Kotlin: The Ultimate Guide
else{
"$numb is equal to zero"
}
println(results)
}
nested if Expression
If statements nestled inside another if statement is referred to as nested if
statements. If the first condition is true, execute the associated block. Then
check for the if condition nested in the first block, and if it is also true, exe-
cute the related block. It will keep going till the last condition is satisfied.
Syntax:
if(condition1)
{
// code1
if(condition2)
{
// code2
}
}
Flowchart:
Statement of nested-if.
Crash Course in Kotlin ◾ 45
Example:
import java.util.Scanner
fun main(args: Array<String>) {
// to create object for the scanner class
val reader = Scanner(System.'in')
print("Enter three numbers: ")
var numb1 = reader.nextInt()
var numb2 = reader.nextInt()
var numb3 = reader.nextInt()
var maxi = if ( numb1 > numb2) {
if (numb1 > numb3) {
"$numb1 is the largest number"
}
else {
"$numsb is the largest number"
}
}
else if( numb2 > numb3){
"$numb2 is the largest number"
}
else{
"$numb3 is the largest number"
}
println(maxi)
}
Syntax:
while(condition) {
// code to run
}
46 ◾ Kotlin: The Ultimate Guide
Flowchart:
Statement of while-loop.
Using while loop, this Kotlin program prints integers from 1 to 20: We
use a while loop to show the numbers in the following code. To begin,
assign the variable numb to 1. Check whether the expression (number =
20) is true or false in a while loop. If true, it enters the block, runs the print
statement, and adds one to the number. This step is continued until the
condition is no longer true.
Using a while loop, this Kotlin program prints the elements of an array:
In the following code, we create an array (names), populate it with a ran-
dom number of strings, and set a variable index to 0. arrayName.size is
Crash Course in Kotlin ◾ 47
used to determine the size of an array. Provide the condition (index <
names.size) in the while loop.
If index value is less than or equal to the array size, it enters the block
and prints the name stored at the associated index after each iteration. It
increments the index value after each iteration. This step is continued until
the condition is no longer true.
Syntax:
do {
//code to run
{
while(condition)
48 ◾ Kotlin: The Ultimate Guide
Flowchart:
Statement of do-while-loop.
Example:
fun main(args: Array<String>) {
var numbr = 9
var factorial = 1
do {
factorial *= numbr
numbr--
}while(numbr > 0)
println("The Factorial of 9 is $factorial")
}
Syntax:
for(item in collection) {
// code to execute
}
The for loop in Kotlin is used to iterate across the following because they
all provide an iterator:
• Range
• Array
• String
• Collection
• We can’t iterate across Range from top to down unless we use DownTo:
fun main(args: Array<String>)
{
for (d in 6..1) {
print("$d ")
}
println("Print nothing")
}
• Iterate over the Range from top to down using downTo, and then step 3:
fun main(args: Array<String>)
{
for (d in 20 downTo 1 step 3) {
print("$d ")
}
}
• when as a statement
• when as an expression
Crash Course in Kotlin ◾ 53
import java.util.Scanner;
fun main(args: Array<String>) {
var reader = Scanner(System.'in')
print("Enter the largebody:")
var lbt = reader.next()
when(lbt) {
"Sun" -> println("The Sun is Star")
"Moon" -> println("The Moon is Satellite")
"Earth" -> println("The Earth is planet")
else -> println("We don't know anything")
}
}
import java.util.Scanner;
fun main(args: Array<String>) {
var reader = Scanner(System.'in')
print("Enterthename:")
var lbt = reader.next()
when(lbt) {
"Sun" -> println("The Sun is Star")
"Moon" -> println("The Moon is Satellite")
"Earth" -> println("The Earth is planet")
}
}
expression, we get a result that matches the argument, which we may keep
in a variable or simply display.
import java.util.Scanner;
fun main(args: Array<String>) {
var reader = Scanner(System.'in')
print("Enter month of the number:")
var monthyear = reader.nextInt()
var months = when(monthyear)
{
1->"Jan"
2->"Feb"
3->"March"
4->"April"
5->"May"
6->"June"
7->"July"
8->"Aug"
9->"Sept"
10->"Oct"
11->"Nov"
12->"Dec"
else -> {
println("Not month of the year")
}
}
println(months)
}
If the argument fails to meet any branch conditions, the other branch is
executed. Unless the compiler can demonstrate that branch conditions
handle all potential cases, the else branch is required as an expression. A
compiler error is raised if we cannot use the other branch.
Error:(7, 16) Kotlin: ‘when’ expression must be exhaustive, add the nec-
essary ‘else’ branch.
or not; thus, we combined all planet names into a single branch. Anything
other than the planet name will result in the else branch is performed.
import java.util.Scanner;
fun main(args: Array<String>) {
var reader = Scanner(System.'in')
print("Enter name of the planet: ")
var names = reader.next()
when(names) {
"Mercury", "Mars","Jupiter",
"Earth","Neptune","Saturn","Venus",
"Uranus" -> println("Planet")
else -> println("Neither the planet nor the star")
}
}
• Check whether the input value is inside the range: By using the in
or !in operator, we can check the range of arguments given in the
when block. The ‘in’ operator in Kotlin is used to check for the exis-
tence of a specific variable or attribute inside a range. The in opera-
tor returns true if argument is within a given range; the !in operator
returns true if the argument is not within a specific range.
import java.util.Scanner;
fun main(args: Array<String>) {
var reader = Scanner(System.'in')
print("Enter the month number of the year: ")
var numbr = reader.nextInt()
when(numbr){
in 1..3 -> println("It is the spring
season")
in 4..6 -> println("It is the summer
season")
in 7..8 ->println("It is the rainy
season")
in 9..10 -> println("It is the autumn
season")
in 11..12 -> println("It is the winter
season")
!in 1..12 ->println("Enter the valid month
of the year")
}
}
56 ◾ Kotlin: The Ultimate Guide
Syntax:
while(test expression) {
// code to run
if(break condition) {
break
}
// another code to run
}
Example:
fun main(args: Array<String>) {
var sum = 0
58 ◾ Kotlin: The Ultimate Guide
var d = 1
while(i <= Int.MAX_VALUE) {
sum += d
d++
if(d == 11) {
break
}
}
print("The sum of integers from 1 to 11: $sum")
}
To compute the sum of numbers from 1 to 10, we utilize a while loop and
a break statement in the above program. Make a variable sum with a value
of 0 as its initial value. Iterate through the loop once more, this time set-
ting variable I to 1.
Iterator now proceeds from d = 1 and runs the sum statement. When
iterator value d reaches 11, the break expression is performed, and the loop
is terminated without checking the test expression d = Int.MAX_VALUE.
The control is then transferred to the while block’s print() instruction,
which outputs the total number of integers = 55.
Syntax:
do {
//code to run
if(break-condition) {
break
}
while(test-expression)
Example:
fun main(args: Array<String>) {
var name = arrayOf("Earth","Venus","Jupiter","
Mars","Saturn","Uranus")
var d = 0
do{
Crash Course in Kotlin ◾ 59
In the above program, we traverse the array to display the names of plan-
ets. First, populate the array names with planet names, and d is the test
statement’s iterator. We use name.size to compute the size of an array.
The do block first prints the array’s element, then compares the array’s
value at any index to “Jupiter” every time. If it matches, increase the iter-
ator and run one more time. If the expressions match, the break expres-
sion is performed, and the do-while loop ends without checking for the test
expression.
Syntax:
for(iteration through iterator) {
// code to run
if(break-condition){
break
}
}
print("$d")
if(d == 's') {
break
}
}
}
Syntax:
outer@ while(condition) {
// code
inner@ while(condition) {
// code
if(breakcondition) {
Crash Course in Kotlin ◾ 61
break @outer
}
}
}
Example:
fun main(args: Array<String>) {
var numbr1 = 6
outer@ while (numb1 > 0) {
var numbr2 = 6
inner@ while (numb2 > 0) {
if (numbr1==2)
break@outer
println("numbr1 = $numbr1, numbr2 =
$numbr2")
numbr2--
}
numbr1--
}
}
Syntax:
outer@ do {
// code
inner@ do {
// code
if(breakcondition) {
break@outer
}
} while(condition)
} while(condition)
Example:
fun main(args: Array<String>) {
var numbr1 = 4
62 ◾ Kotlin: The Ultimate Guide
outer@ do {
var numbr2 = 4
inner@ do {
if (numbr1 == 2)
break@outer
println("numbr1 = $numbr1; numbr2 =
$numbr2")
numbr2--
} while (numbr2 > 0)
numbr1--
} while (numbr1 > 0)
}
Here, we print the same output as in the while loop. When the (numbr1 == 2)
condition is true, the break@outer command is executed, which termi-
nates the desired outer@ loop.
Syntax:
outer@ for(iteration through iterator) {
// code
inner@ for(iteration through iterator)
// code
if(breakcondition) {
break@outer
}
}
}
Example:
fun main(args: Array<String>) {
outer@ for (numbr1 in 4 downTo 1) {
inner@ for (numbr2 in 4 downTo 1) {
if (numbr1 == 2)
break@outer
Crash Course in Kotlin ◾ 63
Syntax:
while(condition) {
//code
if(condition for continue) {
continue
}
//code
}
Example:
fun main(args: Array<String>) {
var numbr = 0
while (numbr <= 15) {
if (numbr % 3 == 0) {
numbr++
continue
}
println(numbr)
64 ◾ Kotlin: The Ultimate Guide
numbr++
}
}
We display the numbers and skip all multiples of 3 in the prior program.
If a number is divisible by three, the statement (numbr % 3 == 0) is used to
determine if it is divisible by three. Increase the number without publish-
ing it to standard output if it is a multiple of three.
Syntax:
do{
// code
if(condition for continue) {
continue
}
}
while(condition)
Example:
fun main(args: Array<String>) {
var numbr = 1
do {
if (numbr <= 5 || numbr >=25) {
numbr++
continue
}
println("$numbr")
numb++
} while (numbr < 10)
}
the array planets utilizing an array of letters and an iterator. The equation
(c < 2) skips iterating over array indices less than two; therefore, the text
stored at indexes 0 and 1 is not shown.
Syntax:
for(iteration through iterator)
{
//code
if(condition for continue)
{
continue
}
}
Example:
fun main(args: Array<String>) {
var colors = arrayOf("Pink", "Green", "Black",
"White", "Grey")
for (c in colors.indices) {
if(c < 2){
continue
}
println(colors [c])
}
}
Syntax:
outer@ while(firstcondition) {
// code
inner@ while(secondcondition) {
//code
if(condition for continue) {
continue@outer
}
}
}
Example:
fun main(args: Array<String>) {
var numbr1 = 6
outer@ while (numb1 > 0) {
numbr1--
var numbr2 = 6
inner@ while (numbr2 > 0) {
if (numbr1 <= 2)
continue@outer
println("numbr1 = $numbr1, numbr2 =
$numbr2")
numbr2--
}
}
}
Syntax:
outer@ do {
// code
inner@ do {
Crash Course in Kotlin ◾ 67
// code
if(condition for continue) {
continue@outer
}
} while(firstcondition)
} while(secondcondition)
Example:
fun main(args: Array<String>) {
var numbr1 = 6
outer@ do {
numbr1--
var numbr2 = 6
inner@ do {
if (numbr1 <= 2)
continue@outer
println("numbr1 = $numbr1; numbr2 =
$numbr2")
numbr2--
} while (numbr2 > 0)
Syntax:
outer@ for(iteration through iterator) {
// code
inner@ for(iteration through iterator) {
// code
if(condition for continue) {
continue@outer
}
}
}
68 ◾ Kotlin: The Ultimate Guide
Example:
fun main(args: Array<String>) {
outer@ for (numbr1 in 4 downTo 1) {
inner@ for (numbr2 in 4 downTo 1) {
if (numbr1 <= 3)
continue@outer
println("numbr1 = $numbr1; numbr2 =
$numbr2")
}
}
}
EXCEPTIONAL HANDLING
An exception is an undesirable or unexpected occurrence that occurs dur-
ing program execution, i.e., during run time, and disrupts normal flow of
the program’s instructions. Exception handling is an approach for dealing
with errors and avoiding run-time crashes, which might cause our pro-
gram to crash.
Exceptions are classified into two types:
Exceptions in Kotlin
Exceptions in Kotlin are only unchecked and may be detected only at run
time. The Throwable class is the origin of all exception classes.
To throw an exception object, we frequently use the throw-expression:
throw Exception("Throwmeexception")
Example:
fun main(args : Array<String>){
var numb = 30 / 0 // throw an exception
println(numb)
}
Avoiding NullPointerException
Avoid the NullPointerException by using the following checks and
protections:
NullPointerException Example:
Syntax:
try {
// the code that can throw an exception
} catch(c: ExceptionName) {
// catch-exception and handle it
}
Example:
import kotlin.ArithmeticException
fun main(args : Array<String>){
try{
72 ◾ Kotlin: The Ultimate Guide
var numb = 30 / 0
}
catch(c: ArithmeticException){
// caught, handles it
println("It not allowed divide by zero")
}
}
Example:
fun test(x: Int, y: Int) : Any {
return try {
x/y
//println("The Result is: "+ x / y)
}
catch(e:Exception){
println(e)
"The Divide by zero is not allowed"
}
}
//the main function
fun main(args: Array<String>) {
// invoke test-function
var results1 = test(30,2 ) //execute
try-block
println(results1)
var results = test(30,0 ) // execute
catch-block
println(results)
}
We may unite the finally and try blocks and eliminate the catch block.
Syntax:
try {
//the code that can throw an exception
} finally {
// the code of finally block
}
Example:
fun main(args : Array<String>){
try{
var ar = arrayOf(101,202,303,404,505)
var int = ar[6]
println(int)
}
finally {
println("This will always executes")
}
}
try {
// the code that can throw an exception
} catch(c: ExceptionName) {
// catch the exception, handle it.
} finally {
//the code of finally block
}
Example:
fun main (args: Array<String>){
try {
var int = 30 / 0
println(int)
} catch (c: ArithmeticException) {
println(c)
} finally {
74 ◾ Kotlin: The Ultimate Guide
Example:
fun main(args: Array<String>) {
test("xyzde")
println("executes after the validation")
}
fun test(password: String) {
// it calculate the length of entered password
and compare
if (password.length < 6)
throw ArithmeticException("Password is too
short")
else
println("Password is strong ")
}
Syntax:
// the outer try-block
try
{
//the inner try-block
try
{
//the code that can throw an exception
}
Crash Course in Kotlin ◾ 75
catch(c: SomeException)
{
//it catch the exception, handle it
}
}
catch(c: SomeException)
{
// it catch the exception, handle it
}
Example:
fun main(args: Array<String>) {
val numbers = arrayOf(101,202,303,404)
try {
for (x in numbers.indices) {
try {
var nm = (0..4).random()
println(numbers[x+1]/nm)
} catch (c: ArithmeticException) {
println(c)
}
}
} catch (c: ArrayIndexOutOfBoundsException) {
println(e)
}
}
Syntax:
try {
// the code may throw an exception
} catch(c: ExceptionNameOne) {
// catch the exception one, handle it
} catch(c: ExceptionNameTwo) {
// it catch the exception two, handle it
}
76 ◾ Kotlin: The Ultimate Guide
Example:
import java.util.Scanner
object Tests {
@JvmStatic
fun main(args: Array<String>) {
val scn = Scanner(System.'in')
try {
val n = Integer.parseInt(scn.
nextLine())
if (812% n == 0)
println("$n is a factor of 812")
} catch (c: ArithmeticException) {
println(c)
} catch (c: NumberFormatException) {
println(c)
}
}
}
NULL SAFETY
Kotlin’s type system aims to eliminate the possibility of null references in code,
which is a billion-dollar mistake. The program throws NullPointerExceptions
at run-time, resulting in the application or system failure.
If we’ve ever written code in Java or another language that has the con-
cept of a null reference, we’ve almost certainly seen a NullPointerException.
If the Kotlin compiler encounters a null reference without executing any
additional instructions, a NullPointerException is thrown.
The following are some possible sources of NullPointerExceptions:
Now, if we want to acquire the length of the string str1, we can be assured
that it will not throw an NPE; hence, we can confidently say:
val l = str1.length
78 ◾ Kotlin: The Ultimate Guide
Accessing the length of the string str2 is not safe, and the compiler reports
an error:
non-nullable program:
Example:
fun main(args: Array<String>) {
// variable declared as nullable
var str: String? = "TheHuboftutors"
println(str)
if (str != null) {
Crash Course in Kotlin ◾ 79
firstname?.toUpperCase()
is equivalent to:
if(firstname != null)
firstname.toUpperCase()
else
null
Example:
fun main(args: Array<String>) {
// variable declared as nullable
var firstname: String? = "Reena"
var lastname: String? = null
println(firstname?.toUpperCase())
println(firstname?.length)
println(lastname?.toUpperCase())
}
80 ◾ Kotlin: The Ultimate Guide
Elvis Operator(?:)
When the original variable is null, the Elvis operator returns a value that
is not null or a default value. In other words, the Elvis operator returns the
left expression if it is not null; else, the right expression is returned. If it is
determined that the left-hand side expression is null, the right-hand side
expression is evaluated.
The following expression:
is equivalent to:
Furthermore, we may use throw and return expressions on the right side
of the Elvis operator, which is particularly handy in functions. As a result,
we can throw an exception instead of returning the default value on the
Elvis operator’s right side.
Example:
fun main(args: Array<String>) {
var str : String? = "TheHuboftutors"
println(str?.length)
str = null
println(str?.length ?: "-1")
}
println(str!!.length)
str = null
str!!.length
}
Smart Casting
Before accessing a variable’s properties in Java or other programming lan-
guages, explicit type casting is necessary, but Kotlin employs smart cast-
ing. When you send a variable through a conditional operator, the Kotlin
compiler automatically converts it to a particular class reference.
Consider the following Java example. We first use the instanceOf opera-
tor to discover the variable’s type, and then we cast it to the target type, as
seen below:
Smart casts are ineffective if the compiler cannot guarantee that the vari-
able will not change between the check and the usage. The following guide-
lines determine the usage of smart casts:
As a result, we must also use the target type as a nullable string to pre-
vent type casting from throwing an exception.
class Regex
86 ◾ Kotlin: The Ultimate Guide
Properties:
Regex Functions
fun main()
{
// A regex that matches any text that begins with
the letter 'b'
val pattern = Regex("^b")
println(pattern.containsMatchIn("acbd"))
println(pattern.containsMatchIn("bcad"))
}
Crash Course in Kotlin ◾ 87
fun main()
{
// Regex to match "ol" in a string
val pattern1 = Regex("ol")
val ans : MatchResult? = pattern1.
find("HlloooHllooo", 6)
println(ans ?.value)
}
fun main()
{
// A regex to match a 3 pattern starting with ab
val pattern2 = Regex("ab.")
val ans1 : Sequence<MatchResult> = pattern2.
findAll("absgffhdbabc", 0)
// forEach loop used to display all the matches
ans1.forEach()
{
matchResult -> println(matchResult.value)
}
println()
}
fun main()
{
//to tests the demonstrating entire string match
val patterns = Regex("p([ee]+)ks?")
println(patterns.matches("peeks"))
println(patterns.matches("peeeeeeeeeeks"))
println(patterns.matches("peeksforpeeks"))
}
fun main()
{
// Tests demonstrating entire string match
var patterns = Regex("peeks?")
println(patterns.matchEntire("peeks")?.value)
println(patterns.matchEntire("peeeeeeeks")?.value)
patterns = Regex("""\D+""")
println(patterns.matchEntire("peeks")?.value)
println(patterns.matchEntire("peeks13245")?.value)
}
fun main()
{
// Experiments to demonstrate replacement
functions
val pattern4 = Regex("abzz")
// replace all abzz with xycd in the string
println(pattern4.replace("abzzabzzzzzzzzz",
"abcd"))
// replace only first xyz with abc not all
println(pattern4.replaceFirst("abzzddddddabzz",
"abcd"))
println()
}
• split(): This function separates the input text into tokens based on
the given value.
fun split(input: Char_Sequence, limit: Int): List
fun main()
{
// Tests demonstrating split function
val patterns = Regex("\\s+") // separate for the
white-spaces
val ans : List<String> = patterns.split("This is
the class")
ans.forEach { word -> println(word) }
}
RANGES IN KOTLIN
In Kotlin, a range is a collection of finite values defined by endpoints. A
range in Kotlin is made of a start, a stop, and a step. The Range’s start and
endpoints are inclusive, and the step value is set to 1 by default.
The range is given to comparable types.
Range may create in three ways in Kotlin:
(..) operator
It is the most fundamental way to interact with range. It will construct a
beginning to end range containing both the beginning and ending values.
It is the operator form of the rangeTo() function. Using the (..) operator, we
can build ranges for integers and characters.
To create an integer range program in Kotlin, use the (..) operator:
rangeTo() Function
It is comparable to the (..) operator. It will produce a range up to the pro-
vided value. It’s also used to make a range of numbers and characters.
In Kotlin, use the rangeTo() function to build an integer range:
downTo() Function
It is the reverse of the rangeTo() or (..). It produces a range from larger to
smaller numbers in decreasing order. This section will define ranges for
integers and characters in reverse order.
Kotlin code with an integer range and the downTo() function:
step()
To create a step between values, use the keyword step. It is mainly used in
rangeTo(), downTo(), and the (..) operator to provide the space between
two numbers. Because the step has a default value of 1, the step function
cannot have a value of zero.
A step-by-step Kotlin program is provided below:
reverse() Function
It is used to reverse the range type specified. To print the range in descend-
ing order, we may use the reverse() function instead of downTo().
fun main() {
val predefined = (13..20)
println("The minimum value of the range is:
"+predefined.min())
Crash Course in Kotlin ◾ 93
OOP in Kotlin
IN THIS CHAPTER
Class
Class, like Java, is a blueprint for objects with similar characteristics. We
must first declare a class before creating an object, and the class keyword
is used to do so.
The class declaration comprises the class name, the class header, and the
class body, which are all separated by curly brackets.
Syntax:
class className
{ // the class header
// property
// the member-function
}
The header and class body are optional; the class body can be deleted if
there is nothing between the curly braces.
class blankClass
We must use the term immediately after the class name if we want to
include a constructor.
Creating a constructor:
Example:
class employe
{
OOP in Kotlin ◾ 97
// properties
var names: String = ""
var ages: Int = 0
var gender: Char = 'D'
var salary: Double = 0.toDouble()
//the member functions
fun names(){
}
fun ages() {
}
fun salary(){
}
}
Object
It is a key unit of OOP that represents real-world entities with state and
behavior. Objects are used to access the properties and member functions
of a class. In Kotlin, several instances of the same class can create. An item
is made up of the following components:
Example:
class employees
{// Constructor Declaration of Class
var names: String = ""
var ages: Int = 0
var gender: Char = 'F'
var salary: Double = 0.toDouble()
fun insertValues(n: String, a: Int, g: Char, s:
Double) {
names = n
ages = a
gender = g
salary = s
println("The Name of the employees: $name")
println("The Age of the employees: $age")
println("The Gender: $gender")
println("The Salary of the employees:
$salary")
}
fun insertName(n: String) {
this.name = n
}
}
fun main(args: Array<String>) {
// creating the multiple objects
var objt = employees()
// object 2 of class employees
var objt2 = employees()
//accessing the member function
objt.insertValues("Raveen", 8, 'F', 40000.00)
// accessing the member function
objt2.insertName("Jlie")
// accessing the name property of class
println("Name of the new employees: ${objt2
.name}")
Syntax:
class out_Class {
..............
// the properties of the outer class or a
member function
class nest_Class {
...........
// the properties of the inner class
or member function
}
}
It is important to note that nested classes cannot access the members of the
outer class, but we may access nested class properties from the outer class
without creating an object for the nested class.
In Kotlin, use the following program to access nested class attributes:
In Kotlin, we must first create the nested class’s object and then invoke the
member function from it.
100 ◾ Kotlin: The Ultimate Guide
class outer_Class {
.............
// properties of the outer class or member-function
OOP in Kotlin ◾ 101
We try to access strg from the inner class member function in the follow-
ing program. It does not, however, work and creates a compile-time error.
To begin, place the inner keyword before the inner class. Then, create an
instance of outer class; otherwise, we will be unable to use inner classes.
Syntax:
var <propertyName>[: <PropertyType>]
[= <property_initializer>]
[<getter>]
[<setter>]
The property initializer, getter, and setter are all optional in this scenario.
We may also omit the property type if we can infer it from the initializer. A
read-only or immutable property declaration differs from a mutable prop-
erty declaration in two ways:
val b: Int = 1
a = 2 // It can be allocated unlimited number
of times
b = 0 // It'll never be allocated again
}
class companie
{
var names: String = "Defaultvalues"
}
class companie
{
var names: String = "defaultvalues"
get() = field // getter
set(value) { field = value } // setter
}
We make a ‘y’ object of the type ‘companie.’ We provide the setter’s param-
eter value when we initialize the ‘names’ property, which sets the ‘field’ to
value. When we try to access the object’s names property, we receive a field
since the code gets () = field. We can acquire or set the properties of a class
object using the dot(.) syntax.
val y = companie()
y.names = "TheHuboftutor" // access setter
println(y.names) // access getter
class companie
{
var names: String = ""
104 ◾ Kotlin: The Ultimate Guide
• Value: We usually use the name of the setter parameter as the value,
but we may use whatever name we choose. The value argument con-
tains the value that has been assigned to a property. In the above pro-
gram, we set the property name to y.name = “TheHuboftutor” and we
set the value parameter to “TheHuboftutor.”
• Backing Field (field): It allows us to save the property value in mem-
ory. When we initialize property with value, the value is written to
the property’s backing field. In the preceding program, the value is
assigned to the field, and then the field is assigned to obtain ().
Private Modifier
If we want the public to be allowed to utilize the get function, we may use
the following code:
We can only set the name in a method within the class due to the private
modifier near the set accessor. In a Kotlin program, a method within a
class is used to set the value.
class companie () {
var names: String = "cde"
private set
// throw IllegalArgumentException("Passwords is
small")
peek.password = "abc"
// throw IllegalArgumentException("Age should be
19+")
peek.age= 5
// throw IllegalArgumentException("User should be
male")
peek.gender = 'M'
}
Property
It is a combination of accessories and fields in the case of Java. In Kotlin,
properties are meant to be first-class language features. These features
have replaced fields and accessor methods. The val and var keywords are
used to specify class properties in the same manner as variables are. A var-
declared property is mutable, which means it may change.
OOP in Kotlin ◾ 107
Creating a class:
class Cbad(
val names: String,
val ispassed: Boolean
)
class Cbad(
val names: String,
val ispassed: Boolean
)
fun main(args: Array<String>) {
val abcd = Cbad("Bobbin",true)
println(abcd.names)
println(abcd.ispassed)
/*
In Java
Cbad abcd = new Cbad("Bobi",true);
System.out.println(person.getName());
System.out.println(person.isMarried());
*/
}
In Kotlin, the constructor can be called without the requirement for a new
keyword. Instead of utilizing a getter, the property is addressed directly.
The logic is the same, but the code is much shorter. Setters of mutable
properties work in the same way.
Customer Accessors
Implementation of property accessors on a specific instance basis:
class Rect(val height: Int, val width: Int)
{
val isSquare: Boolean
108 ◾ Kotlin: The Ultimate Guide
get() {
return height == width
}
}
fun main(args: Array<String>) {
val rect = Rect(22, 14)
println(rect.isSquare)
}
KOTLIN CONSTRUCTOR
Constructor is a member function that is invoked when a class object is
created to initialize variables or properties. Every class must have a con-
structor, and if we don’t define one, the compiler will create one for us.
There are kinds of constructors in Kotlin:
• Primary Constructor
• Secondary Constructor
A class in Kotlin can have one primary constructor and one or more sub-
sidiary constructors. The primary constructor is responsible for initializ-
ing the class, whereas the secondary constructor is in charge of initializing
the class and introducing some extra logic.
Primary Constructor
After the class name, the constructor keyword is used to initialize the pri-
mary in the class header. The main constructor’s parameters are optional.
Example:
//the main function
fun main(args: Array<String>)
{
val add = Add(10, 2)
println("The Sum of numbers 10 and 2 is:
${add.a}")
}
//the primary constructor
class Add constructor(x: Int,y:Int)
{
var a = x+y;
}
Example:
fun main(args: Array<String>) {
val empy = employees(27117, "Rani")
}
class employees(empy_id : Int, empy_name: String)
{
val id: Int
var names: String
// initializer block
init {
id = empy_id
names = empy_names
println("Employees id is: $id")
println("Employees name: $names")
}
}
Example:
fun main(args: Array<String>) {
val empy = employees(27117, "Rani")
// the default value for empy_name will be
used here
val empy2 = employees(10011)
//default values for the both parameters
because no arguments passed
val empy3 = employees()
}
class employees(empy_id : Int = 110, empy_name:
String = "cbad") {
val id: Int
var name: String
// initializer block
init {
id = empy_id
name = empy_name
print("Employee id is: $id, ")
println("Employee name: $name")
println()
}
}
Secondary Constructor
Kotlin, as previously noted, may have one or more secondary constructors.
Secondary constructors enable variable initialization and the inclusion of
logic to the class. The keyword constructor precedes them.
Example:
//the main function
fun main(args: Array<String>)
{
Add(10, 3)
}
//class with the one secondary constructor
class Add
{
constructor(x: Int, y:Int)
{
OOP in Kotlin ◾ 111
var a = x + y
println("The sum of numbers 10 and 3 is:
${a}")
}
}
Example:
fun main(args: Array<String>) {
employee(17117, "Rani")
employee(12011,"Prithwi",52000.5)
}
class employee {
constructor (empy_id : Int, empy_name:
String ) {
var id: Int = empy_id
var name: String = empy_name
print("Employee id is: $id, ")
println("Employee name: $name")
println()
}
constructor (empy_id : Int, empy_name:
String, empy_salary : Double) {
var id: Int = empy_id
var name: String = empy_name
var salary : Double = empy_salary
print("The Employee id is: $id, ")
print("The Employee name: $name, ")
println("The Employee name: $salary")
}
}
Modifier Description
Public The Visible everywhere
Private The Visible inside same class only
Internal The Visible inside the same module
Protected The Visible inside the same class and its subclasses
Public Modifier
The public modifier is the default in Kotlin. It is the most commonly used
modifier in the language, and there are additional restrictions on who may
OOP in Kotlin ◾ 113
// by default public
class X {
var int = 40
}
Classes X and Y access from anywhere in the code, and the variables int
and int2 and the function display() can access from anything that can
access classes X and Y.
Private Modifier
In Kotlin, private modifiers limit access to code specified inside the same
scope, which makes it impossible to access the modifier variable or func-
tion outside the scope. In contrast to Java, Kotlin allows several top-level
declarations in the same file – a private top-level element in the same file
can be accessed by everything else in the same file.
In this situation, Class X can only access the int variable from inside the
same source file, and Class X can only access the int variable from within
Class X. We encountered a compile-time error when attempting to access
int from outside the class.
Internal Modifier
The internal modifier is a new Kotlin modifier that Java does not support.
Internal means that it will only be accessible inside the same module;
attempting to access the declaration from another module will result in an
error. A module is a group of files that have been assembled.
internal class X {
}
public class Y {
internal val int = 30
internal fun display() {
}
}
Class X is only accessible from inside the same module in this situation.
Even though class Y may be accessible from everywhere, the variable int
and function display() are only available within the same module.
Protected Modifier
In Kotlin, the protected modifier restricts access to the declaring class and
its subclasses. The protected modifier cannot be shown at the top level. In
the following example, we utilized the getvalue() function of the derived
class to obtain the int variable.
// base class
open class X {
OOP in Kotlin ◾ 115
// protected variable
protected val int = 30
}
// derived class
class Y: X() {
fun getvalue(): Int {
// accessed from the subclass
return int
}
}
// base class
open class X {
// protected variable
open protected val int = 30
}
// derived class
class Y: X() {
override val int = 40
fun getvalue():Int {
// accessed from the subclass
return int
}
}
fun main(args: Array<String>) {
var c = Y()
println("The overridden value of integer is: "+c.
getvalue())
}
116 ◾ Kotlin: The Ultimate Guide
Constructor Visibility
Constructors are always public by default, although modifiers can change
that.
When changing the visibility, we must indicate this clearly by using the
constructor keyword.
INTERFACES IN KOTLIN
Interfaces are Kotlin-provided custom types that cannot be directly
instantiated. These, on the other hand, indicate a style of behavior that the
implementing types must exhibit. The interface enables us to define a set
of traits and methods that concrete types must comply and implement.
Creating Interfaces
In Kotlin, the interface declaration begins with the interface keyword,
followed by the interface’s name, and lastly by the curly brackets con-
taining the interface’s members. The members, on the other hand, will
not have their definition. The conforming types will provide these
definitions.
Example:
interface Machine()
{
fun start()
fun stop()
}
Implementing Interfaces
A class or an object can implement an interface. When we implement
an interface, we must define all of its members in the conforming type.
OOP in Kotlin ◾ 117
interface Machine {
fun start()
fun stop()
}
fun main()
{
val obj = Bus()
obj.start()
obj.stop()
}
Example:
interface FirstInterface {
fun add(x: Int, y: Int = 9)
fun print()
{
println("This is a default-method defined
in the interface")
}
}
class InterfaceDemo : FirstInterface {
override fun add(x: Int, y: Int)
{
val c = x + y
println("Sum is $c")
}
fun main()
{
val objt = InterfaceDemo()
println(objt.add(9))
objt.print()
}
Interface Properties
Attributes can be included in interfaces, just as they can in methods.
However, because the interface lacks a state, they cannot be generated, and
OOP in Kotlin ◾ 119
hence no underlying fields to store their values exist. As a result, the inter-
face fields are either left abstract or provided an implementation.
Example:
interface InterfaceProperties {
val x : Int
val y : String
get() = "Heyyyy"
}
fun main()
{
val x = PropertiesDemo()
println(a.x)
println(a.y)
}
Interface Inheritance
Interfaces in Kotlin can inherit from other interfaces. When one inter-
face extends another, it may add its own properties and methods, but the
implementing type must specify all of the properties and methods in both
interfaces. An interface can inherit many interfaces.
Example:
interface Dimension {
val len : Double
val br : Double
}
120 ◾ Kotlin: The Ultimate Guide
Example:
interface InterfaceProperties {
val x : Int
val y : String
get() = "Heyyyy"
}
interface InterfaceMethods {
fun description()
}
OOP in Kotlin ◾ 121
DATA CLASSES
We often create classes to store data in them. Few standard functions may
frequently be derived from the data in such classes. In Kotlin, this class is
a data class and is labeled as such.
Example:
data class Stud(val name: String, val roll_no: Int)
• hashCode()
• toString()
• copy()
• equals()
toString()
This function returns a string containing all of the parameters to the data
class.
Example:
fun main(args: Array<String>)
{
//the declarion of data-class
data class woman(val roll: Int,val name:
String,val height:Int)
//declarion of variable of the above data
class and initializing values to all parameters
val woman1=woman(1,"woman",40)
//print all details of the data class
println(woman1.toString());
}
The compiler only utilizes the characteristics specified inside the primary
constructor for the automatically produced functions.
It excludes the properties declared in the class’s body.
Example:
fun main(args: Array<String>)
{
//declarion of data-class
data class woman(val name: String)
{
//the property declared in class-body
var height: Int = 0;
}
//declarion of variable of the above data
class and initializing values to all parameters
val woman1=woman("Rhiana")
//class body properties must be assigned
uniquely
woman1.height = 50
OOP in Kotlin ◾ 123
copy()
We may need to copy an object and update its characteristics while leaving
others unchanged.
In this case, the copy() function is used.
• copy() properties:
All of the arguments or members defined in the main constructor
are duplicated.
When two objects are defined, they may have the same main
parameter values but different class body values.
• copy() declaration:
Example:
fun main(args: Array<String>)
{
//declarion of a data class
data class woman(val name: String, val age:
Int)
{
//property declared in class-body
var height: Int = 0;
}
val woman1 = woman("Damini",16)
//copying details of man1 with change in name
of man
val woman2 = woman1.copy(name="Pari")
• The hashCode() function returns the hash code value of the object.
• The equals() method returns true if two objects have the same con-
tents and work in the same way as “==”, but with Float and Double
values.
hashCode() declaration:
hashCode() properties:
• Two hash codes that are specified twice on the same item are equal.
• The hash codes will be the same if two objects are equal according to
the equals() method.
SEALED CLASSES
Kotlin provides a new class type that is not found in Java. These are known
as sealed classes. As the name indicates, Sealed classes adhere to confined
or bounded class hierarchies. A collection of subclasses is specified within a
sealed class. It is used when it is known in advance that a type will conform
to one of the subclass types. Sealed classes ensure type safety by restricting
the types that can match at compile time rather than at runtime.
Declaration of sealed class:
To define a sealed class, just use the sealed keyword before the class modi-
fier. Another feature that distinguishes sealed classes is that their con-
structors are, by default, private.
A sealed class cannot instantiate since it is inherently abstract.
Example:
sealed class Demo1 {
class X : Demo1() {
fun display()
{
println("Subclass X of sealed class
Demo")
}
}
class Y : Demo1() {
fun display()
{
println("Subclass Y of sealed class
Demo")
}
}
}
fun main()
{
val objt = Demo1.Y()
objt.display()
val objt1 = Demo1.X()
objt1.display()
}
It should note that all sealed class subclasses must specify in the same
Kotlin file. However, they do not have to be declared within the sealed
class; instead, they can be defined anywhere the sealed class is accessible.
Example:
//sealed class with the single subclass defined
inside
sealed class CDEF {
class X: CDEF(){...}
}
// Another subclass of the sealed class defined
class Y: CDEF() {
class Z: CDEF() // This will result in an
error. The sealed class is not visible in this
case.
}
OOP in Kotlin ◾ 127
Sealed class with when: Because the types to which a sealed class reference
can conform are limited, it is usually used in combination with a when
clause. This completely eliminates the requirement for the otherwise clause.
Example:
// A sealed class with string-property
sealed class Fruit
(val a: String)
{
// Two subclasses of sealed-class defined
within
class Banana : Fruit("Banana")
class Grapes : Fruit("Grapes")
}
Abstract class can have both the abstract and non-abstract members, as
seen below:
Example:
//abstract-class
abstract class Emp(val name: String,val
experience: Int) { // Non-Abstract-Property
OOP in Kotlin ◾ 129
Example:
open class Livebeing {
open fun breathe() {
println("All live being breathe")
}
}
abstract class Creature : Livebeing() {
override abstract fun breathe()
}
class Cat: Creature(){
override fun breathe() {
println("Cat breathe")
}
}
fun main(args: Array<String>){
val lb = Livebeing()
lb.breathe()
val c = Cat()
c.breathe()
}
Example:
// abstract-class
abstract class Calculation {
abstract fun cal(e: Int, f: Int) : Int
}
// addition of two-numbers
class Add : Calculation() {
override fun cal(e: Int, f: Int): Int {
return e + f
}
}
// subtraction of two-numbers
class Sub : Calculation() {
OOP in Kotlin ◾ 131
INHERITANCE IN KOTLIN
Inheritance is a major concept in OOP. Inheritance enables code reuse
by allowing a new class to inherit (derived-class) all of the characteris-
tics of an existing class (base-class). The derived class can add its own
features.
Syntax:
open class baseClass (x:Int ) {
............
}
class derivedClass(x:Int) : baseClass(x) {
.............
}
All Kotlin classes are final by default. To allow the derived class to inherit
from the base class, we must use the open keyword in front of it.
132 ◾ Kotlin: The Ultimate Guide
The following properties and methods are inherited from the base class:
• We inherit all of its attributes and functionalities when we inherit
a class. Variables and functions from the base class can use in the
derived class, and functions from the derived class object can
call.
//base-class
open class baseClass{
val name = "TheHubtutor"
fun X(){
println("BaseClass")
}
}
//derived class
class derivedClass: baseClass() {
fun Y() {
println(name) //inherit name
property
println("Derivedclass")
}
}
fun main(args: Array<String>) {
val derived = derived-Class()
derived.X() // inheriting base-class
function
derived.Y() // calling derived-class
function
}
Inheritance Use
Assume a company employs three people: a webDeveloper, an iOSDevel-
oper, and an androidDeveloper. They all share some traits, such as a name,
an age, and specific special skills.
OOP in Kotlin ◾ 133
First, we split the individuals into three classes, each with its own set of
standard and unique talents.
Although all three developers have the same name and age, their pro-
gramming abilities are vastly different. We would use the same code for
each character’s name and age in each class.
If we want to add a salary() method, we must replicate the code in each
of the three classes. This results in multiple duplicate copies of code in our
program, which nearly always leads to more intricate and chaotic code.
The use of inheritance makes the work more approachable. We could
create a new base class Employee with the same characteristics as the three
original kinds. These three classes can then inherit the base class’s shared
attributes while adding their own. Without duplicating, we can easily add
salary functionality to the Employee class.
Inherit class.
134 ◾ Kotlin: The Ultimate Guide
Example:
//baseclass
open class Employ( names: String,age: Int,salary :
Int) {
init {
println("Name is $names, $age years old
and earning $salary per month. ")
}
}
//derivedclass
class web_Developers( names: String,age:
Int,salary : Int): Employ(names, age,salary) {
fun website() {
println("website-developer")
println()
}
}
//derived-class
class android_Developer( names: String,age:
Int,salary : Int): Employ(names, age,salary) {
fun android() {
println("android-app-developer")
println()
}
}
//derived class
class ios_Developers( names: String,age:
Int,salary : Int): Employ(names, age,salary) {
fun iosapp() {
println("iOS-app-developer")
println()
}
}
//the main method
fun main(args: Array<String>) {
val wd = web_Developers("Rheinna", 21, 13000)
wd.website()
OOP in Kotlin ◾ 135
//baseclass
open class Employ(names: String,age: Int) {
init{
println("Name of Employee is $names")
println("Age of an Employee is $age")
}
}
// derivedclass
class CEO( names: String, age: Int, salary: Double):
Employ(names,age) {
init {
println("Salary per annum is $salary crore
rupees")
}
}
136 ◾ Kotlin: The Ultimate Guide
//baseclass
open class Employ {
constructor(names: String,age: Int){
println("Name of Employee is $names")
println("Age of Employee is $age")
}
}
// derived class
class CEO : Employ{
constructor( names: String,age: Int, salary:
Double): super(names,age) {
println("Salary per annum is $salary million
dollars")
}
}
fun main(args: Array<String>) {
CEO("Raniti Dela", 59, 320.00)
}
First example:
// baseclass
open class Animals {
open fun run() {
println("Animals runs")
}
}
// derivedclass
class Tiger: Animals() {
override fun run() { // it overrides the
run method of base-class
println("Tiger runs very fast")
}
}
fun main(args: Array<String>) {
val tg = Tiger()
tg.run()
}
Similarly, we may override the property of the base class in the derived
class.
Second example:
// baseclass
open class Animals {
open var name: String = "Cat"
open var speed = "30 km/hr"
}
// derivedclass
class Tiger: Animals() {
override var name = "Lion"
override var speed = "100 km/hr"
}
138 ◾ Kotlin: The Ultimate Guide
// baseclass
open class Phones() {
var color = "Rose Gold"
fun displayCompany(names:String) {
println("The Company is: $names")
}
}
// derivedclass
class iphone: Phones() {
fun displayColor(){
// calling the base-class property color
println("Color is: "+super.color)
// calling the base-class member function
super.displayCompany("Blackberry")
}
}
fun main(args: Array<String>) {
val ps = iphone()
ps.displayColor()
}
COMPOSITION
The concepts of inheritance and composition are used to construct rela-
tionships between classes and objects. It is critical to understand which of
them to prioritize to create a successful software design.
Composition is method in which we compose a class by adding pri-
vate fields to it that refer to an instance of an existing class rather than
extending it. As a result, a “has-a” relationship is created between the
constructed class and the instances it contains. The class fulfills its
OOP in Kotlin ◾ 139
class User_Mediator {
private val cacheService: UserCacheService =
UserCacheService()
private val apiService: UserApiService =
UserApiService()
…
}
First and foremost, the code above will not compile. The relationship would
be meaningless even if it did since UserMediator utilizes UserCacheService
and UserApiService as implementation details rather than an is-a relation-
ship. Later, we’ll see how to solve this.
OOP in Kotlin ◾ 141
Tight Coupling
Implementation Inheritance establishes a close bond between a parent and
their children. Inheriting a class binds the child class to the parent class’s
implementation details. As a result, if the parent class changes – that is, if
it becomes unstable – the child class may fail even though its code remains
unchanged. As a result, each child class must grow with the parent class.
This necessitates making a broad assumption about future require-
ments. We must establish the hierarchy early on and maintain the rela-
tionship with each new demand. As a result, we may have to use a Big
Design Up Front (BDUF) approach, resulting in over-engineering and
complicated design.
When the value is not of the type String, the functions getProperty() and
get() in the above example provide different results for the same key. As a
result, the resultant API is perplexing and prone to incorrect invocations.
Composition Refactoring
Composition is the utilization of tiny elements to create a complex entity.
This section will show us how to utilize this composition-based method
to minimize or alleviate the design challenges caused by implementation
inheritance.
class User_Mediator {
private val cacheService: UserCacheService =
UserCacheService()
private val apiService: UserApiService =
UserApiService()
/**
* Search for [User] with the [username] on cache
first. If not found,
144 ◾ Kotlin: The Ultimate Guide
class User_Mediator(
private val cacheService: UserCacheService,
private val apiService: UserApiService
) {
// methods
}
class Hashtable_Store {
// 1
private val store: Hashtable<String, String> =
Hashtable()
// 2
fun getProperty(key: String): String? {
return store[key]
}
fun setProperty(key: String, value: String) {
store[key] = value
}
fun propertyNames() = store.keys
}
If we want all of Properties’ capabilities while still having control over the
“exposure area,” we may put a wrapper over it and expose our methods.
Make a new class called PropertiesStore and add the following code into it:
class Properties_Store {
private val properties = Properties()
fun getProperty(key: String): String? {
return properties.getProperty(key)
}
fun setProperty(key: String, value: String) {
properties.setProperty(key, value)
}
fun propertyNames() = properties.propertyNames()
}
Example: Let me illustrate the concept with a simple example. Assume you
work at an automotive firm and our job is to build automobiles depend-
ing on several specifications such as the color of the car (appearance), the
maximum speed (performance), and the number of seats (interior).
Then we can create our Car class with only one line of code:
public YellowSlowSUV() {
this.$$delegate_0 = Yellow.INSTANCE;
this.$$delegate_1 = SixSeat.INSTANCE;
this.$$delegate_2 = Slow.INSTANCE;
}
public String getColor() {
return this.$$delegate_0.getColor();
}
public int getNumberOfSeats() {
return this.$$delegate_1.getNumberOfSeats();
}
OOP in Kotlin ◾ 149
ENCAPSULATION
Encapsulation is the union of data and logic into a single unit that con-
ceals data from external access. As a consequence, we have fewer couplings
between software components, as well as more understandable and reli-
able code.
The following access modifiers are available:
• Private: name is only available within the class where it was declared.
• Protected: name is only accessible within the class and its subclasses.
• Internal: name is accessible to everyone within the same module.
• Public: name is open to the public; this is the default modification
to omit it.
It is worth noting that in Kotlin, the outer class does not view the private
members of its inner classes.
Protected members are not permitted within interfaces or objects in
Kotlin.
Kotlin does not provide abstract private functions; only body functions
are supported.
If we override a protected member without explicitly specifying the vis-
ibility, the overriding member will also have protected visibility.
Modifiers can apply to the class constructor.
// c is not visible
// d, e and f are visible
// Nested and g are visible
override val d = 5 // 'd' is protected
}
class Unrelated(o: Outer) {
// o.c, o.d are not visible
// o.e and o.f are visible (same module)
// Outer.Nested is not visible, and Nested::g is
not visible either
}
class C private constructor(c: Int) { ... }
POLYMORPHISM
Unlike Python, Kotlin needs the use of the override keyword when an ele-
ment in a class/interface is being overridden, and tests are done at build
time to verify if the element may override. Any class that may inherit from
must be open, as any of its declared components can override. In src, add
a new package called org.example.enpoly.doggie. Create a new Kotlin file
named Dog in the package with the following contents:
package org.example.enpoly.doggie
import org.example.enpoly.AnimalBase
internal open class Doggie(var petName: String = "",
open protected val coat: String,
open protected val energy:
Int) : AnimalBase {
override val MAX_AGE = 20
override fun doMove() = "Walks/runs"
override fun makeSound() = "Wooff"
fun stats() = "Coat: $coat, Energy: $energy"
}
The absence of the open keyword in the stats function in the above exam-
ple indicates that the function cannot alter. Create a new Kotlin file called
SmallDoggie in the same package with the following contents:
package org.example.enpoly.doggie
internal open class SmallDoggie : Doggie(coat =
"Fluffy", energy = 12)
OOP in Kotlin ◾ 151
Create a new Kotlin file named LargeDoggie in the same package with the
following contents:
package org.example.enpoly.doggie
internal open class LargeDoggie : Dog(coat = "Raggy",
energy = 2)
Now it’s time for several classes that will cover two dog breeds. Create a
new Kotlin file called Chiwawa in the same package with the following
contents:
package org.example.enpoly.doggie
internal class Chiwawa(petName: String) :
SmallDoggie() {
override fun makeSound() = "Yaap, yaap, yaap"
init {
this.petName = petName
}
}
Create new Kotlin file called GreatDane in the same package with the fol-
lowing contents:
package org.example.enpoly.doggie
internal class GreatDane(petName: String) :
LargeDoggie() {
override val MAX_AGE = 13
override val coat = "Smooth"
init {
this.petName = petName
}
}
package org.example.enpoly
import org.example.enpoly.doggie.*
fun main(args: Array<String>) {
val chiwawa = Chiwawa("Fiifi")
val greatDane = GreatDane("Earles")
152 ◾ Kotlin: The Ultimate Guide
OOP
Here’s an example of the same problem tackled using an OOP approach.
class Rect(
var width : Int,
var height : Int,
var color : String){
fun calcArea() = this.width * this.height
override fun toString() =
"Width = ${this.width}, Height = ${this.
height}, Color = ${this.color}, Area = ${calcArea()}"
}
Because the data and the activity associated with the data are gathered into
a single object called a class, the OOP approach displays encapsulation. The
data associated with a class is commonly referred to as “properties,” and
the actions described in the class are commonly referred to as “methods.”
Because all objects based on the Rectangle class contain width, height, and
color, the calcArea() and function toString() methods are always guaran-
teed to function. We also keep our type safety since we may define each
property as a separate variable within the class, along with its type.
When invoking the calcArea() and function toString() methods, the
term ‘this’ relates to the object called. Unlike the preceding procedural
program, we’ll observe that no Rectangle parameter is sent to calcArea()
or function toString(). Instead, the ‘this’ keyword is modified to refer to
the presently active object.
However, certain issues are easier to address when using procedural rather
than OOP, while others are better solved with OOP.
Procedural
When we operate in terms of pure mathematical functions, a function
receives certain inputs and returns specific outputs without any side effects.
• GUI toolkits: Objects such as buttons, windows, and web pages are
extremely well represented as classes.
• Grouping state or behavior: We frequently find that entities in soft-
ware have qualities or methods shared by other entities with com-
parable properties or methods. All road vehicles, for example, have
wheels and move. Trucks are specialized vehicles with a box. Four-
wheel drive trucks are specialist vehicles that have four wheels of
drive. We can utilize OOP to organize all of the components shared
by all cars into a Vehicle class. All things common to Vehicles may
be classified as Trucks, while all items used solely in four-wheel drive
trucks can be classified as FourByFourTruck.
• Modularization: OOP enables developers to modularize code into
smaller, reusable software components. Because the code units in a
system are small, the code is typically easier to maintain.
Putting Everything Together
A working program demonstrating both procedural programming and
OOP is provided below.
package ch1
/**
OOP in Kotlin ◾ 155
/**
* This class represents a Rectangle. You’ll see it
contains less code than the
* non-OOP implementation right away. This is because
the state (width, height, and color) is bundled with
the behavior.
* Kotlin goes this a step further by allowing us to
adjust our code’s width, height, and color. We need to
add calcArea(), which we can ensure will always
function because
* we know width and height will always exist.
Similarly, we know that our function toString()
function will never fail us
* for the same reason!
*/
class Rect(
var width : Int,
var height : Int,
var color : String){
fun calcArea() = this.width * this.height
override fun toString() =
156 ◾ Kotlin: The Ultimate Guide
This chapter introduced the notion of OOP, where we learned about Class
and Object, Nested classes, Constructors, and Inheritances. In addition, we
discussed Interfaces, Abstract classes, and Generics in Kotlin. Moreover,
Composition, Polymorphism, and Encapsulation.
Chapter 3
Usability Aspects
of Kotlin
IN THIS CHAPTER
➢➢ Nullable types
➢➢ Extension methods
➢➢ Overloading
➢➢ Enumeration and generics
Nullable Types
Nullable types are declared by adding a? to the end of a String, as in:
Example:
fun main(args: Array<String>){
var strg: String? = "Hello" // variable is
declared as nullable
strg = null
print(strg)
}
Non-Nullable Types
Non-nullable types are regular strings that are specified as String types,
such as:
What happens when we add a null value to a string that is not nullable?
SMART CAST
We have seen how to declare a nullable type in the previous course Kotlin
nullable types and non-nullable types. We have the option of using smart
casts to use these nullable classes. Smart cast is a feature that allows the
Kotlin compiler to track circumstances within if expressions. If the com-
piler discovers that a variable is not null of type nullable, it will enable
access to the variable.
For casting to work, the source and target variables must be nullable:
In the above code, the String strg includes a null value; thus, before access-
ing the value of strg, we must run a safety check to see if the string contains
a value or not. Traditionally, we conduct this safety check with an if… else
sentence.
The Elvis operator(?:) in Kotlin returns a result that is not null even if the
conditional expression is null. The following Elvis operator may be used to
express the above if… else operator:
The Elvis operator returns the expression to the left to ?:, i.e. −1. (strg?.
length) If it is not null, it returns the expression right to (?:) i.e. (−1). The
expression on the right side of Elvis operator is evaluated only if the
expression on the left side returns null.
Usability Aspects of Kotlin ◾ 163
Example:
fun main(args: Array<String>){
var strg: String? = null
var strg2: String? = "May be declare nullable
string"
var len1: Int = strg ?.length? : -1
var len2: Int = strg2 ?.length? : -1
println("Length of strg is ${len1}")
println("Length of strg2 is ${len2}")
}
Because Kotlin throw and return expressions, they may also be used on
the Elvis operator’s right side. This may be used to check functional argu-
ments such as:
EXTENSION FUNCTION
The Kotlin programming language enables the programmer to enhance
the functionality of existing classes without inheriting them. This is per-
formed by utilizing a feature known as extension. A function that is added
to an existing class is referred to as an Extension Function.
Create a new function that is tied to the classname, as shown in the
example below, to add an extension function to class:
Example:
fun main(){
// Extension function defined for the Int type
fun Int.abs() : Int{
return if(this < 0) -this else this
}
println((-8).abs())
println(8.abs())
}
Example:
// An Open class created to be inherited
open class E(val e:Int, val f:Int){
}
166 ◾ Kotlin: The Ultimate Guide
// Class F inherits E
class F():E(6, 6){}
fun main(){
// Extension function operate defined for E
fun E.operate():Int{
return e+f
}
Nullable Receiver
The nullable class type can also use to construct extension functions. The
correct value is returned when the check for null is inserted inside the
extension method.
Example:
// A sample class to display name
class CDE(val name: String){
override fun toString(): String {
return "Name is $name"
}
}
Usability Aspects of Kotlin ◾ 167
fun main(){
// An extension function as a nullable receiver
fun CDE?.output(){
if(this == null){
println("Null")
}else{
println(this.toString())
}
}
val a = CDE("Charch")
// Extension function called using an instance
a.output()
// Extension function called on null
null.output()
}
class mynewClass {
// the companion object declaration
companion object {
fun display(){
println("The companion object's defined
function")
}
}
}
fun main(args: Array<String>) {
// invoking the member function
val obj = mynewClass.display()
}
Example:
class mynewClass {
companion object {
168 ◾ Kotlin: The Ultimate Guide
Unary Operators
The table below lists the many functions that may define for unary opera-
tors. These functions modify the caller instance.
The type for which the operator is defined is represented by r in this example.
The overloaded functionality is defined within the functions.
Usability Aspects of Kotlin ◾ 169
Binary Operators
The binary operators and their equivalent functions are shown in the table
below. All of these functions affect the instance that is being called.
//main-function
fun main() {
val objt1 = Objects("Chairs")
// Calling-overloaded-function
objt1+9
println(objt1)
}
Other Operators
Because Kotlin has many operators, declaring each for a type is not a
good programming practice. The below table lists some of the other useful
Kotlin operators that may be overloaded.
Enum Initializing
Kotlin enums, like Java enums, can have constructors. Enum constants
may initialize by passing particular values to the main constructor since
they are Enum class objects.
Here’s an example of how to color-code cards:
• ordinal: This property stores the ordinal value of the constant, which
is usually a zero-based index.
• name: This property contains the name of the constant.
Methods:
• values: This method returns a list of all the constants in the enum
class.
• valueOf(): The enum constant defined in enum that matches the
input string is returned. If the constant is not found in the enum, an
IllegalArgumentException is thrown.
Example:
enum class WEEKDAY {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY
}
fun main()
{
// A straightforward demonstration of
properties and methods
for (day in WEEKDAY.values()) {
println("${day.ordinal} = ${day.name}")
}
println("${WEEKDAY.valueOf(" FRIDAY ")}")
}
174 ◾ Kotlin: The Ultimate Guide
Example:
// A default value is provided for the property
enum class WEEKS(val isWeekend: Boolean = false){
SUNDAY(true),
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
// Default-value-overridden
SATURDAY(true);
companion object{
fun today(obj: WEEKS): Boolean {
return obj.name.compareTo("SATURDAY")
== 0 || obj.name.compareTo("SUNDAY") == 0
}
}
}
fun main(){
// A simple demonstration of properties and
methods
for(day in WEEKS.values()) {
println("${day.ordinal} = ${day.name} and
is weekend ${day.isWeekend}")
}
val today = WEEKS.MONDAY;
println("Is today a weekend ${WEEKS.
today(today)}")
}
Usability Aspects of Kotlin ◾ 175
// enum-class defining
enum class Seasons(var weather: String) {
Summer("cold"){
// if not override the function foo() compile
time error
override fun fooo() {
println("The cold days of year")
}
},
Winter("hot"){
override fun fooo() {
println("The Hot days of year")
}
},
Rainy("moderate"){
override fun fooo() {
println("The Rainy days of year")
}
};
abstract fun fooo()
}
// the main function
fun main(args: Array<String>) {
// calling fooo() function override be Summer
constant
Seasons.Summer.fooo()
}
fun main(){
when(WEEKDAYS.SUNDAY){
WEEKDAYS.SUNDAY -> println("Today is Sunday")
WEEKDAYS.MONDAY -> println("Today is Monday")
WEEKDAYS.TUESDAY -> println("Today is
Tuesday")
WEEKDAYS.WEDNESDAY -> println("Today is
Wednesday")
WEEKDAYS.THURSDAY -> println("Today is
Thursday")
WEEKDAYS.FRIDAY -> println("Today is Friday")
WEEKDAYS.SATURDAY -> println("Today is
Saturday")
// Adding an else clause will generate a
warning
}
}
KOTLIN GENERICS
Generics are helpful features that allow us to create classes, methods, and
properties that may be accessed using a variety of data types while still
ensuring compile-time type safety.
Creating parameterized classes: A type-parameterized class or function
is a generic type. We always use angle brackets () to define the type param-
eter in the program.
The following is the generic class definition:
class mynewClass<E>(text: E) {
var name = text
}
Usability Aspects of Kotlin ◾ 177
The type arguments can remove if the parameters can deduce from the
constructor arguments:
type class is a general type class that accepts arguments of both int and
String types.
Example:
class Companie<E> (text : E){
var d = text
init{
println(d)
}
}
fun main(args: Array<String>){
var name: Companie<String> = Companie<String>(
"Thehubtutors")
var rank: Companie<Int> = Companie<Int>(19)
}
Variance
Unlike Java, Kotlin makes arrays invariant by default. By extension, generic
types are invariant in the Kotlin. The out and in keywords may be useful
here. Invariance is the property that prevents a standard generic function/
class written for a single data type from taking or returning another data
type. Any is the supertype of all extra datatypes.
There are several types of variation:
The in Keyword
To assign it to the reference of its subtype, we might use the keyword in
on the generic type. The in keyword may only use on parameters that are
consumed rather than produced:
Covariance
Subtypes is permitted but not supertypes, i.e., the generic function/class
may take subtypes of the datatype for which it is already defined, e.g., a
generic class made for Number can accept int, but a generic class built for
int cannot accept Number. This may be done in Kotlin by using the out
keyword, as seen below:
fun main(args: Array<String>) {
val c: MyClass<Any> = MyClass<Int>()
// Error: Type-mismatch
val d: MyClass<out Any> = MyClass<String>()
// Works since String is subtype of Any
val e: MyClass<out String> = MyClass<Any>()
// Error since Any is supertype of String
}
class MyClass<X>
180 ◾ Kotlin: The Ultimate Guide
Contra Covariance
It is used to substitute a supertype value in subtypes, implying that the
generic function or class may take supertypes of the datatype for which it
is already defined. A generic class designed for Number, for example, can-
not accept int, but a generic class defined for int can accept Number. It is
performed in Kotlin by using the in keyword as follows:
fun main(args: Array<String>) {
var c: Container<Dog> = Container<Animal>()
//compiles-without-error
var d: Container<Animal> = Container<Dog>()
//gives-compilation-error
}
open class Creature
class Cat : Animal()
class Container<in C>
Type Projections
It is possible to copy all of the elements of an array of some type into an
array of Any type, but for the compiler to compile our code, the input
argument must annotate with the out keyword. Consequently, the com-
piler decides that the input argument can be of Any type.
Kotlin code for copying array members into another array:
fun copy(from: Array<out Any>, to: Array<Any>) {
assert(from.size == to.size)
// copying (from) array to (to) array
for (d in from.indices)
to[d] = from[d]
// printing elements of array in which copied
for (d in to.indices) {
println(to[d])
}
}
Usability Aspects of Kotlin ◾ 181
Star Projections
The star(*) projection is used when we don’t know what kind of value we’re
looking for and just want to output all the elements in an array.
Example:
// star-projection in array
fun printArray(array: Array<*>) {
array.forEach { print(it) }
}
fun main(args :Array<String>) {
val name = arrayOf("Worst","for","Good")
printArray(name)
}
Kotlin Functional
Programming
IN THIS CHAPTER
➢➢ Lambdas
➢➢ Higher-Order functions
➢➢ Local functions
➢➢ Scope functions
➢➢ Lists and maps
LAMBDA EXPRESSION
As we all know, the syntax of Kotlin lambdas is quite similar to that of
Java lambdas. An anonymous function does not have a name. We may call
lambda expressions anonymous functions.
Example:
fun main(args: Array<String>) {
val company = { println("PeeksforPeeks")}
// invoking the function method1
company()
// invoking the function method2
company.invoke()
}
Syntax:
val lambda_names : Data_type = { argument_List ->
code_body }
Example:
val sum = {x: Int, y: Int -> x + y}
Except for the code body, the lambda expression in Kotlin has optional
parts. The lambda expression is shown below after the optional component
has been removed.
It’s worth noting that we don’t always need a variable because it can be
supplied directly as an argument to a method.
Program:
// with the type annotation in lambda expression
val sum1 = { x: Int, y: Int -> x + y }
// without type annotation in lambda expression
Kotlin Functional Programming ◾ 185
In this case, the Kotlin compiler evaluates it as a function that takes two
Int parameters and returns an Int value.
ANONYMOUS FUNCTION
An anonymous function is quite similar to a regular function except for
the omission of the function’s name from the declaration. The anonymous
function’s body can be either an expression or a block.
Higher-Order Function
Higher-Order functions in Kotlin are functions that can receive a function
as an argument or return a function. We shall pass anonymous functions
or lambdas instead of passing Integer, String, or Array as function param-
eters. Lambdas are frequently passed as parameters in Kotlin functions for
simplicity.
The lambda expression is passed as an argument to the Higher-Order
function: A lambda expression can pass as a parameter to Higher-Order
function.
There are two kinds of lambda expressions that may be passed:
// lambda expression
var lambda = {println("Huboftutors: A Computer Science
portal for Hub") }
//the higher-order function
fun higherfunc( lmbd: () -> Unit ) { // accepting
lambda as parameter
lmbd() //invokes the
lambda expression
}
fun main(args: Array<String>) {
//invoke higher-order function
higherfunc(lambda) // passing the
lambda as parameter
}
higherfunc(lambda)
It is given two parameters. One is the String type, and the other is the
function:
The higher function is invoked from the main function by supplying the
string and function as arguments.
This is known as the Fizz Buzz issue. The requirement instructs us to print
the integers from the beginning to the finish value. However, if integer is a
multiple of 2, we should print Fizz. We should print Buzz if it is a multiple
of four. Print Fizz Buzz together if it is a multiple of 2 and 4.
The first solution is short and readable; however, it has some dupli-
cated code. Because the modulo checks are coded twice, an error is
likely doubled. Obviously, this example is relatively simple, so the
Kotlin Functional Programming ◾ 195
possibilities of a typo are minimal; yet, it helps to show the issue for
more complex issues. We may declare a local function for each mod-
ulo test, using only one line of code. This gets us to our next solution
iteration:
In this case, our if…else branches now call the nested methods isFizz and
isBuzz. However, passing x to the function each time is still a bit verbose. Is
there any way to avoid this? Local functions can be defined not just directly
within other functions, but also in for loops, while loops, and other blocks:
We’ve moved the function definitions within the for loop in this third iter-
ation of our function. As a result, we may skip the parameter definitions
196 ◾ Kotlin: The Ultimate Guide
This results in our final solution, which avoids code repetition and is more
understandable than the initial iteration.
class Companie() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
fun main() {
// without using the scope function
// creating instance of the Companie Class
val hft = Companie()
// initializing members of the class
hft.name = "Thehuboftutorials"
Kotlin Functional Programming ◾ 197
class Companie() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
fun main() {
// using the scope function
val hft = Companie().apply {
// don't need to use-object
// name to refer members
name = "Thehuboftutorials"
objective = "Computer science tutorial for
Students"
founder = "Akshit Jain"
}
println(hft.name)
}
Explanation: We’ve probably observed that when we don’t use the scope
function, we have to specify the object name every time we refer to a
class member. We may use the scope function to refer to members with-
out specifying the object name. This is one method of using the scope
function.
SCOPE FUNCTIONS
Every scope function has well-defined use cases, even though they all have
roughly the same conclusion. Let’s take a closer look at each scope func-
tion and its associated use cases.
• let
• run
• with
• apply
• also
1. let function
• Context object: it
• Return value: lambda result
Case in point: The let function is frequently used to give null
safety checks. Use the safe call operator(?.) with ‘let’ for null
safety. It only performs the block with a non-zero value.
Kotlin Functional Programming ◾ 199
Example:
fun main() {
// nullable variable
// with the value as null
var x: Int? = null
// using let function
x?.let {
// statements will
// not execute as x is null
print(it)
}
// re-initializing value of x to 2
x = 2
x?.let {
// statements will execute
// as x is not null
print(x)
}
}
Example:
class Companie() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
fun main() {
Companie().apply {
200 ◾ Kotlin: The Ultimate Guide
3. with function
• Context object: this
• Return value: lambda result
Case in point: ‘with’ is recommended for invoking functions
on context objects without passing the lambda result.
Example:
class Companie() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
fun main() {
val hft = Companie().apply {
name = "thehuboftutorials"
objective = "Computer science tutorials
for Students"
founder = "Akshit Jain"
}
// with function
with(hft) {
// similar to println( "${this.name}" )
println(" $name ")
}
}
4. run function
• Context object: this
• Return value: lambda result
The ‘run’ function is a mix of the ‘let’ and ‘with’ functions.
Kotlin Functional Programming ◾ 201
Example:
class Companie() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
5. also, function
• Context object: it
• Return value: context object
202 ◾ Kotlin: The Ultimate Guide
Example:
fun main() {
// initialized
val list = mutableListOf<Int>(11, 22, 33)
// later if we want to perform multiple-
operations on this list
list.also {
it.add(44)
it.remove(22)
// more operations if needed
}
println(list)
}
Object References
In scope functions, there are two methods for referring objects:
Example:
Company().apply {
// same as : name = "thehuboftutorials"
this.name = "thehuboftutorials"
this.founder = "Akshit Jain"
this.objective = "Computer science tutorials
for Students"
}
Example:
Company().let {
it.name = "thehuboftutorials"
it.founder = "Akshit Jain"
it.objective = "Computer science tutorials for
Students"
}
Return Values
A scope function can return one of two sorts of return values:
Example:
class Companie {
var name: String = "thehuboftutorials"
var founder: String = "Akshit Jain"
var objective: String = "Computer science
tutorials for Students"
}
fun main() {
val founderName: String = with(Companie()) {
// 'founder' is returned by 'with' function
founder
}
println("HfT's Founder : $founderName")
}
Example:
class Companie {
var name: String = "thehuboftutorials"
var founder: String = "Akshit Jain"
var objective: String = "Computer science
tutorials for Students"
}
fun main() {
val hft = Companie().apply {
204 ◾ Kotlin: The Ultimate Guide
// any statements
}
// hft is an object of class Companie as
// return of apply() is the context object
print("HfT's Founder : ${hft.founder}");
}
Notes:
• Scope functions improve the readability, clarity, and conciseness of code.
• “This” and “it” are object references.
• The context object and lambda result are returned as the return value.
• To prevent NullPointerException, operate with nullable objects.
• Change the configuration of an item.
• run: execute lambda expressions on a nullable object.
• Additionally, other procedures can add.
• with: working with non-null items.
KOTLIN COLLECTIONS
The concept of collections is introduced in Kotlin, as it is in Java Collections.
A collection frequently consists of several things of the same sort, known
as elements or items in the collection. The Kotlin Standard Library includes
a comprehensive set of collection managing functions.
Types of Collections
In Kotlin, collections are categorized into two kinds:
1. Immutable Collection
2. Mutable Collection
Immutable Collection
It denotes that it solely offers read-only capabilities and that its elements
are not editable. Immutable collections and the strategies related to them
are as follows:
3. Map: Each key in a map is distinct and stores just one value; it is
a collection of key-value pairs. Each key represents a single value.
Values can duplicate, but keys must be unique. Maps are used to store
the logical relationship between two objects, such as a student’s ID
and name. Because it is immutable, its size is fixed, and its methods
give read-only access. The immutable map is demonstrated in the
following Kotlin application:
206 ◾ Kotlin: The Ultimate Guide
Mutable Collection
It is capable of both read and write. The following are examples of mutable
collections and the strategies that go with them:
1. List: Because mutable lists may be read and written to, declared list
elements can be removed or added. The mutable list is demonstrated
in the following Kotlin program:
fun main(args : Array<String>) {
var mutableLists = mutableListOf("Rahil","Lali
ta","Pihu")
// we modify element
mutableLists[0] = "Rajni"
// add one more element in the list
mutableLists.add("Anmol")
for(item in mutableLists){
println(item)
}
}
2. Set: The mutable Set supports read and write operations. We may
simply add or remove elements from the collections while keeping
the order of the components. Write the following Kotlin code to
demonstrate the mutable set:
Kotlin Functional Programming ◾ 207
ArrayList IN KOTLIN
The ArrayList class in Kotlin is used to create a dynamic array. The phrase
“dynamic array” refers to an array’s ability to expand or decrease its size
depending on its demands. It also can read and write. ArrayList is a non-
synchronized list that may include duplicates. We use ArrayList to get the
index of a specific item, convert an ArrayList to a string or another array,
and other things.
Constructors:
Example:
var arraylists1=ArrayList<String>()
//adding all the elements from arraylists to
arraylists1
println("Elements in the arraylist1:")
arraylist1.addAll(arraylists)
for(c in arraylists1)
println(c)
}
arraylists.add("Piiks")
arraylists.remove("of")
// iterating through the elements
for(r in arraylists)
print("$r ")
}
listOf() IN KOTLIN
List is a collection of elements that have been sorted in a specified order.
Lists in Kotlin can be immutable (non-modifiable) or mutable (modifiable)
(can be modified).
Read-only lists are created with listOf(), and their items cannot edit, but
mutable lists are created with mutableListOf(), and their contents may be
amended or modified.
In the Kotlin program list, integers are used:
fun main(args: Array<String>) {
val r = listOf('1', '2', '3')
println(r.size)
println(r.indexOf('2'))
println(r[2])
}
212 ◾ Kotlin: The Ultimate Guide
println(numbs1.first())
println(numbs1.last())
}
Explanation:
for (name in names1) {
print("$name, ")
}
214 ◾ Kotlin: The Ultimate Guide
The for loop traverses the list. In each cycle, the variable ‘name’ refers to
the next element of the list.
This method makes use of the size of the list. The til keyword generates a
collection of list indexes.
Using the forEachIndexed() function, we loop over the list with index and
value accessible in each iteration.
Explanation:
val asc1 = list.sorted()
Kotlin Functional Programming ◾ 215
Explanation:
val rest = lists.contains(0)
Checks if the lists include 0 and returns true or false, saving the result in
rest1.
This function determines if the list contains the numbers 3 and –1.
216 ◾ Kotlin: The Ultimate Guide
setOf() in Kotlin
The Kotlin Set interface is a general, unordered collection of items con-
taining duplicates. Sets are classified as changeable or immutable in
Kotlin.
Syntax:
fun <C> setOf( vararg elements: C): Set<C>
Description:
Set Indexing
The index functions indexOf() and lastIndexOf() can be used to deter-
mine the index of the specified element. We may alternatively use the ele-
mentAt() function to find elements at a certain index.
Index-using the Kotlin program:
Set the first() and last() element: To get the first and last element in a set,
use the first() and last() functions.
Example:
fun main(args: Array<String>){
val captain = setOf(01,02,03,04,"Smriti","Raman",
"Pihu","Kalash","Rita","Disha")
println("the first element of the set is:
"+captain.first())
println("the last element of the set is:
"+captain.last())
}
Set Basics
We’ll go through basic functions like count(), max(), min(), sum(), and
average ().
Basic functions are used in Kotlin program:
println("seta1.isEmpty() is ${seta1.isEmpty()}")
// since Empty sets are equal
//check if 2 sets are equal or not
println("seta1 == setb1 is ${seta1 == setb1}")
println(seta1) //printing first set
}
Syntax:
fun <C> mutableSetOf( vararg elements: C):
MutableSet<C>
Description:
Example:
fun main(args: Array<String>)
{
//declaring the mutable set of integers
val seta1 = mutableSetOf( 101, 202, 303,
404, 303);
println(seta1);
//adding the elements 606 & 707
seta1.add(606);
seta1.add(707);
println(seta1);
//removing the 303 from the set
seta1.remove(303);
println(seta1);
//another way to add the elements is by using
listOf() function
seta1 += listOf(808,909)
println(seta1)
}
Set Indexing
The index methods indexOf() and lastIndexOf() can be used to determine
the index of the provided element (). To discover elements at a certain
index, we may also utilize the elementAt() function.
Index-using the Kotlin program:
Example:
fun main(args: Array<String>){
val captain = mutableSetOf(01,02,03,04,
"Karishma","Smriti",
"Pihu","Maya","Rita","Disha")
println("first element of the set: "+captain.
first())
println("last element of the set: "+captain.
last())
}
Traversal in a mutableSet
To explore all the elements in a mutableSet, we may use a for loop and an
iterator.
fun main(args: Array<String>)
{
//declaring mutable set of the integers
val seta1 = mutableSetOf( 101, 202, 303,
404, 303);
//traversal of the seta1 using iterator 'item'
for(item in seta1)
println( item )
}
"Pihu","Kama;","Raman","Alka")
var names = "Raman"
println("The set contains element $names or not?"
+
" "+captain.contains(names))
var nums = 5
println("The set contains element $nums or not?" +
" "+captain.contains(nums))
println("the set contains given elements or not?" +
" "+captain.containsAll(setOf(01,03,
"Root")))
}
hashSetOf() IN KOTLIN
Kotlin HashSet is a general, unordered collection of items with no dupli-
cates. It is responsible for implementing the set interface. hashSetOf() is a
function that returns a mutable hashSet that may be read and written to.
To hold all of the components, the HashSet class use hashing.
Syntax:
fun <C> hashSetOf(vararg elements: C): HashSet<C>
Kotlin Functional Programming ◾ 223
It returns a new HashSet with the requested elements but offers no assur-
ances about the order sequence specified when storing.
Example:
fun main(args: Array<String>)
{
//declaring hash set of integers
val seta1 = hashSetOf(11,22,33,33);
//printing the first-set
println(seta1)
//declaration of hash set of strings
val setb1 = hashSetOf("Piiks","of","piiks");
println(setb1);
}
hashSet Traversal
We can traverse hashSet in a loop using an iterator.
Indexing in a hashSet
The index of the specified element can be obtained using the index meth-
ods indexOf() and lastIndexOf(). We may alternatively utilize the element
At() function to find elements at a certain index.
Index-using the Kotlin program:
Using the isEmpty() methods to check the equivalence of empty hash sets:
mapOf () in Kotlin
A Kotlin map is a set of object pairs. A map’s data is kept in the form of
pairs, each of which has a key and a value. Map keys are unique, and the
map maintains just one value for each key.
Kotlin distinguishes between immutable and mutable maps. Immutable
maps produced by mapOf() are read-only, but mutable maps produced by
mutableMapOf() may be read and write.
Syntax:
fun <C, D> mapOf(vararg pairs: Pair<C, D>): Map<C, D>
• The first value in the pair is the key, and the second is the value of the
related key.
226 ◾ Kotlin: The Ultimate Guide
• If several pairs have the same key, the map will return the value of
the last pair.
• The map entries are traversed in the specified order.
Map Size
A map’s size may determine in two ways. Using size property of the map
and the count() function.
fun main() {
val ranks1 = mapOf(1 to "Canada",2 to
"WestAfrica",3 to "Russia",4 to "London")
//method-1
println("size of the map: "+ranks1.size)
//method-2
println("size of the map: "+ranks1.count())
}
Empty Map
We can build an empty serializable map using mapOf ().
Kotlin Functional Programming ◾ 227
MapOf() Example:
fun main(args: Array<String>)
{
//creation of an empty map using the mapOf()
val map = mapOf<String, Int>()
println("The Entries: " + map.entries) //
entries of the map
println("The Keys:" + map.keys) //keys of the
map
println("The Values:" + map.values) //values
of the map
}
Example:
fun main(args: Array<String>)
{
//let's make the two values with the same key
val map1 = mapOf(1 to "piiks1",2 to "of", 1
to "piiks2")
// return-map-entries
println("Entries of map is: " + map1.entries)
}
Explanation: In this scenario, key value 1 contains two values: piiks1 and
piiks2, but because mapOf() can only have one value for a single key item,
the map only keeps the most recent value, and piiks1 is erased.
HashMap IN KOTLIN
Kotlin HashMap is a collection of object pairings. Hash Tables are used
to construct MutableMap in Kotlin. It stores information in the form of a
key and value pair. Map keys are unique, and the map maintains just one
value for each key. HashMap<key, value> or HashMap<K, V> is how it’s
written.
Kotlin Functional Programming ◾ 229
for(key in hashMap1.keys){
println("Element at key $key is :
${hashMap1[key]}")
}
//creation of another hashMap1 object with the
//previous version of the hashMap1 object
var secondHashMap : HashMap<String, Int>
= HashMap<String, Int> (hashMap1)
println("\n" + "Second HashMap : ")
for(key in secondHashMap.keys){
//using hashMap1.get() function to fetch
values
println("The Element at key $key : ${hashMap1.
get(key)}")
}
//this will clear whole map and make it empty
println("hashMap1.clear()")
hashMap1.clear()
println("After Clearing : " + hashMap1)
}
//function to print the hashMap1
fun printHashMap(hashMap1: HashMap<String, Int>){
// isEmpty() function to check whether the
// hashMap1 is empty or not
if(hashMap1.isEmpty()){
println("hashMap1 is empty")
}else{
println("hashMap1: " + hashMap1)
}
}
hashMap1.put("Iron-Man", 1300)
hashMap1.put("Thor", 300)
hashMap1.put("Spider-Man", 1900)
hashMap1.put("Nick-Fury", 1200)
for(key in hashMap1.keys) {
println("Element at the key $key :
${hashMap1[key]}")
}
//return the size of hashMap1
println("\n" + "hashMap1.size : " + hashMap1.size
)
//adding new element in the hashMap
hashMap1["Black-Widow"] = 3100;
println("hashMap1.size : " + hashMap1.size + "\n")
for(key in hashMap1.keys) {
println("Element at key $key :
${hashMap1[key]}")
}
}
println("hashMap1.get(\"Thor\") : "
+ hashMap1.get("Thor") + "\n")
//replacing some value
hashMap1.replace("Cap", 909);
hashMap1.put("Thor", 2100);
println("hashMap1.replace(\"Cap\", 909)" +
" hashMap1.replace(\"Thor\", 2100)) :")
for(key in hashMap1.keys) {
println("Element at key $key :
${hashMap1[key]}")
}
}
IN THIS CHAPTER
➢➢ Exception handling
➢➢ Logging
➢➢ Unit testing
➢➢ “Nothing” type
Exceptions in Kotlin
Exceptions in Kotlin are unchecked and can only be discovered at run
time. Throwable is the parent of all exception classes.
We frequently use the throw-expression to throw an exception object:
throw Exception("Throw-me")
Exception Handling
In the example below, we divide an integer by 0 (zero), which results in an
ArithmeticException. The catch block will be performed because this code
is in the try block.
Code Management and Exception Handling ◾ 235
finally{
println("can't-ignore ")
}
}
NullPointerException Example
Here’s an example of a NullPointerException raised when the length()
method of a null String object is called:
public class Exception_Example {
private static void printLength(String strg) {
System.out.println(strg.length());
}
public static void main(String args[]) {
String myString = null;
printLength(myString);
}
}
Syntax:
try {
// the code that throw exception
} catch(c: ExceptionName) {
// catch exception, handle it
}
import kotlin.ArithmeticException
fun main(args : Array<String>){
try{
var numb = 40 / 0
}
catch(e: ArithmeticException){
// caught, handles it
println("not allowed divide by zero")
}
}
Syntax:
try {
//the code that can throw-exception
} finally {
// code of finally-block
}
Code Management and Exception Handling ◾ 239
We used the try with finally block instead of the catch block in the previ-
ous program. In this scenario, the catch block ignores the exception and
performs the finally block instead.
Finally block with the try-catch block Syntax:
try {
// the code that throw-exception
} catch(c: ExceptionName) {
// catch the exception, handle it.
} finally {
// code of finally-block
}
Syntax:
// the outer try-block
try
{
//the inner try-block
try
{
//the code that can throw an exception
}
catch(c: SomeException)
{
//it catch the exception, handles it
}
}
catch(c: SomeException)
Code Management and Exception Handling ◾ 241
{
// it catch the exception, handles it
}
Remember that this result is generated for a random integer. Don’t be con-
cerned if we get a different outcome because it will be decided by the ran-
dom number generated at the time.
Syntax:
try {
// the code may throw-exception
} catch(c: ExceptionNameOne) {
// catch the exception one, handle it
} catch(c: ExceptionNameTwo) {
// it catch the exception two, handle it
}
242 ◾ Kotlin: The Ultimate Guide
import java.util.Scanner
object Tests {
@JvmStatic
fun main(args: Array<String>) {
val scn = Scanner(System.'in')
try {
val n = Integer.parseInt(scn.nextLine())
if (612% n == 0)
println("$n is a factor of 612")
} catch (c: ArithmeticException) {
println(c)
} catch (c: NumberFormatException) {
println(c)
}
}
}
LOGGING IN KOTLIN
Kotlin is a new programming language. JetBrains, the firm behind IntelliJ,
Resharper, and other prominent development tools, released it as open
source in 2012. Kotlin is a statically typed language with extensive func-
tional programming features. It is frequently executed on the Java Virtual
Machine (JVM) and supports Java libraries, although it may also be com-
piled to Javascript or native code.
We’ll begin with the most basic example of Kotlin logging that can use.
After that, we’ll utilize better logging tools after exploring why logging
is important and how it affects our ability to maintain our code. We’ll
also show how appropriate logging increases our capacity to troubleshoot
issues, monitor our app, and provide better support to our clients.
• Because the JetBrains team designed Kotlin, using IntelliJ for this
lesson makes logical. We’ll locate the community edition here if we
don’t already have it.
• Begin by making a new project. In the welcome page, select the new
project menu option.
• Next, under the project settings, pick Kotlin and Kotlin JVM.
• Next, enter a name for our project and click Next.
• After we click Finish, IntelliJ will build our project.
• It’s now time to make our first file and log a message. Right-click on
the src folder in the project directory.
• This will open up a window where we can enter the file name. It
should be called logging.
• Click OK, and we’re ready to start writing code.
• We’ve already completed the difficult part by building the simplest
Kotlin logging example that will run. Here’s our first program’s code:
import java.io.File
fun main() {
File("application.log").writeText
("Hello-Logging")
}
244 ◾ Kotlin: The Ultimate Guide
• Enter that, and start our program by right-clicking the source file
and selecting run.
• IntelliJ will compile and execute our code.
The findings are shown at the bottom of the IDE window by IntelliJ.
Because we told Kotlin to create it there, our log file will locate in the proj-
ect’s working directory. To open our log file in the editor, double-click it,
and we’ll see the log message.
This code is adequate for simple logging, but it is not a long-term solu-
tion. Is the Kotlin keeping fit open in the background, or does it open it
for each call? What would happen if hundreds of messages were sent? Is
it threadsafe, or does accessing the file every time cause the application to
crash? Would the file be corrupted if numerous threads ran concurrently?
After a quick explanation of what logging is, let’s look at a better
approach to do Kotlin logging.
• Our code may access any Java library when we execute Kotlin in the
JVM. So, let’s configure your application with Logback, one of Java’s
most popular logging frameworks.
Code Management and Exception Handling ◾ 245
• Logback may now call from Kotlin. Add new Kotlin file to the proj-
ect. Utilities are what it’s named.
The code is as follows:
fun getLogger(): Logger = LoggerFactory.
getLogger(Logger.ROOT_LOGGER_NAME)
fun getLogger(name: String): Logger =
LoggerFactory.getLogger(name)
We now have a timestamp, the name of the function, the logging level, the
name of the logger, and the message. So, we’ve already enhanced our log-
ging with only a few lines of code.
Why Log?
Kotlin is a valuable programming language. With more concise syntax and
support for functional and object-oriented programming, it has full access
to Java’s vast ecosystem. That doesn’t imply our Kotlin code is impenetra-
ble. We’ll still need the means to observe what’s going on within the app.
Even the finest Kotlin code contains flaws and will encounter unexpected
circumstances. Kotlin logging is required.
The Kotlin is a popular programming language for Android. Android
apps encounter a variety of unexpected scenarios. We may launch our app
in a simulator to catch mistakes while it is still in development. A system
for recording logs as part of problem reports, on the other hand, is a help-
ful tool. On our client devices, we may launch a remote debugging session.
Logs are the closest thing to being there.
Logs may use for more than just isolating issues. We may use them to
monitor our application while running and identify areas for improve-
ment. And, of course, the use of logs does not end there. Logs are a busi-
ness necessity if our code processes financial transactions.
• Timestamp: the time when the event in the log entry occurred. We’ll
see how to include this into messages in the section following.
• The location of the event: where did it take place? Whom are you
addressing? During a debugging session, saying “It worked” or “It’s
broken” may be beneficial or funny. “Failed to connect to the data-
base at 192.9.168.3:5000” is more useful in production.
Code Management and Exception Handling ◾ 247
• Severity level: Each entry requires a flag in context with other mes-
sages. ERROR, WARN, INFO, DEBUG, and TRACE are all defined
by Logback.
Configuring Logger
We configure the Logback file, which we supply to the library through a
Java property or by including it in the classpath. To make things easy, we’ll
utilize the classpath in this lesson.
Make a new file in our project’s source directory. The default configura-
tion file name is logback.xml. Include the following information:
<configuration>
<appender name="FILE" class="ch.qos.logback.core.
FileAppender">
<file>my_App.log</file>
<encoder>
<pattern>%date %level [%thread]
%logger{12} [%file:%line] %msg%n</pattern>
</encoder>
<appender name="STDOUT" class="ch.qos.logback.
core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
Logback will detect this file at runtime since the directory from where you
execute your code is part of the project’s classpath. It is divided into three
pieces. They are all log appenders, save for two. The root logger is defined
by the other.
A log appender is exactly what its name suggests. It’s an item that adds to
the end of a log. The first appender writes to a file, while the second writes
to standard output; the terminal. Logback makes it simple to deliver logs to
many destinations; simply add another appender. Each appender is equipped
with an encoder. The encoder prepares the message before the appender sends
the message to the logger. In a minute, we’ll see how the two encoders vary.
248 ◾ Kotlin: The Ultimate Guide
Hello-Logging
The program also produces log file called my_App.log in the project root.
It is only one line:
Both appenders received the logging output, but the messages were speci-
fied differently. The encoders are distinct.
Here’s the STDOUT encoder:
<encoder>
<pattern>%msg%n</pattern>
</encoder>
<encoder>
<pattern>
%date %level [%thread] %logger{12} [%file:%line]
%msg%n</pattern>
</encoder>
output, we can safely assume that %msg is the formatter for the log data.
Here’s a table with the rest of the information.
Word Description
%date date, including a timestamp
%level log message level
%thread thread logging the message
%logger name of logger
%file source code file name
%line source code line number
%msg Message contents
%n Platform-specific linefeed character
Although these are merely the fundamental formatters, we’ve already met
the requirements for useful log messages using the file encoder. It explains
where the message originated in our source code. It has a date and time, as
well as the log level.
Logging to a File
Our log files are also being stored to a persistent media.
<appender name="FILE" class="ch.qos.logback.core.
FileAppender">
<file>my_App.log</file>
<encoder>
<pattern>%date %level [%thread] %logger{10}
[%file:%line] %msg%n</pattern>
</encoder>
</appender>
With each program’s execution, the file appender creates the file and opens
and closes it. If we rerun it, we’ll notice that a second line has been added.
Logback also features a RollingFileAppender. It will produce a new file
and rename the old one for us so that our log files do not get too large to
manage or create a new file at regular intervals.
Restart the program. The log message is suppressed because we set the root
logger to INFO.
Messages can be routed to specified destinations using appenders and
loggers. Assume we want to send just debug messages to the console and
only information or higher to a file. Make a new logger and assign it the
file appender:
fun main() {
getLogger("productions").info("Start log test")
getLogger("test").debug("w00t")
}
We’re replacing the root logger with two named loggers. One of
these is the Logback configuration’s production logger. Restart the
program.
Both messages are sent to the console:
The output to terminal was sent down from the root logger to the new
logger. However, because we changed its level to information, it did not
inherit the debug messages. That’s a lot of power in only a few lines of
code.
Code Management and Exception Handling ◾ 251
UNIT TESTING
A unit test is a piece of code separate from our application. It can generate
and invoke our application’s public classes and methods. But why would
we want to build code that we would never use in our application? Simply
because we want to ensure that the application code works as expected.
And we want to double-check it to ensure that you don’t disrupt any cur-
rent functionality. And, like me, we’re probably lazy and don’t want to do
it manually. As a result, we may build test code to check our application
behavior. Unit Tests are here to help.
Unit testing focuses on testing only a small number of classes (one or
more) that perform a single function (domain) and do not rely on libraries
or framework code. We don’t want to test the libraries we use (at least not
in a unit test); they should just function. We want to concentrate solely on
our valuable code and demonstrate no hidden issues.
Simple Android Application
Before we begin writing any tests, we’d want to show us a simple Android
app with a login screen. It accepts two inputs for login and password and
validates them. When the inputs are accurate, we can sign in with the
proper data or receive an error indicating wrong credentials. We chose
MVP design since it would allow us to develop tests that are not dependent
on the Android framework.
Project Setup
We can now write our first test when we have an application to test. The
JUnit4 test runner and the Kotlin programming language will use. A test
runner is a library that executes our test code and gathers the results in a
user-friendly manner.
We may name tests in Kotlin with natural names, such as login with the
right username and password; however, this only applies to code that runs
on the JVM. Fortunately, unit tests are run on the JVM, utilizing such
descriptive names.
Test Structure
Each test should be built using the following blocks:
• Arrange/Given: We will prepare the necessary data for the test Act/
When – we will invoke a single method on the tested object.
• Assert/Then: We will check the test result, whether it is pass or fail.
Because JUnit4 does not split test blocks, it is easy to add comments to test
code, especially if we are starting off with testing.
@Test
fun 'login with the correct login and password'() {
//given
//when
//then
}
Given Block
Our test will start with the supplied block, in which we will prepare our
test data and build the tested object.
We’re making a new instance of the tested object LoginRepository and
assigning it to the read-only attribute. It’s easier to distinguish between
tested objects and test parameters, thus I’m naming it objectUnderTest.
It can also be referred to as sut, topic, or target. Choose a name that best
describes us, but keep it constant throughout our project.
When we have an instance of the tested object, we may proceed to test-
ing the parameters. That is correctLogin with the value ‘dabcisski’ and
correctPassword with the value ‘correct’. It is critical to give each test
Code Management and Exception Handling ◾ 253
@Test
fun 'login with the correct login and password'() {
//given
val objectUnderTest = LoginRepository()
val correctLogin = 'dabcisski'
val correctPassword = 'correct'
//when
//then
}
When Block
In the when block, we must call the method we want to test using the
parameters we prepared in the previous block. As a result, we invoke
the function objectUnderTest.login (correctLogin, correctPassword). We
should just have one line of code in the when block to make it obvious what
is being tested.
@Test
fun 'login with the correct login and password'() {
//given
val objectUnderTest = LoginRepository()
val correctLogin = 'dabcisski'
val correctPassword = 'correct'
//when
objectUnderTest.login(correctLogin,
correctPassword)
//then
}
Then Block
It’s time to see if the tested object returns the expected result. However,
we must first store the result of the tested method in a property val result
and then analyze it in the then block. Now we can do an assertion to see
whether the return value matches what we anticipate. If the assertion is not
met, it will throw an error, and the test will fail.
In this situation, the returned object is a RxJava 2 Observable, but we
can simply convert it to TestObserver, a class that includes assertion meth-
ods. I’m testing to see if the result value is true; otherwise, the test will fail.
254 ◾ Kotlin: The Ultimate Guide
@Test
fun 'login with the correct login and password'() {
//given
val objectUnderTest = LoginRepository()
val correctLogin = 'dabcisski'
val correctPassword = 'correct'
//when
val result = objectUnderTest.login(login,
password)
//then
result.test().assertResult(true)
}
Running Test
We can run a test in Android Studio/IntelliJ by hitting Ctrl + Shift + F10,
or from a Terminal by typing ./gradlew test.
After running the test that we just wrote, we should see a green bar in
the IDE or BUILD SUCCESSFUL in the Terminal.
A LinkedList.
The sealed class and the Node<C> may be easily coded as follows:
Coding the empty list is a little more difficult. Every empty list is the same.
As a result, an empty list is an object. EmptyList must be a subclass of
LinkedList<T> as well. We could attempt to write.
Kotlin objects do not support type arguments. The above code will
not compile. Instead, we may try to delete the type parameter from the
EmptyList.
What does the Kotlin Nothing type look like? Select Tools -> Kotlin ->
Kotlin REPL from the Android Studio menu. Enter and run the command
println in the REPL window (Nothing::class.java). As a result,
println(Nothing::class.java)
class java.lang.Void
256 ◾ Kotlin: The Ultimate Guide
Java’s Void type backs up Kotlin’s Nothing type. Nothing is a type in Kotlin
that represents the absence of type.
Nothing’s constructor is private. Contrast the preceding code with the
Java equivalent:
The Void class in Java has a private constructor. Void cannot create. We are
unable to return a Void. As a result, it appears reasonable that we cannot
return Nothing in Kotlin.
Key Points
Nothing:
IN THIS CHAPTER
➢➢ Optimization tips
➢➢ Best coding practices
➢➢ Security and hardening ideas
OPTIMIZATION TIPS
This chapter discusses approaches for building Android code in Kotlin that
is both efficient and simple. JetBrains, the company behind the IntelliJ IDE,
created Kotlin, a general-purpose language that compiles to Java bytecode.
<RelativeLayout xmlns:android="http://schemas.android
.com/apk/res/android"
DOI: 10.1201/9781003308447-6 257
258 ◾ Kotlin: The Ultimate Guide
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingRight="@dimen/
activity_horizontal_margin"
android:paddingLeft="@dimen/
activity_horizontal_margin"
android:paddingBottom="@dimen/
activity_vertical_margin"
android:paddingTop="@dimen/
activity_vertical_margin"
tools:context="kotlineffiecienttechniques">
<TextView android:id="@+id/maintextview"
android:text="@string/helloo_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
And the activity code that uses static imports to change the text of the
maintextview:
package kotlineffiecienttechniques
import android.support.v7.app.ActionBarActivity
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import kotlinx.android.synthetic.main.
activity_main_activity2.*
public class MainActivity2 : ActionBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.
activity_main_activity)
maintextview.text = "Helloo Static Import!"
}
}
If we look at the code above, we’ll notice that we’ve ‘statically imported’ all
views using the import line.
import kotlinx.android.synthetic.main.activity_main_
activity.*
Code Optimization Ideas ◾ 259
To get the preceding code to compile, add the following to our build.gradle
dependencies:
dependencies {
compile 'org.jetbrains.anko:anko-sdk21:0.9' //
sdk19, sdk21, sdk23 are available also
compile 'org.jetbrains.anko:anko-support-v4:0.9'
// In case we need support-v4 bindings
compile 'org.jetbrains.anko:anko-appcompat-v7:0.9'
// For appcompat-v7 bindings
}
Apply plugin:
dependencies {
classpath "org.jetbrains.
kotlin:kotlin-android-extension:$kotlin_version"
}
return ISBN;
}
public void setISBN(String ISBN) {
this.ISBN = ISBN;
}
public float getPrices() {
return prices;
}
public void setPrice(float prices) {
this.prices = prices;
}
public int getQuantities() {
return quantities;
}
public void setQuantities(int quantities) {
this.quantities = quantities;
}
If we want to define the same POJO with the same functionality in Kotlin,
we may do it as follows:
This POJO differs from the previous one because it has a main contractor.
All arguments must be passed to the constructor when the object is created.
Defining a data class includes the methods ‘equals’, ‘hashCode’, and con-
tructor. This should be the preferable method for defining a POJO in Kotlin.
The above code defines a primary constructor to which values are passed.
The values are assigned to the members.
To construct an object of the Books class, do the following:
This eliminates the need for boilerplate code in the form of distinct con-
structor functions. The constructor just copies the parameters supplied to
it into the member variables. If we were writing our Android app in Java,
we would need to build such a constructor.
Inheritance in Kotlin is also safer; it cannot expand unless a class is
specified as open.
So, if we want to expand Book, we should define it as follows:
It’s only one line. We don’t even need to define the type of argument view
because it can be deduced statically. In Java, the same code would be:
maintextview.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
Toast.makeText(this, "Showing-Toast", Toast.
LENGTH_SHORT).show();
}
});
Code Optimization Ideas ◾ 263
Infix Functions
Infix functions are useful for readability since they allow us to type things
like “test” foo “c” for example, which is pretty awesome.
Inline Functions
An overhead occurs when a lambda expression in Kotlin is converted to
Java anonymous classes in Java 6 or 7. Lambda calls affect the call stack,
which influences performance.
Instead of initiating another method call and adding it to the call stack,
inline functions can utilize to make direct calls. When we pass in the
lambdas, it makes logical to utilize inline functions.
Tail Recursion
We tell compiler that we want to replace the method call with a for loop or
goto expression by using tailrec.
It can only use if the last call of a function is simply calling itself.
Sealed Classes
According to the Kotlin reference, we should use sealed classes to express
restricted class hierarchies, which occur when an item has a limited set of
types but cannot have any other type.
Code Optimization Ideas ◾ 265
In other words, they are useful for returning types that are not identical
but are related.
It gets fooo to return true. We may also limit the forEach scope just to
return values.
fun fooo() {
Observable.just(1)
.map{ intValue ->
return@map intValue.toString()
}
...
...
}
If we used return in the above code piece, it would return to foo, which
makes no sense in this context. The return@map, on the other hand,
returns the result of the map function, which is the desired behavior.
Operator Overloading
To override supported operators, use operator.
Lambda Extensions
They are just easier to read and type, much like markup.
status {
code = 403
descriptions = "Not-found"
}
lateinit
If a lateinit property is attempted to be used before it has been initialized,
it will throw an exception of type UninitializedPropertyAccessException.
Companion Objects
Companion Objects are the equivalent of Java static methods.
class MykotlinClass {
@Jvmstatic
companion object Factory {
fun create(): MyKotlinClass = MyKotlinClass()
}
}
Members of the companion object may access by using the class name as
the qualifier:
General Suggestions
Use the latest current Kotlin version. This way, we’ll always get the most
recent performance enhancements.
Avoid making large courses. During execution, they require a lengthy
time to build and load.
Between builds, keep downloaded and cached components. Kotlin/
Native downloads the necessary components and saves some of the results
to the $USER HOME/.konan directory when we compile a project. The
compiler uses this directory for subsequent compilations, helping them
run faster.
268 ◾ Kotlin: The Ultimate Guide
Configuration of Gradle
Due to the requirement to download dependencies, construct caches, and
execute additional stages, the first Gradle compilation frequently takes
longer than subsequent ones. To accurately assess the real compilation
times, we need to compile your project at least twice.
Here are some suggestions for customizing Gradle to improve compila-
tion performance:
• Don’t turn off the Gradle daemon unless we have a compelling cause
to. By default, Kotlin/Native is executed by the Gradle daemon.
When it is enabled, the same JVM process is utilized for all compila-
tions, and there is no need to warm it up.
• Enable previously disabled Kotlin/Native functionality. The Gradle
daemon and compiler caches can be disabled using the kotlin.
native.disable option. CompilerDaemon=true and kotlin.native.
cacheKind=none are set. Whether you had problems with these
features in the past and put these lines to your gradle.properties or
Gradle arguments, delete them and see if the build succeeds. It’s
conceivable that some characteristics were introduced in the past to
work around concerns that have since been resolved.
• Make use of the Gradle build caches:
• Local build cache: Add org.gradle.caching=true to your gradle.
properties file or use the command line option – build-cache.
• In continuous integration systems, remote build cache is used.
Discover how to set up the remote build cache.
Configuration of Windows
Operating System Set up Windows Security. The Kotlin/Native compiler
may slow by Windows Security. We may circumvent this by adding the
.konan directory, which is by default placed in %USERPROFILE%, to
Windows Security exclusions.
As we can see, there are a few notable differences between Java and Python:
• Null Safety
• Lambdas
• Extension Methods
}
272 ◾ Kotlin: The Ultimate Guide
actionBar.setTitle(R.string.about_heading)
}
val textViewWhyBookDash = findViewById(R.
id.text_why_bookdash) as TextView
textViewWhyBookDash.text = Html.
fromHtml(getString(R.string.why_bookdash))
Linkify.addLinks(textViewWhyBookDash, Linkify.
ALL)
......
}
override fun showLearnMorePage(url: String) {
val intent = Intent(Intent.ACTION_VIEW)
intent.setData(Uri.parse(url))
startActivity(intent)
}
}
• After that, we may begin adding code to that folder. Here’s an exam-
ple of my AboutActivityTest in Kotlin, which performs some basic
espresso testing.
@RunWith(AndroidJUnit4::class)
@SmallTest
274 ◾ Kotlin: The Ultimate Guide
class AboutActivityTest {
@Rule
fun getRule() = ActivityTestRule(AboutActivity
::class.java)
@Before
fun setUp() {
Intents.init()
}
@After
fun tearDown() {
Intents.release()
}
@Test
@Throws(Throwable::class)
fun loadAboutBookDash_SeeInformation() {
val about = Html.fromHtml(InstrumentationR
egistry.getTargetContext().getString(R.string.
why_bookdash))
val headingAbout =
InstrumentationRegistry.getTargetContext()
.getString(R.string.heading_about)
onView(withText(headingAbout))
.check(matches(isDisplayed()))
onView(withText(about.toString()))
.perform(scrollTo()).check(matches(isDisplayed()))
}
@Test
@Throws(Throwable::class)
fun clickLearnMore_OpenBrowser() {
onView(withText(R.string.learn_more)).
perform(scrollTo(), click())
intended(allOf(hasAction(Intent.
ACTION_VIEW),
hasData(Uri.parse("http://bookdash
.org"))))
}
}
Code Optimization Ideas ◾ 275
Accept Immutability
Immutability is not explicitly stated in Java. While the final operator
might be useful, it isn’t usually employed consistently. Given that immu-
table programming is generally easier and less error-prone, it’s a good idea
to get into the habit of keeping everything immutable and only resorting
to mutable objects when absolutely required.
Nothing in this example prevents the values inside someData and some-
Number from being changed; they are mutable variables. If later code uses
such values, there may be unforeseen effects. Long this is great for a single
developer working on a project, teams or even individuals who have been
away from a piece of code for a while might lose track of the usages of a
value and accidentally create a problem.
Instead, Kotlin makes it extremely simple to declare things immutable
from the start. In fact, if the value of a var variable isn’t being changed
elsewhere, IntelliJ Idea would often offer a quick-fix to convert it to val.
fun main() {
val someData = "Data"
var someMutableNumber = 63
someData = "some other data" // Compiler-error,
val cannot be reassigned
// This is ok since someMutableNumber was
specified as a mutable var.
someMutableNumber = 3
}
276 ◾ Kotlin: The Ultimate Guide
In general, the presence of var in code should raise a red warning. There
are situations when it is required; however, the vast majority of use cases
may be refactored to be immutable.
fun oldCollection() {
val myLists = ArrayList<Int>()
myLists.add(1)
myLists.add(2)
myLists.add(3)
val myMap = HashMap<Int, Int>()
myMap[0] = 0
}
fun newCollections() {
val myLists = listOf(1, 2, 3)
my mutableList = mutableListOf(4, 5)
myList.add(4) // Error: List<Int> doesn't have the
method add()
mutableList.add(4)
val myMap = mapOf(0 to 0, 1 to 1)
val mutableMap = mutableMapOf(2 to 2)
mutableMap[3] = 3
}
We will admit that this conceals some details that may be relevant for per-
formance on huge collections. We’ll probably want to employ more par-
ticular implementations in specialized instances. However, it’s probably
not critical enough to sacrifice code readability most of the time.
This method not only mutates the array that was handed in, but it also
has a low signal-to-noise ratio. The for syntax is clear, but it introduces
unnecessary noise that detracts from the “signal” in the method where the
value multiplication occurs. This is a great location for an operation such
as. map():
This example is considerably shorter, with much less “noise” code sur-
rounding the key multiplication part. The Another essential aspect to note
here is that the original array is not altered in any way, but rather a dupli-
cate of the array with the alterations is returned. Using different functional
techniques such as .map() can frequently eliminate the need to abstract
collection operations out to another method because using them in-line is
usually sufficient.
Bonus:
javaClass
This one, in particular, falls into the category of “here’s a neat sugges-
tion” rather than “best practice.” Some Java libraries, especially loggers,
require a reference to the current class. This is done rather simply in
Java:
LoggerFactory.getLogger(My_Class.getclass());
// Or
LoggerFactory.getLogger(this.getclass());
In Kotlin, :
LoggerFactory.getLogger(My_Class:class.java)
// Or
LoggerFactory.getLogger(this::class.java)
LoggerFactory.getLogger(javaClass)
String Interpolation
Concatenating strings is not just one of the core programming concepts
that individuals learn early on, but it is also employed in some way in prac-
tically every programming project. Many languages offer a few variants to
normal concatenation to aid in formatting or efficiency, but there is usu-
ally a cost in readability.
Concatenation is simple: take these string sections and put them together,
but this comes with a slew of extra symbols that can be difficult to remem-
ber. Finally, the most legible aspect of string concatenation is the overall
end string; thus the code should get as near as possible. To do this, Kotlin
offers string interpolation (also known as string templating), which makes
string composition considerably easier to read.
Infer Types
This is a nice feature in Kotlin, but it might be a bit tricky if you’re not used
to a language where types aren’t explicitly specified. The Kotlin compiler
is intelligent enough to infer the type of most things while retaining the
power of those types in reality (unlike JavaScript where the type system
is somewhat rudimentary). We won’t get into whether static or dynamic
typing is preferable, but it should go without saying that type checking
can assist eliminate issues, although at the expense of readability. As an
example:
This code isn’t doing anything particularly complicated, and the types
themselves make sense, but repeating GetFunctionConfigurationRequest
280 ◾ Kotlin: The Ultimate Guide
@Test
fun
handlerShouldSaveRecordToDbOnUpdatedEventProcessed()
{ ...... }
This is detailed and difficult to read. The rules of Kotlin allow for the nam-
ing of test methods in natural language style with spaces (or underscores).
Safe Operator?
One of the most notable aspects of Kotlin is its handling of compile-time
null safety. Kotlin includes a number of utilities to make dealing with
nullable types simple and clean by implementing its null system. The fol-
lowing is an example of traditional Java convention in Kotlin:
if (dbRow.person != null) {
if (dbRow.person.names != null) {
return dbRow.person.names
}
}
}
return null
}
Instead, Kotlin includes aids that are comparable to those found in other
languages that enable nullable types:
If the parent container is not null, the? access operator will continue to access
the field. If any of values in the chain are null, the entire line returns null.
Elvis Throws
Following the lead of safe calls, the Elvis Operator may convert a nullable
value to a non-null value. In the above example, getNameFromdb() returns
a nullable string and expects the caller to handle the scenario where a null
result is returned. We may assert that getNameFromDb() will always
return a non-null string or throw a more thorough error if the value can-
not retrieve using the Elvis operator.
Collection Helpers
Collections in Kotlin contain strong helper methods that may make
working with collections cleaner and more “Kotlin-y.” Looping is a com-
mon operation on collections, sometimes with a changeable accumulator
collection that saves the result.
These and other procedures are frequent, and they usually result in the
creation of some form of utility class or library so that they may reuse.
ProfilesWithPictures(), the latter of the instances, also necessitates the
usage of a changeable list, which deviates from immutability as a best prac-
tice. Kotlin’s standard library includes many utility methods on built-in
collections to save time and encourage immutable practices. These accept
Code Optimization Ideas ◾ 283
No more .equals()
As someone from a Python and C# background, the way Java handles
equality testing caused me a lot of agony and debugging. In those lan-
guages, the == operator determines value equality or invokes an equals
method on a complicated object. This means that == can be used to check
the equality of everything, from integers to strings to objects.
Because there are no operator overloads in Java, == determines refer-
ence equality (which I’ve never been inclined to check for). This means that
only primitives may be tested using ==, whereas complicated objects (such
as Strings) require the usage of .equals (). Consider sorting through code
that looks something like this:
Rather than depending on positional indexing, this may make what value
is going where on a constructor extremely apparent. While methods with
a high number of arguments are often considered an anti-pattern, named
parameters allow you to add more parameters as needed without sacrific-
ing readability.
This is a contrived example that probably lends itself to better design. Still, it
demonstrates how a method with that many arguments may become chal-
lenging to comprehend and debug if the parameter names aren’t helpful.
Code Optimization Ideas ◾ 285
We don’t have this problem with null handling in Kotlin since it incor-
porates the idea of null safety into its general design and implementation.
While null pointer exceptions can still arise in Kotlin, there are only a few
methods for this to happen.
One method is to invoke the NullPointerException() function in the
code directly. Another approach is to use them!! (not null) operators.
Finally, null pointers appear in Kotlin only when there is data discrepancy
during startup.
The Kotlin type system is designed to throw exceptions if a cast is
deemed unsafe, hence rendering the type un-nullable.
In Java, this is impossible. Unsafe casts are considered because they
provide an erroneous definition of the typed item, resulting in undefined
errors on static targets.
• first-class delegation
• type inference for variable and property types
• range expressions
• operator overloading
• singletons
• data classes
• companion objects
• separate interfaces for read-only and mutable collections
• coroutines
Application Patches
Application patches are likely to come in three flavors: hotfixes, patches,
and upgrades.
1. Hotfixes: These are often tiny bits of code intended to repair a spe-
cific problem. As an example, a hotfix may be provided to address a
buffer overflow within an application’s login procedure.
2. Patches: These are generally sets of fixes that are significantly bigger
in size and are generally provided regularly or when sufficient prob-
lems have been solved to allow a patch release.
3. Upgrades: These are another common technique of patching apps,
and they are more likely to be accepted than patches. The phrase
“upgrade” has a positive role. We’re progressing to a lot better, more
useful, and safer application.
IN THIS CHAPTER
III. Unzip the res folder. This folder holds all of our app’s resources,
including photos, layout files, strings, icons, and style. It con-
tains the following subfolders:
– Drawable: This folder will hold all of our app’s pictures.
– layout: The UI layout files for our activities are stored in
this folder. Our app currently has one activity with a lay-
out file called activity_main.xml. The content_main.xml,
fragment first.xml, and fragment_second.xml are also
included.
– menu: In this folder, we’ll find XML files that describe
any menus in our program.
– mipmap: This folder holds our app’s launcher icons.
– navigation: This folder includes the navigation graph,
which instructs Android Studio on how to move between
various portions of your application.
– values: Contains resources utilized in our app, such as
strings and colors.
<TextView
...
/>
<Button
...
/>
</androidx.constraintlayout.widget.
ConstraintLayout>
ii. When we click on the string in the text property, we’ll see that it
corresponds to a string resource called hellofirst_fragment.
android:text="@string/hellofirst_fragment"
vii. Examine the Attributes panel on the right, and, if necessary, open
the Declared Attributes section.
viii. Notice that the string resource @string/hellofirst_fragment is still
referred to in the text field of the TextView in Attributes. There
are various advantages to storing the strings in a resource file. We
may modify the value of string without changing any other code.
Because our translators don’t need to know anything about the
app code, this simplifies translating our app to different languages.
ix. To view the modification we made in strings.xml, restart the pro-
gram. “Hello Everyone” appears in our app now.
• Step 5: Modify the text display settings
i. With textview_first still selected in the Component Tree, expand
the textAppearance field in the layout editor’s list of attributes,
under Common Attributes.
ii. Modify the text’s appearance attributes. Change the font family,
raise the text size, and pick the bold style, for example. (We may
need to scroll across the panel to see all fields.)
Change the color of the text. Enter g in the textColor field by
clicking on it.
iii. A menu appears with possible completion values beginning with
the letter g. Predefined colors are included in this list.
iv. Press Enter after selecting @android:color/darker_gray.
v. Examine the TextView’s XML. The additional homes have been
added, as we can see.
<TextView
android:id="@+id/textview_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-condensed"
android:text="@string/hellofirst_fragment"
android:textColor="@android:color/darker_gray"
android:textSize="25sp"
android:textStyle="bold"
vi. Run the app again and see the changes applied to our Hello
Everyone.
Kotlin for Android Development ◾ 303
The editor opens the colors.xml file. Three colors have been
defined thus far. These are the colors we’ll see in our app’s design
(e.g., purple for the app bar).
ii. Return to fragment_first.xml to view the layout’s XML code.
iii. Add a new android:background property to the TextView and
begin typing to change its value to @color. This attribute may add
anywhere in the TextView code.
A menu appears, displaying the predefined color resources.
iv. Select @color/colorPrimaryDark.
v. Change the value of the android:textColor property to @
android:color/white.
304 ◾ Kotlin: The Ultimate Guide
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
ii. Take note that the text “Button” is directly in the layout field,
rather than referring to a string resource as the TextView does.
This will make translating our application into other languages
more difficult.
iii. To correct this, click the highlighted code. On the left, a light bulb
emerges.
Kotlin for Android Development ◾ 309
iv. Click the lightbulb. Select Extract string resource from the option
that appears.
v. In the resulting dialogue box, update the resource name to toast_
button_text and the resource value to Toast, then click OK.
vi. Notice how the android:text property’s value has changed to
@string/toast_button_text.
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/toast_button_text"
vii. Navigate to the file res > values > strings.xml. A new string
resource entitled toast button text has been added.
<resources>
.....
<string name="toast_button_text">Toast</string>
</resources>
xmlns:tools="http://schemas.android.com/
tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/screenBackground"
tools:context=".FirstFragment">
<TextView
android:id="@+id/textview_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/
colorPrimaryDark"
android:fontFamily="sans-serif-condensed"
android:text="@string/
hello_first_fragment"
android:textColor="@android:color/black"
android:textSize="34sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_
toTopOf="parent" />
<Button
android:id="@+id/random_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/
random_button_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_
toBottomOf="@+id/textview_first" />
<Button
android:id="@+id/toast_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
312 ◾ Kotlin: The Ultimate Guide
android:text="@string/toast_button_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_
toBottomOf="@+id/textview_first" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_
toStartOf="@+id/random_button"
app:layout_constraintStart_
toEndOf="@+id/toast_button"
app:layout_constraintTop_
toBottomOf="@+id/textview_first" />
</androidx.constraintlayout.widget.
ConstraintLayout>
Button Text id
Left-button Toast @+id/toast_button
Middle-button Count @+id/count_button
Right-button Random @+id/random_button
v. Run app.
Kotlin for Android Development ◾ 313
v. We can also use the Constraint Widget to set the vertical bias.
Click and drag number 50 that appears on the left side, then slide
it upward until it says 30.
Create ReviewManager
The ReviewManager interface allows our app to initiate an in-app review
flow. Create an instance of the ReviewManagerFactory to obtain it.
(e.g., when the user completes a level in a game). When our app reaches
one of these stages, create a request task using the ReviewManager object.
The API delivers the ReviewInfo object required to begin the in-app review
procedure if the request is successful.
HISTORY
The Kotlin language was initially introduced in 2011 by the business
JetBrains; if we’re unfamiliar with them, they were previously known as
the creators of the popular IntelliJ IDEA and are now equally well-known
as the inventors of the Kotlin language.
Although their initial release was in 2011, it wasn’t until 2016 that Kotlin
v1.0 was released, the first official release for which JetBrains would guar-
antee backward compatibility; the Kotlin release versioning method can
be seen here. Kotlin is presently at version 1.5, and the following timelines
compare Kotlin’s release cycle to JDK’s release cycle.
UNDERSTANDING
These may be executed on an open-source platform and are mostly
regarded as a Java substitute. It may combine with both Java and Javascript
programs and Java libraries. Kotlin has its libraries that may access via
the Application programming interface. The program in Java is redun-
dant and repeated in nature, resulting in long code, whereas Kotlin is more
simple and current, making it readily accessible by newcomers. It primar-
ily focuses on decreasing functional code while also removing repetitive
code. Kotlin protects null points by removing null point exceptions and
the semicolons (;) required in Java code but can be ignored. There is no
problem if the user uses it by default.
Android Development
Kotlin is the recommended language for Android development because it
allows developers to produce more concise, expressive, and secure code.
Android Studio, the official IDE for Android development, fully supports
it, so we can receive the same sort of code completion and type checking
to assist us to create Kotlin code as we can with Java.
Because more people now access the Internet via mobile phones, most
companies must have a mobile presence. Because Android accounts for
more than 70% of the mobile phone market, Kotlin developers would be in
great demand even if Kotlin was solely used for Android development. It
may, however, be used for much more.
Data Science
Data Scientists have long used Java to crunch information, discover pat-
terns, and make predictions, so it seems to reason that Kotlin will find a
home in the field as well.
Data Scientists can utilize all of the normal Java libraries used in Java
projects, but they must develop their code in Kotlin. Jupyter and Zeppelin,
two tools that many Data Scientists regularly utilize for data visualization
and exploratory study, support Kotlin.
(Continued)
Appraisal ◾ 325
Simple to Understand
Compared to more sophisticated programming languages, Kotlin’s gram-
mar is simple to grasp. As a newbie, we will rapidly learn and use it for
app development. Kotlin will help us improve our programming abilities
if we’re seasoned developers. It’s straightforward to know if we’ve worked
with Python or Java before.
Ample Resources
If we want to study Kotlin, there are several resources available online.
We will have no trouble finding resources to learn Kotlin whether we join
in a Bootcamp, sign up for an online course, or self-study through online
tutorials.
Community
When it comes to Kotlin, there is a sizable developer community. There
are Kotlin communities throughout the world, and these platforms allow
professionals of different skill levels to help one another. Furthermore, we
will have the opportunity to network with experienced programmers who
may give free mentorship.
Appraisal ◾ 327
Prospective Careers
Kotlin developers are in great demand. As Kotlin developers, we will have
a wide range of job options accessible to us. We will discover a suitable job
opportunity whether we seek work in mobile development, game develop-
ment, or web development. Furthermore, Kotlin developers may expect to
earn between $120,000 and $166,000 per year.
• Write Less Code: Every developer wants to write the least amount of
code feasible while still accomplishing the goal. Kotlin lets us write
the least amount of code possible, enhancing app speed.
• Adoption Ease: It is relatively simple to migrate the existing Android
app code to Kotlin.
• Supports Functional Programming: Kotlin supports functional
programming by allowing developers to simply and swiftly handle
tasks.
• Complete Java Compatibility: Developers may utilize all Java librar-
ies and frameworks when working in Kotlin.
• No Runtime Overhead: There is no runtime overhead since Kotlin
has a minimal library, and most of the hard lifting is done during
compilation.
• Multi-Platform Compatibility: Kotlin is compatible with Android
development and with JavaScript and Gradle.
• Less Error-Prone: Kotlin is less error-prone because the language
itself removes a few frequent coding errors; also, the developer’s error
risks are lowered when a developer needs to write less code.
manipulation and Pandas for data processing. Some people may employ
scikit-DecisionTreeClassifier. Learn’s If we want to build a decision tree
from scratch, Python is an excellent choice.
Like other programming languages, Python does not need us to iden-
tify a variable’s data type explicitly.
It also has many programs available via pip, so save our lives! However,
as the number of edge devices around us grows, we will likely have to build
ML algorithms for iOS, Android, and Rasberry Pi. Working with arrays
on Java might be a pain when it comes to Android. Then there’s Kotlin.
Android now has a new programming language. It includes simple array
manipulation techniques, making it powerful and developer-friendly. Its
syntax is also similar to Python’s. This section will learn about several fan-
tastic Kotlin functions that can help us in our ML adventure on Android.
In Java, we’ll most likely need to construct a for loop that iterates over
the files, converting them to Bitmap one by one.
Various ML methods rely on computing the minimum, maxi-
mum, and average of integers contained in an array. We can have the
argmax function, as well as the max and min functions in Python,
in Kotlin.
val p1 = floatArrayOf( 8f, 2f, 2.3f, 0.001f )
// Compute-mean
val mean = p1.average()
// Compute sum of all the elements
val sum = p1.sum()
// Compute-min/max
val max = p1.max()
330 ◾ Appraisal
prefer Kotlin over Java because it offers less coding risks. The lan-
guage enables developers to write less code while maintaining project
quality.
Kotlin developers are in great demand in the IT industry. Almost every
mobile app development business prefers to hire developers to create apps
in Kotlin for Android. These businesses strive to capitalize on every avail-
able opportunity. The need for Kotlin developers is really strong.
To become a Kotlin developer, we must have the following skills:
Nonetheless, Google has long desired to distance itself from the eco-
system. Java is a nearly ubiquitous programming language. But, whether
android developers detest it or avoid it, the need for Java persists in some
form or another. That is why they needed to discover something that com-
plements rather than replaces Java. A language that is more enjoyable to
use than Java and is compatible with it, Kotlin was born.
The features in the fourth through ninth positions on the list, on the other
hand, received a lot of support from the community. The six features at the
bottom of the list garnered much less votes. Some of them, such as Lateinit
Appraisal ◾ 335
for nullable and basic types and Overloadable bitwise operators like I and
&, ended up in the top three most disliked features.
Because there are other ways to implement the Multicatch and union
types functionality, we asked the Kotlin community to vote on which of
the two options they preferred:
Cross-Platform Libraries
Library writers can also benefit from Kotlin Multiplatform. We may build a
multiplatform library with shared code and platform-specific implementa-
tions for the JVM, JS, and Native platforms. Once released, a multiplatform
library can utilize as a dependency in other cross-platform applications.
IN THIS CHAPTER
BASICS
“Hello, Everyone” program
Declaring function
Single-expression function
Declaring variables
CONTROL STRUCTURES
If as an expression
For loop
When expression
CLASSES
Primary constructor
Inheritance
Data classes
5. copy that returns copy of object with the concrete properties changed
val drake = kiran.copy(name = "Drake")
COLLECTION LITERALS
listOf(1,5,2,4) // List
<Int> mutableListOf(1,5,2,4) // MutableList<Int>
List(4) { it * 2 } // List<Int>
generateSequence(4) { it + 2 } // Sequence<Int>
COLLECTION PROCESSING
students
.filter { it.passing && it.averageGrade > 5.0 }
// Only passing-students
Cheat Sheet ◾ 341
.sortedByDescending { it.averageGrade }
// Starting from ones with the biggest grades
.take(10) // Take-first 10
.sortedWith(compareBy({ it.surnames }, { it.names }))
// Sort by surnames and then names
generateSequence(0) { it + 1 }
// Infinitive sequence of the next numbers starting on 0
.filter { it % 2 == 0 } // Keep even only
.map { it * 3 } // Triple-every one
.take(100) // Take-first 100
.average() // Count-average
val l = listOf(11,22,33,44)
filter - returns only the elements matched by
predicate
l.filter { it % 2 == 0 }
map - returns elements after the transformation l.map
{ it * 2 }
flatMap - returns elements yielded from the results of
trans.
l.flatMap { listOf(it, it + 10) }
fold/reduce – accumulates-elements
l.fold(0.0) { acc, i -> acc + i }
l.reduce { acc, i -> acc * i }
forEach/onEach - performs an action on every element
l.forEach { print(it) }
l.onEach { print(it) }
Returns
Reference
to Receiver Receiver Result of Lambda
it also let
this apply run/with
FUNCTIONS
Function types
Function literals
val add: (Int, Int) -> Int = { x, y -> x + y }
// Simple lambda-expression
val printAndDouble: (Int) -> Int = {
println(it)
// When the single-parameter, we can reference it
using 'it'
it * 2 // In lambda, last expression is returned
}
Extension functions
DELEGATES
name = "Mehak"
// Prints: name changed Unset -> Mehak
VISIBILITY MODIFIERS
VARIANCE MODIFIERS
Interoperability of Java
Kotlin code is entirely interchangeable with Java code. Existing Java code
can readily call from Kotlin code, and Kotlin code may also call usually
from Java code.
}
public void setfirstNames(String firstNames) {
this.firstNames = firstNames;
}
public String getlastNames() {
return lastNames;
}
public void setlastNames(String lastNames) {
this.lastNames = lastNames;
}
}
myJava.lastNames = "Sharma"
myJava.setfirstNames("Karan")
println("accessing the value using property: "+myJava.
firstNames)
println("accessing the value using property: "+myJava.
lastNames)
println("accessing the value using method: "+myJava.
getfirstNames())
println("accessing the value using method: "+myJava.
getlastNames())
}
}
return result;
}
}
We must use the spread operator * to pass the array while accessing Java
varargs from Kotlin; we must use the spread operator *.
Let’s look at an example of a Java function that utilizes an int type vara-
rgs and is called from a Kotlin file.
Let’s look at another example that accepts two parameters in a Java func-
tion and utilizes them as String and int type varargs called from a Kotlin
code.
Before we get into how to call Kotlin code from Java code, let’s look at
how a Kotlin file looks inside.
Internally, the Kotlin compiler inserts a wrapper class with the name
My_KotlinKt. The Kotlin file My_Kotlin.kt gets transformed to My_
KotlinKt default and made public. The high-level function’s default
modifier is public, and the process is converted to static by default.
Because the return type of My_Kotlin.kt is Unit, it is changed to void in
My_KotlinKt.
Java Code Invokes the Kotlin File Included within the Package
If we want to call the Kotlin code from a Java class presents in distinct
packages, we must import the package name with the Kotlin file name
within the Java class and then call the Kotlin code from the Java class.
Another option is to provide the complete path as the package name.
KotlinFileKt.methodName().
package mykotlinpackage
fun main(args: Array<String>) {
}
fun area(l: Int,a: Int):Int{
return l*a
}
package myjavapackage;
import mykotlinpackage.MyKotlinFileKt;
public class My_JavaClass {
public static void main(String[] args){
int area = My_KotlinKt.area(4,5);
System.out.println("printing area inside the Java
class returning from Kotlin file: "+area);
}
}
@file: JvmName("My_Kotlin_FileName")
package mykotlinpackage
fun main(args: Array<String>) {
}
fun area(l: Int,a: Int):Int{
return l*a
}
package myjavapackage;
import mykotlinpackage.My_Kotlin_FileName;
public class My_JavaClass {
public static void main(String[] args){
int area = My_Kotlin_FileName.area(14,25);
System.out.println("printing area inside the Java
class returning from Kotlin file: "+area);
}
}
@file: JvmName("My_Kotlin_FileName")
@file:JvmMultifileClass
package mykotlinpackage
354 ◾ Cheat Sheet
@file: JvmName("MyKotlinFileName")
@file:JvmMultifileClass
package mykotlinpackage
fun volume(l: Int,b: Int,h: Int):Int{
return l*b*h
}
package myjavapackage;
import mykotlinpackage.My_Kotlin_FileName;
public class My_JavaClass {
public static void main(String[] args){
int area = My_Kotlin_FileName.area(14,25);
System.out.println("printing area inside the Java
class returning from Kotlin file: "+area);
int vol = My_Kotlin_FileName.volume(14,5,36);
System.out.println("printing volume inside the Java
class returning from Kotlin file: "+vol);
}
}
class D {
companion object {
constval VERSION = 8
}
}
Agrawal, S. (2020, October 26). The Nothing Type : Kotlin. Suneet Agrawal;
agrawalsuneet.github.io. https://agrawalsuneet.github.io/blogs/the-nothing-
type-kotlin/
Akhin, M., & Belyaev, M. (n.d.). Kotlin language specification. Kotlin Language
Specification; kotlinlang.org. Retrieved July 11, 2022, from https://kotlinlang
.org/spec/introduction.html
Baeldung. (2021, February 8). Kotlin-Java Interop. Kotlin Java Interoperability.
https://www.baeldung.com/kotlin/java-interoperability
Baeldung. (2022, May 31). Baeldung Kotlin. Extension Functions in Kotlin. https://
www.baeldung.com/kotlin/extension-methods
Balauag, T. (2019, May 17). Idiomatic Kotlin: Local functions | by Tompee Balauag |
Familiar Android | Medium. Medium; medium.com. https://medium.com/
tompee/idiomatic-kotlin-local-functions-4421f86ac864
Basic types | Kotlin. (2022, July 8). Kotlin Help; kotlinlang.org. https://kotlinlang.
org/docs/basic-types.html
Build Your First Android App in Kotlin | Android Developers. (n.d.). Android
Developers; developer.android.com. Retrieved July 11, 2022, from https://
developer.android.com/codelabs/build-your-first-android-app-kotlin#8
Collections overview | Kotlin. (2022, July 8). Kotlin Help; kotlinlang.org. https://
kotlinlang.org/docs/collections-overview.html#collection-types
Control Flow Statements in Kotlin. (n.d.). CherCherTech; chercher.tech. Retrieved
July 11, 2022, from https://chercher.tech/kotlin/control-flow-kotlin
Dehghani, A. (2021, October 25). Baeldung Kotlin. Operator Overloading in
Kotlin. https://www.baeldung.com/kotlin/operator-overloading
Destructuring Declarations in Kotlin | raywenderlich.com. (n.d.). Destructuring
Declarations in Kotlin | Raywenderlich.Com; www.raywenderlich.com.
Retrieved July 11, 2022, from https://www.raywenderlich.com/22178807-
destructuring-declarations-in-kotlin
Ebel, N. (2021, June 22). A complete guide to Kotlin lambda expressions –
LogRocket Blog. LogRocket Blog; blog.logrocket.com. https://blog.logrocket.
com/a-complete-guide-to-kotlin-lambda-expressions/
EPS Software Corp., Wei-Meng Lee, C. M. (n.d.). Introduction to Kotlin.
Introduction to Kotlin; www.codemag.com. Retrieved July 11, 2022, from
https://www.codemag.com/Article/1907061/Introduction-to-Kotlin
357
358 ◾ Bibliography
Soroker, T. (2020, December 6). Best Practices for Logging in Kotlin – Coralogix.
Coralogix; coralogix.com. https://coralogix.com/blog/best-practices-for-logging-
in-kotlin/
Technologies, M. (2021, April 22). Kotlin vs Python | What are the differences?
Mindmajix; mindmajix.com. https://mindmajix.com/kotlin-vs-python
Index
363
364 ◾ Index
unit-returning functions, 36 I
user-defined functions, 34–35
If-else expression in Kotlin, 39
if-else-if ladder expression, 42–44
G if-else statement, 40–41
as ternary operator, 42
Generics, 176
if statement, 39–40
contra covariance, 180
nested if expression, 44–45
covariance, 179–180
Immutability, accepting, 275–276
generic usage in program, 177–178
Immutable collection, 204–206
in keyword, 179
Importance of Kotlin, 320
out keyword, 178–179
In-app reviews, integrating, 316
star projections, 181
development environment, setting up,
type projections, 180–181
316
variance, 178
launching in-app review flow, 317
GetFunctionConfigurationRequest, 279
ReviewInfo object, requesting, 316–317
getNameFromdb(), 281
ReviewManager, creating, 316
GetOrNull() Function in Kotlin, 26–27
Increment and decrement operators,
Given block, 252–253
169–170
Google
IndexOf() function, 26, 217
choosing Kotlin as preferred language,
Infer types, 279–280
333
Infix functions, 263
seeking alternatives to Java
Inheritance in Kotlin, 131, 132, 261–262
programming language,
overriding member functions and
332–333
attributes, 137–138
primary constructor for, 135–136
H secondary constructor for, 136
superclass implementation, calling, 138
HashCode() function, 124–125 In keyword, 179
HashMap in Kotlin, 228, 276 Inline function in Kotlin, 38–39, 263–264
functions use, 229–232 Inner class, 100–102
time complexity, 232 Intellij IDEA, 9–10
HashSetOf() in Kotlin, 222 Interfaces in Kotlin, 116
empty map, 226–227 creation, 116
get map values, 227 default methods and default values,
hashSet traversal, 224 117–118
indexing in a hashSet, 224 implementing, 116–117
contains() and containsAll() inheritance, 119–120
functions, 224–225 multiple interfaces, implementation of,
map containing keys or values, 120–121
227–228 properties, 118–119
mapOf () in Kotlin, 225–226 Internal modifier, 114
map size, 226 !is operator, use of, 56, 82, 83
two values and same key, 228
“Hello, Everyone” program, 11, 337
J
Higher-order functions, 38, 188–192
returning a function from, 192–193 Java
History of Kotlin, 2, 319 existing Java files’ conversion to Kotlin,
Http4k, 8 272–273
368 ◾ Index