Home Programming Kotlin for Enterprise Applications using Java EE

Kotlin for Enterprise Applications using Java EE

By Raghavendra Rao K
books-svg-icon Book
eBook $39.99 $27.98
Print $48.99
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $39.99 $27.98
Print $48.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Kotlin – A First look
About this book
Kotlin was developed with a view to solving programmers’ difficulties and operational challenges. This book guides you in making Kotlin and Java EE work in unison to build enterprise-grade applications. Together, they can be used to create services of any size with just a few lines of code and let you focus on the business logic. Kotlin for Enterprise Applications using Java EE begins with a brief tour of Kotlin and helps you understand what makes it a popular and reasonable choice of programming language for application development, followed by its incorporation in the Java EE platform. We will then learn how to build applications using the Java Persistence API (JPA) and Enterprise JavaBeans (EJB), as well as develop RESTful web services and MicroServices. As we work our way through the chapters, we’ll use various performance improvement and monitoring tools for your application and see how they optimize real-world applications. At each step along the way, we will see how easy it is to develop enterprise applications in Kotlin. By the end of this book, we will have learned design patterns and how to implement them using Kotlin.
Publication date:
November 2018
Publisher
Packt
Pages
388
ISBN
9781788997270

 

Kotlin – A First look

Kotlin is a new language based on the Java Virtual Machine (JVM) that is fascinating the developer community with its concise, clear syntax, its lack of boilerplate code, and its full interoperability with the Java language.

The following topics will be covered in this chapter:

  • The features offered by Kotlin
  • Installing and running Kotlin
  • The various constructs of the language

 

Technical requirements

Knowing the basics of the Java language will help you to understand Kotlin and compare the two JVM-based languages. We will work with the command line to illustrate the language features that are highlighted in this chapter.

 

Introduction to Kotlin

Kotlin is a statically-typed programming language that runs on the JVM and works across different platforms. The fact that it is statically typed means the types are resolved during compilation. JVM is a specification that provides a runtime environment for running applications that are developed in Java and other JVM-based languages. The most well known reference implementation of JVM is OpenJDK, which was originally developed by Sun Microsystems and is now supervised by Oracle. Kotlin is another JVM-based language that is simple to write and concise in nature.

Kotlin combines object-oriented and functional programming features. Kotlin is designed to be interoperable with Java and relies on the Java code from the existing Java Class Library (JCL).

Kotlin provides a more expressive syntax than Java. It is concise and has strong type inference, which reduces code verbosity. It also has a wide variety of useful features, such as operator overloading, string templates, extended functions, and coroutines.

The history of Kotlin

Kotlin was developed by JetBrains in 2010. They initially released it under the name Project Kotlin in July 2011. They needed a language that was concise, elegant, expressive, and also interoperable with Java, as most of their products were developed in Java, including the Intellij Idea. They were looking for an alternate language to reduce the amount of boilerplate code required and to introduce new constructs, such as higher-order functions, to make language more expressive and concise. One of the goals of the Kotlin language was to be able to compile code as quickly as Java.

JetBrains open-sourced the project under the Apache 2 license in February 2012. Kotlin v1.0 was released on February 15, 2016. This was the first official stable release from JetBrains. Kotlin v1.2 was released on November 28, 2017. This release added a feature to allow code to be shared between JVM and JavaScript platforms.

Features of Kotlin

The key features of Kotlin are as follows:

  • Interoperability with Java: The most important feature of Kotlin is its deep interoperability with Java. Kotlin compiles to JVM bytecode and runs on the JVM, using Java libraries and tools.
  • Concise: Unlike Java, which is verbose, Kotlin reduces the amount of boilerplate code. This results in a leaner code syntax and improved readability.
  • Safe: Kotlin improves code safety through the proper initialization of properties, null safety, and strong type inference.
  • No runtime overhead: Kotlin imposes no runtime overhead. The standard Kotlin library is small. The Kotlin runtime exists only to support the language features. It has mostly focused on extensions to the Java standard library. Many of its internal functions are inline.
  • Collections: In Kotlin, we have higher-order functions, lambda expressions, operator overloading, lazy evaluation, and lots of other useful functions for working with collections.
  • Extension functions: Kotlin allows us to extend the functionality of existing classes without inheriting from them. Extensions do not modify classes; they extend them and are resolved statically.
  • Open source: Kotlin is an open-source programming language. The Kotlin project is open-sourced under the Apache 2.0 license. It is on GitHub and is open for community contribution.

Getting started with Kotlin

Before installing Kotlin, we need to have JDK installed, as Kotlin relies on JDK.

In this course, we will be using OpenJDK. OpenJDK can be downloaded from http://jdk.java.net/. Alternatively, we can use Oracle JDK, which can be downloaded from http://www.oracle.com/technetwork/java/javase/downloads/index.html.

After installing the JDK, set the PATH variable to include the JDK installed and we can check its version using the java --version command.

Once we have JDK installed, we need to set up Kotlin. We will look at how to install it in the following section.

Installing Kotlin

Installing Kotlin on Linux

To install Kotlin on Unix based systems such as Linux, Solaris, OS X etc., run the following commands in a terminal.

$ curl -s https://get.sdkman.io | bash

Then open a new terminal and execute below commands to install Kotlin:

$ sdk install kotlin

We can run the following command to see the version of Kotlin:

$ kotlin -version

To install Kotlin on Ubuntu, execute the following command from a terminal:

$ sudo snap install --classic kotlin

Installing Kotlin on Windows

To install Kotlin on Windows, perform the following steps:

  1. Extract and set the PATH variable to include the Kotlin runtime.
  2. Check its version using the kotlin -version command.
The source code for the Kotlin project can be found at the following link:
https://github.com/JetBrains/kotlin.

Installing Kotlin on Mac

To install Kotlin on a Mac system run the following command in a terminal:

$ sudo port install kotlin

Compiling and running

Now that we have JDK and the Kotlin compiler set up, let's try writing our first program in Kotlin and learn a few different ways to compile and run it.

Let's consider the HelloWorld.kt program, which just prints the hello message and the first argument passed to it:

fun main(args:Array<String>){
println("Hello${args[0]}")
}

There are different ways to compile and run Kotlin code:

  • Command line: By including the runtime, we don't have to provide the classpath; it gets bundled into it. To bundle the JAR, execute the following command in the command prompt/console:
kotlinc HelloWorld.kt -include-runtime -d HelloWorld.jar

We pass the class name and include the runtime and the name of the JAR as command-line arguments.

In order to run the program, execute the following command:

kotlin -classpath helloworld.jar HelloWorldKt World

Alternatively, we can use the following command:

java -classpath helloworld.jar HelloWorldKt World

The output is as follows:

We can also compile Kotlin code without the runtime. When we want to run it using Java or Kotlin, we have to specify where the class file,HelloWorldKt, is located:

kotlinc HelloWorld.kt -d classes
kotlin -classpath classes HelloWorldKt World

The output is as follows:

  • Read-eval-print-loop: Kotlin has an read-eval-print-loop (REPL) that we can use. Simply type kotlinc in the terminal and it will become an REPL. We can now run the Kotlin code interactively and experiment with it, as demonstrated in the following:

We can type :quit to exit the REPL.

  • Scripts: We can create a script file to compile and run a Kotlin program. Create a file called HelloWorld.kts. The s in the file extension stands for script. Then add the following print statement to it:
println("Hello World from Script")                 

HelloWorld.kts just has one print line statement. In the console, execute the following command:

kotlinc -script HelloWorld.kts   

This gives the output shown in the following screenshot:

This way, we can directly run the Kotlin file as a script.

In this section, we have learned the following:

  • How to install Kotlin
  • How to compile and create byte code and run it
  • How to code and play with REPLs directly
  • How to write Kotlin code as a script and run it
 

A quick tour of Kotlin

In this section, let's take a quick look at the world of Kotlin and understand the basics of the language.

Declaring variables

To declare a variable in Kotlin, we use either the val or var keywords.

Let's take a look at the following example:

val number = 10
println(number)

The preceding code prints the value that is assigned to a variable number, as can be seen in the following screenshot:

However, if we try to change the value assigned to the number, we will get a compilation error. Take a look at the following code:

val number = 10
println(number)
number = 11
println(number)

The output is as follows:

This is because val is immutable in Kotlin. This means that once a value is assigned, it cannot be modified. The keyword var, however, can be used to create a mutable variable.

Now consider the code for 3_valnVar.kts:

val number = 10
println(number)

var anotherNumber = 15
println(anotherNumber)

anotherNumber = 20
println(anotherNumber)

The output for the preceding code is as follows:

Let's examine what happens if we assign a string value to the preceding code:

val number = 10
println(number)

var anotherNumber = 15
println(anotherNumber)

anotherNumber = "20"
println(anotherNumber)

Compile this and see what happens:

In this case, the compiler throws an error saying that the type is mismatched. This is because the anotherNumber variable was inferred to be of type int and, as a result, we cannot assign a different type.

The type is inferred from the context and type safety is also guaranteed.

Both var and val are used to declare variables in Kotlin. val creates immutable variables, and var creates mutable variables. Variables declared using the val keyword cannot be changed once a value is assigned to them. This is similar to a final variable in Java. val is used to create constants. Variables declared using the var keyword can be changed later in the program. This corresponds to a regular Java variable.

Data types in Kotlin

The basic data types in Kotlin are numbers, characters, Boolean, arrays, and strings. These are described as follows:

  • Number: Kotlin provides the following built-in types that represent numbers, similar to Java:
Type Byte
Double 8
Float 4
Long 8
Int 4
Short 2
Byte 1
Unlike in Java, characters are not numbers in Kotlin.
    • Byte: Byte is a one-byte or 8-bit type for which values range from -128 to 127
    • Short: Short is a two-byte or 16-bit type for which values range from -32768 to 32767
    • Int: Int is a four-byte or 32-bit type for which values range from -2^31 to 2^31-1
    • Long: Long is an eight-byte or 64-bit type that can have values from -2^63 to 2^63-1
    • Double: Double is a double-precision, 8-byte, or 64-bit floating point
    • Float: Float is a single-precision, 4-byte or 32-bit floating point
    • Char: Char is used to represent a character in Kotlin, two-byte or 16-bit long, and is used to represent unicode characters

Char is a type used to represent characters. This is represented as follows:

val ch = 'a'
  • Boolean: Kotlin has a Boolean type to represent Booleans. It takes either true or false:
val isValid = true
val flag = false
If you are using IntelliJ IDEA, you can place your cursor inside the variable and press Ctrl + Shift + P to see its type.

Warnings

If we have created a variable and not used it, or if we forget to initialize a variable, we will get warnings, which can be useful to prevent errors. Kotlin provides many such warnings during compile time to avoid possible runtime errors. This increases program reliability.

Type inference

Kotlin is a statically-typed language. It executes the type inference for us, so we don't have to specify types. Consider the code for 3a_TypeInference.kts:

val message = "Hi there"
println(message)

When we run this code, we get the following output:

We can also explicitly specify the type. Consider the following code:

val message : String = "Hi there"
println(message)

This is an example of creating a variable of the String type and printing it in the console. This looks like Scala syntax and it is quite different from what we do in Java.

In Java, we would write this as follows:

String message = "Hi there";

Languages such as Kotlin emphasize that the name of a variable is more important than the nature of the variable. Kotlin puts the name of a variable or constant first and the type after in the var declaration syntax. The type is, in fact, optional; we don't have to specify it. We might think that this is the same as the dynamic type, where the type is resolved during runtime. Kotlin, however, actually infers the type at compile time.

Kotlin uses the String class from the JDK library. We can query the class that it uses as follows:

val message = "Hi there"
println(message.javaClass)

The output is as follows:

As a general rule, it's a good idea to specify type information when we write public-facing interfaces and, when using local variables, we can let the language infer the type.

String templates

Kotlin has support for templates for the String type. This is useful because it helps us to avoid concatenation in code.

Let's look at an example for 4_StringTemplate.kts:

val name = "Atrium"
println("Hello ${name}")

The output is as follows:

The curly brackets are optional here. println("Hello ${name}") can be written as println("Hello $name"), but it is good practice to use them to indicate the boundaries of the expression.

Let's look at 4a_StringTemplate.kts:

val name = "Atrium"
println("Hello $name")

The output is as follows:

Now consider the following code in Java:

myName= "tanbul"
System.out.println("my name is" + myName);

Here, we meant to print tanbul, but due to a formatting error, this code prints my name istanbul. We want to correct the code as follows:

myName= "tanbul"
System.out.println("my name is " + myName);

Kotlin's string template really helps to avoid any possible formatting errors from string concatenation. In Kotlin, we write the preceding code with clear syntax as follows:

myName= "tanbul"
println("my name is ${myName}")

This prints the following:

my name is tanbul

Multi-line String Literals

We can also define multiline string literals without having to use + + for concatenation. Let's create a multiline string in the example 4b_MultilineString.kts:

val name = "Atrium"
val message = """This is an example of
multiline String $name
"""
println(message)

The output is as follows:

Observe the indentation in the preceding example. If we don't want to use indentation, we can put | and use the trimMargin() function to trim the margin as follows:

val name = "Atrium"
val message = """This is an example of
|multiline String $name
"""
println(message.trimMargin())

The output is as follows:

One more thing that we can do is customize the character that we are going to use for margin separation and pass it to the trimMargin() function as follows:

val name = "Atrium"
val message = """This is an example of
^multiline String $name
"""
println(message.trimMargin("^"))

This gives the following output:

Expressions over statements

A statement is an element of a program that represents an action. An expression is a part of the statement that gets evaluated to a value. Statements introduce mutability. The more statements a program contains, the more mutability it will have. Mutability in code increases the chance that it is erroneous. Expressions, on the other hand, do not produce mutability. In purely functional constructs, there are no statements, there are only expressions. More expressions in a program mean less mutability and code that is more concise.

Consider the code for 5_Expressions.kts:

val number = 5
val evenOrOdd = if(number % 2 == 0) "is even number" else "is odd number"
println("$number $evenOrOdd")

The output is as follows:

In this case, the code has expressions and we are not mutating any state. We are simply assigning the result of an expression to a variable and printing it.

Similarly, try...catch is also an expression. try...catch is used for handling the exceptions. The last statement in the try block becomes the expression for the try block.

Functions

The fun keyword is used to define functions in Kotlin. In this section, we'll discuss writing a function, type inference, and specifying the return type.

In the following example, we create a function that takes two arguments of the String type and prints them to the console.

Consider the following code for 6_Function.kts:

fun welcome(name:String, msg:String) {
println("$msg $name")
}
welcome("Bob", "hello")

Note that we used string template to print the values without concatenating string literals.

The output of the preceding code as follows:

This is a simple example of creating a function and invoking it. Now, let's create a function that returns a value.

Consider the code for 6a_Function.kts:

fun welcome(name: String, msg:String) =
"$msg $name"
println(welcome("Bob", "hello"))

The output is as follows:

The = symbol says that Kotlin should infer the type from the context and identify the return type of the function. This is more suitable for single-line functions. For complex functions, we can specify the return type, in this case a String, and the return statement in the function, as shown here.

Consider the code for 6b_Function.kts:

fun welcome(name: String, msg:String) : String {
return "$msg $name"
}
println(welcome("Bob", "hello"))

The output is as follows:

We specified the String return type after the arguments prefixed by the colon (:) and the return statement in the function body.

Let's take a look at a function that doesn't return anything. We are interested in writing the void function.

Consider the code for 6c_Function.kts:

fun addNumbers(x: Int, y:Int) : Unit {
println("Sum of numbers is ${x+y}")
}
addNumbers(2, 3)

The output is as follows:

Unit is the representation of void in Kotlin. We can also write a void function without the Unit, as shown here.

Consider the code for 6d_Function:

fun addNumbers(x: Int, y:Int) {
println("Sum of numbers is ${x+y}")
}
addNumbers(2, 3)

The output is as follows:

Default arguments

Default values to the arguments is a nice way for an API to evolve. If we already have a function with two arguments and we need a third argument, we can make the transition easy by making use of default values to arguments. The existing code still works and, at the same time, we can invoke a function with new arguments. Default values to arguments make the API simple and expressive.

Let's write an example to provide a default value to an argument to the function.

Consider the code for 6e_DefaultArguments.kts:

fun welcome(name: String, msg:String = "Hey") {
println("$msg $name")
}
welcome("Bob", "hello")
welcome("Berry")

In this case, we are not providing the second argument, msg, to the welcome() function. It therefore uses a default message instead. The output is as follows:

As shown in the preceding example, a default value to an argument can be specified with an = symbol in the argument declaration. In this case, if we don't pass the second argument while invoking the function, a default value will be provided.

Named arguments

We can use a named argument to invoke a function and pass the arguments by naming them. Since the arguments are named, the order doesn't need to be maintained.

Let's take a look at the following example. Consider the code for 6f_NamedArguments.kts:

fun welcome(name: String, msg:String = "Hey") {
println("$msg $name")
}
welcome(msg = "How are you", name = "Mark")

The output is as follows:

We can also mix named arguments with arguments without a name. Consider the code for 6g_NamedArguments.kts:

fun welcome(name: String, msg:String = "Hey") {
println("$msg $name")
}
welcome("Joseph", msg = "Hi")

The output is as follows:

In this case, we invoked the function with one positional argument with the value Joseph and one argument named msg. When we are dealing with multiple arguments in a method, we can choose to send some arguments positionally by maintaining the order and to send others as named arguments. The language gives us the flexibility to invoke functions with type safety.

varargs and spread

Kotlin supports a variable number of arguments. vararg is the keyword that is used for a variable number of arguments. Using vararg, we can pass multiple arguments to a function.

Let's see an example of 7a_VarArgs.kts:

fun findMaxNumber(vararg numbers : Int) =
numbers.reduce { max , e -> if(max > e) max else e }

println(findMaxNumber(1,2,3,4))

The output is as follows:

The findMaxNumber() function takes a variable number of arguments and finds the maximum. We invoked reduce on the numbers and wrote a lambda expression. In Kotlin, a lambda is specified using curly braces.

If we have an array of numbers, we can invoke the findMaxNumber() function using the spread operator without changing the function argument type.

Consider the following code for 7b_Spread.kts:

fun findMaxNumber(vararg numbers : Int) =
numbers.reduce { max , e -> if(max > e) max else e }

val numberArray = intArrayOf(25,50,75,100)
println(findMaxNumber(*numberArray))

The output is as follows:

Note that * acts as a spread operator here. We can combine this with discrete values, as shown in the following 7c_Spread file.

Consider the code for 7c_Spread.kts:

fun findMaxNumber(vararg numbers : Int) =
numbers.reduce { max , e -> if(max > e) max else e }

val numberArray = intArrayOf(25,50,75,100)
println(findMaxNumber(4,5,*numberArray,200, 10))

The output is as follows:

The for loop

Let's write a for loop to print numbers. Consider the code for 8a_ForLoop.kts:

for(num in 1 .. 5){
println(num)
}

The output is as follows:

.. is used to specify the range, meaning the program prints numbers from 1 to 5 inclusively.

To exclude a range, the until keyword is used. Consider the code for 8b_ForLoop_Until.kts:

for(num in 1 until 5){
println(num)
}

The output is as follows:

If we want our numbers to be inclusive, we use (..). If we want to exclude the range, we use until.

If we want to traverse the range in a given step size, we can use step. Consider the code for 8c_ForLoop_Step.kts:

for(num in 1 .. 10 step 2){
println(num)
}

The output is as follows:

If we want to iterate in reverse order, we can use downTo.

Consider the code for 8d_ForLoop_downTo.kts:

for(num in 25 downTo 20){
println(num)
}

This gives us the following output:

If we want to iterate in reverse order in a given step size, we can use downTo and step.

Consider the code for 8e_ForLoop_downTo_Step.kts:

for(num in 25 downTo 15 step 2){
println(num)
}

The output is as follows:

.. works on a range in ascending order.

Now, consider the code for 8e1_ForLoop_downTo.kts:

for(num in 25 .. 20){
println(num)
}

The output is as follows:

This code compiles without any errors, but when you run it, there will be no output.

For downTo and step, the value has to be a positive number. If we give a negative number, such as -2, it will produce a compilation error.

Consider the code for 8e2_ForLoop_downTo_Step.kts:

for(num in 25 downTo 15 step -2){
println(num)
}

The output is as follows:

Iterating over a list

Collections are used for storing and processing a set of objects. Kotlin provides an elegant syntax for iteration over a collection.

Consider the code for 9_IteratingOverList.kts:

val names = listOf("Mark", "Tina", "Williams")
for(name in names) {
println(name)
}

The output is as follows:

If we are interested in getting the index value, we can do that by running the indices command on the collection.

Consider the code for 9a_IteratingOverListIndex.kts:

val names = listOf("Mark", "Tina", "Williams")
for(index in names.indices) {
println(index)
}

The output is as follows:

As the index is a String, we can write an expression to print it. Consider the code for 9b_IteratingOverListIndex.kts:

val names = listOf("Mark", "Tina", "Joseph")
for(index in names.indices) {
println("$index")
}

The output is as follows:

We can also add names to the expression to get items out of the collection, as in the following example, in which we are printing index and name. Consider the code for 9c_IteratingOverList.kts:

val names = listOf("Mark", "Tina", "Joseph")
for(index in names.indices) {
println("$index: ${names.get(index)}")
}

The output is as follows:

When clause

when is a pattern matching clause in Kotlin. This helps us to write elegant code when dealing with pattern matching, meaning we can avoid using a lot of if else statements.

Let's write a function that takes an input, the type of which is not known. Any is used to indicate this and a when block is used to handle different patterns.

Consider the code for 10_when.kts:

fun processInput(input: Any) {
when(input) {
10 -> println("It is 10")
98,99 -> println("It is 98 or 99")
in 101 .. 120 -> println("More than 100")
is String -> println("This is ${input} of length ${input.length}")
else -> println("Not known")
}
}
processInput(10)
processInput(98)
processInput(99)
processInput(102)
processInput("hey there")
processInput(Thread())

The output is as follows:

Alongside the pattern matching, we can also perform type checking using the when block:

is String -> println("This is ${input} of length ${input.length}")

Note that the argument input is of the Any type. After type checking, the input is automatically cast to String, and we can use the length property, which is defined in the String class. The Kotlin language does the auto-typecasting for us, so we don't have to do any explicit type casting.

The nullable type

In Kotlin, we can declare a variable to hold a null value using the nullable type.

Let's write a program to check whether the given input is Web. If it is, it should return Web Development. If not, it should return an empty string.

Consider the code for 11_NullType.kts:

fun checkInput (data: String) : String {
if(data == "Web")
return "Web development"
return ""
}
println(checkInput ("Web"))
println(checkInput ("Android"))

The output is as follows:

So far, so good. Let's say that we want to return null if there is no match for the given input:

fun checkInput (data: String) : String {
if(data == "Web")
return "Web development"
return null
}
println(checkInput ("Web"))
println(checkInput ("Android"))

Let's compile and run this code:

Here, we get a compilation error because the return type is non-null by default in the function declaration. If we want to return null, we have to specify the type as nullable using ?:

fun checkInput (data: String) : String? {
if(data == "Web")
return "Web development"
return null
}
println(checkInput ("Web"))
println(checkInput ("Android"))

The output is as follows:

This code has compiled and run successfully. When we invoke the checkInput function with Web, it prints Web development. When we pass Android, it prints null to the console.

Similarly, when we receive data in response, we can also receive a nullable type from the function and perform a null check. Kotlin provides a very elegant syntax to do null checks.

Consider the code for 11a_NullCheck.kts:

fun checkInput (data: String) : String? {
if(data == "Web")
return "Web development"
return null
}
var response = checkInput ("Web")
println(response)
response ?.let {
println("got non null value")
} ?: run {
println("got null")
}

The checkInput() function returns a string if there is a match for Web, otherwise it returns null. Once the function returns a value, we can check whether it is null or non-null and act appropriately. ?.let and ?:run are used for this kind of scenario.

The output is as follows:

Consider the code for 11a_NullCheck.kts:

fun checkInput (data: String) : String? {
if(data == "Web")
return "Web development"
return null
}
var response = checkInput ("iOS")
println(response)
response ?.let {
println("got non null value")
} ?: run {
println("got null")
}

We now pass iOS instead of Web.

In this case, the output is as follows:

 

Lambda expressions in Kotlin

Functional programming can be advantageous when we are performing lots of different operations on data that has a known, fixed amount of variation. It provides a very elegant way to write code with immutability. It also allows you to write pure functions.

A lambda expression is an anonymous function that represents the implementation of single abstract method (SAM) of an interface. Lambda expressions deal with expressions and promote immutability, which turn functions into higher-order functions.

Let's write a lambda expression. Consider the following code for 12_LambdaExpressions_HelloWorld.kts:

val greetingLambda = { println("Hello from Lambda")}
greetingLambda()

The output is as follows:

We can invoke lambda functions directly, as in the example shown in the preceding code, or we can use invoke() as follows—greetingLambda.invoke():

val greetingLambda = { println("Hello from Lambda")}
greetingLambda.invoke()

In the next example, we will write a lambda expression that takes an argument. Consider the following code for 12a_LambdaExpressions.kts:

val greetingLambda = { user: String -> println("Hello ${user}")}
greetingLambda.invoke("Tom")

The output is as follows:

We will now write an inline lambda function to print only even numbers. Consider the following code for 12b_LambdaExpressions.kts:

listOf(0,1,2,3,4,5,6,7,8,9)
.filter{ e -> e % 2 == 0}
.forEach{ e -> println(e)}

Here, we created a list of numbers from 0-9, and then we used filter to retrieve only the even numbers. Finally, we used forEach to iterate over the numbers and print the values to the console.

The output of the preceding code is as follows:

 

Extension functions

In Kotlin, we can easily add functionality to existing classes through its extension functions. The language provides the ability to add additional functions to classes without modifying the source code. In this section, we will look at how to extend the functionality of classes so that they provide the exact functionality that we are interested in. Kotlin supports extension functions and extension properties.

To create an extension function, we start with the fun keyword, and then we prefix the name of the extension function with the name of the class to be extended (known as the receiver type), followed by the dot operator (represented by the . character).

An example of this is receiverType.customFunctionName().

Consider the following code for 13_ExtensionFunctons.kts:

fun String.myExtendedFunction() = toUpperCase()

println("Kotlin".myExtendedFunction())

Here, myExtendedFunction() is an extension to the existing String class. We added myExtendedFunction() as an extension function and invoked it on a String literal.

The output for the preceding example is as follows:

This can be pictorially represented as follows:

  • Extension functions do not get added to the original classes. Instead, new functions are made callable by adding a dot on the receiverType variables.
  • Extension functions are resolved during compilation time. They are statically typed. This means that the extension function being invoked is determined by the receiverType of the expression on which the function is invoked, not by the nature of the result of evaluating the expression at runtime.
  • The extension functions cannot be overloaded.
 

Classes in Kotlin

Classes in Kotlin are created using the class keyword, which is depicted as follows:

class User {

}

The structure of the class is as follows:

Class className {
//properties and constructor
//member functions
}

Let's write a class for User.

Consider the following code for 14_Class.kts:

class User {
var name = "George"
}

val user = User()
println(user.name)

The output is as follows:

This class has a property called name. Classes are instantiated with just the class name, followed by parentheses. Note that there is no new keyword in Kotlin to create an object, unlike in Java.

Classes in Kotlin are final by default. We cannot extend from a class directly. To inherit from the classes, we have to open the classes explicitly. Classes need to have an open keyword in their declaration, as shown in the following code:

open class Person {

}

Alternatively, we can use all-open compiler plugins to make all the classes extendable or accessible to frameworks such as JPA and Spring. We will discuss compiler plugins further in the next chapter.

Constructors

Constructors are used to initialize class properties. As in Java, a constructor is a special member function that is invoked when an object is instantiated. However, they work slightly different in Kotlin.

In Kotlin, there are two constructors:

  • Primary constructor: This is a concise way to initialize the properties of a class
  • Secondary constructor: This is where additional initialization logic goes

The primary constructor is part of the class header. Here's an example:

class User() {

}

The block of code surrounded by parentheses is the primary constructor. Consider the following code for 14a_PrimaryConstructor.kts:

class User(var firstName: String, var lastName: String) {

}

val user = User("Norman", "Lewis")
println("First Name= ${user.firstName}")
println("Last Name= ${user.lastName}")

The output is as follows:

The constructor goes here as part of the class header. The constructor declares two properties—firstName and lastName. Let's look at another example for 14b_PrimaryConstructor.kts:

class User(var firstName: String, val id: String) {

}
val user = User("Norman", "myId")
println("First Name = ${user.firstName}")
println("User Id = ${user.id}")

The output of the preceding code is as follows:

For the primary constructor, properties have to be declared using var or val. Otherwise, the code fails to compile.

The secondary constructor is created using the constructor keyword. The class can declare a secondary constructor to initialize its properties. This is shown in the following code:

class AuditData {
constructor(message: String) {
//init logic
}
constructor(message: String, locale: String) {
// init logic
}
}

In the preceding code snippet, we wrote two constructors. One had a message as an argument and one had two arguments—message and locale. Consider the following code for 14c_SecondaryConstructor.kts:

var audit = AuditData("record added")
println("Message ${audit.message}")

audit = AuditData("record updated", "en-US")
println("Message: ${audit.message}")
println("Locale: ${audit.locale}")

When we call AuditData with only a message, the constructor with one argument will be invoked. Similarly, when we pass two arguments, a message and a locale, the constructor with two arguments will be invoked.

The output is as follows:

Static functions

Static functions are functions that can be invoked without creating multiple instances of a class. Static functions avoid code duplication and can be reused.

Let's take a look at how to write a static function in Kotlin.

Consider the following code for 15a_StaticMethods.kts:

object MyUtil {
fun foo(){
println("Static function foo() is invoked")
}
}

MyUtil.foo()

Note that we declared an object MyUtil and defined a function foo(). This is known as object declaration.

We invoked the function foo() directly using the object MyUtil.

The output of the preceding code is as follows:

There are different ways to write static functions in Kotlin. We can define a companion object inside a class and define a static function in it. Consider the following code for 15b_StaticMethods.kts:

class Person {
companion object {
fun foo(){
println("Static function foo() is invoked")
}
}
}
Person.foo()

The output is as follows:

We can also give a name to the companion object. Consider the following code for 15c_StaticMethods.kts:

class Person {
companion object Util {
fun foo(){
println("Static function foo() is invoked")
}
}
}
Person.Util.foo()

The output is as follows:

We can invoke the static method shown in the preceding example with companion as Person.Companion.foo(). The static method foo can be invoked using either the class name or a named companion object prefixed with the class name, such as Person.Util.foo().

In this section, we have covered the constructs that Kotlin provides. We will be using these constructs in the next few chapters.

 

Kotlin programming style and Syntax

Let's now discuss some of Kotlin's syntactic rules and coding guidelines:

  • Class name: As in Java, class names begin with an uppercase letter. We can create it with a lowercase letter, but it is recommended that we use an uppercase letter, as per the Java coding convention. This is to keep the convention the same when dealing with both Java and Kotlin files.
  • Packages: Specify the package at the top of the class. Packages are written in lowercase letters separated by a dot(.):
package org.rao.kotlin.intro

Note that the semicolon is optional in package declarations in Kotlin.

  • Imports: The imports should be after the declaration in the class file. If there is no package statement, the import statement should be the first statement. An example of an import statement is as follows:
import java.util.List

  • Variables: In Kotlin, var and val are used to declare variables. Use camelCase when declaring variables and provide meaningful names for them. Some examples are shown in the following table:

Examples

Explanation

val number = 10

Here, the type Int is inferred. We can use this syntax in local contexts in code.

val number: Int = 10

Here, the type Int is declared explicitly and a value is assigned.

val number: Int

Here, a variable is declared but not initialized. Declaring the type is required in this case.

var userName = "Bob"

Here, we used var to create a mutable variable, which is initialized. Because of this, the type is optional and is inferred from the context. In this case, the type inferred is String.

  • Comments: Kotlin has support for single-line and multiline comments:
// This is single line comment
/* This is a multi-line
comment. */

Unlike Java, Kotlin also supports nested comments:

/*
Top level comment section
/*
Nested comments section
*/
*/
  • Operators: Use the in operator to check whether a number is in a specified range or in loops for iteration:
if(number in 1..5)

for(number in 1..5)

Similarly, use the is operator to check the type. When we use the is operator, explicit type casting is not required:

fun processInput(input: Any) {
if(object is String) {
var data: String = object
}
}

Note the automatic type conversion that is applied when using the is operator in this context. Outside this context, the type will be Any. This is a super type in Kotlin, like Object in Java.

Kotlin provides an easy and flexible syntax compared to Java. This helps us write concise and more expressive code that is easy to maintain.

 

Summary

In this chapter, we have discussed the following:

  • A brief introduction to the Kotlin language
  • A quick tour of the language, with various examples enabling us to familiarize ourselves with the Kotlin world
  • A brief look at Kotlin syntax
About the Author
  • Raghavendra Rao K

    Raghavendra Rao K is a senior programmer who's skilled in Java, Kotlin, Groovy, Scala, Java EE, Spring Framework, Cloud Foundry, and Docker. He's a strong engineering professional with a bachelor of engineering degree focused on computer science and engineering. He's a co-organizer of Java User Group (BoJUG) in Bangalore. He's enthusiastic about code quality and loves refactoring.

    Browse publications by this author
Latest Reviews (1 reviews total)
Good written book. Learn new things from the book.
Kotlin for Enterprise Applications using Java EE
Unlock this book and the full library FREE for 7 days
Start now