🔙 Quay lại trang tải sách pdf ebook Mastering Kotlin
Ebooks
Nhóm Zalo
Mastering Kotlin
Learn advanced Kotlin programming techniques to build apps for Android, iOS, and the web Nate Ebel
BIRMINGHAM - MUMBAI
Mastering Kotlin
Copyright © 2019 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Richa Tripathi
Acquisition Editor: Karan Gupta
Content Development Editor: Tiksha Sarang
Senior Editor: Rohit Singh
Technical Editor: Romy Dias
Copy Editor: Safis Editing
Project Coordinator: Prajakta Naik
Proofreader: Safis Editing
Indexer: Priyanka Dhadke
Production Designer: Nilesh Mohite
First published: October 2019
Production reference: 1111019
Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham
B3 2PB, UK.
ISBN 978-1-83855-572-6
www.packtpub.com
To my wife, for being a constant source of support and encouragement, and for being understanding during all the late nights and early mornings; I couldn't have finished this book without you. To my parents, for always believing in me and teaching me to do the same, and for raising me to dream big; I wouldn't be here without you. To the educators, mentors, and friends over the years: Steve, Steve, Shawn, and Scott—the kindness, encouragement, knowledge, and support you've given me will never be forgotten.
Packt.com
Subscribe to our online digital library for full access to over 7,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Why subscribe?
Spend less time learning and more time coding with practical eBooks and videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Fully searchable for easy access to vital information
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and, as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Contributors
About the author
Nate Ebel is a software developer who enjoys building great software and helping others do the same. He has worked with Android since its early days, across a variety of projects, from creative and educational apps, mapping and navigation applications, to the evolution of robotic controllers.
Nate has a passion for technology, education, and software development, and enjoys opportunities to combine the three. He enjoys being involved in the Android developer community and is an active contributor through conference speaking, blogging, and event organizing.
He is working to help himself and others dream, learn, and create in an effort to positively impact others.
About the reviewer
Ashok Kumar Srinivas is a Google-certified Android developer from Bengaluru, India. He is an expert in the web and mobile engineering domains. He has authored books on Android Wear and Firebase, and has reviewed books on subjects including web and mobile applications. He is one of the top open source contributors. He is a passionate YouTuber and runs a channel called AndroidABCD. He is also a speaker at international conferences. He has a keen interest in the quality, architecture, and unit testing of the code. When he can find the time, he writes and reviews books. He also likes to travel inside India and further afield.
I would like to thank T. Subhash Chandra, my teacher in college and life. He has been an incredible support for a diverse range of students, and I am proud to say that I am one such student. I would also like to thank my wife, Geetha Shree Ashok, for supporting me in every way during my work on this book. I would also like to thank my sister, Shylaja Shripathi, my father, Srinivas, my mother, Lalitha, and my entire family.
Packt is searching for authors like you
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Table of Contents
Title Page
Copyright and Credits
Mastering Kotlin
Dedication
About Packt
Why subscribe?
Contributors
About the author
About the reviewer
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Code in Action
Conventions used
Get in touch
Reviews
1. Section 1: Kotlin – A Modern Solution to Application Development 1. A New Challenger Approaches
Technical requirements
Creating a modern language for the JVM
What is Kotlin?
Kotlin is flexible
Kotlin is expressive and concise
Kotlin is powerful
Hello Kotlin
Who created Kotlin?
Announcing Kotlin
Motivations for Kotlin
Community involvement
Moving beyond the JVM
Kotlin for Android
Kotlin for the web
Server-side Kotlin
Kotlin to JavaScript
Native and multiplatform Kotlin
Designing Kotlin with best practices in mind
Learning from Java
Best practice by design
Checking in on the current state of Kotlin
Developing Kotlin in the open
Increasing popularity for Kotlin
Learning Kotlin
Summary
Questions
Further reading
2. Programmers' Multi-Tool – Flexible, Expressive, and Concise
Technical requirements
Picking your programming paradigm
Object-Oriented Programming
Functional programming
Reactive programming
Embracing first-class functions
Function types
Top-level functions
Extension functions
Higher-order functions
Standard library
Fixing the billion-dollar mistake
Defining null and non-null types
Working with null
Null-safe calls
Non-null assertion
Conditional checks
The Elvis operator
Integrating with Java
Using Java from Kotlin
Creating and working with Java classes from Kotlin
Calling static Java methods from Kotlin
Using Kotlin from Java
Creating and working with Kotlin classes from Java
Calling Kotlin functions from Java
Expanding on the interop story
Summary
Questions
Further reading
2. Section 2: Putting the Pieces Together – Modeling Data, Managing State, and Application Architecture 3. Understanding Programming Paradigms in Kotlin
Technical requirements
Classifying programming languages
Multi-paradigm languages
Imperative programming languages
Objected-oriented programming languages
Declarative programming languages
Domain Specific Languages
Other programming paradigms
Event-driven programming
Generic programming
Understanding object-oriented programming
Key concepts
Encapsulation
Inheritance
Polymorphism
Object-oriented programming with Kotlin
Functional programming
Key concepts
First-class functions
Pure functions
Functional programming with Kotlin
More to learn
Reactive programming
RxJava
Key concepts in RxJava
Observables
Operators
Threading
RxKotlin
Reactive coroutines
Channels and flow
Summary
Questions
Further reading
4. First-Class Functions
Technical requirements
Hello functions – first-class support for functions
Writing a basic function
First-class functions
Functions as variables
Read-only function variables
Mutable function variables
Function properties
Functions as arguments
Functions as return values
Top-level functions
Flexibility by design – reducing boilerplate with effective parameters Adding function parameters
Multiple function parameters
The vararg modifier
Limitations of vararg
Named parameters
Default parameter values
A function for every job – understanding function variations
Top-level functions
Class functions
Local functions
Single expression functions
Infix functions
Extension functions
Summary
Questions
Further reading
5. Modeling Real-World Data
Technical requirements
Object-oriented programming in Kotlin
Defining a class
Adding properties
Property basics
Working with properties
Custom accessors
Primary constructor properties
Initialization
Primary constructor initialization
Property assignments and initializer blocks
Adding methods
Customizing construction
Primary constructors
Secondary constructors
Private constructors
Controlling visibility
The public modifier
The internal modifier
The protected modifier
The private modifier
Organizing your code
Files and classes
Packages
Modules
Achieving inheritance and composition
Interfaces
Defining a simple interface
Defining an interface property
Interface inheritance
Implementing multiple interfaces
Default methods
Subclasses and abstract classes
Nested classes
Delegation
Implementation delegation
Type checking
Any
Type casting
Smart casting
Understanding data classes
Creating a data class
Generated code
equals()
hashCode()
toString()
copy()
Destructuring
Working with enums, sealed classes, and objects
Enums
Sealed classes
Object classes
Singletons
Companion objects
Object expressions
Summary
Questions
Further reading
3. Section 3: Play Nice – Integrating Kotlin With Existing Code 6. Interoperability as a Design Goal
Technical requirements
Understanding why Kotlin was designed with interop in mind
Why is interop so important for Kotlin?
How is interop achieved?
Adding Kotlin to an existing Java project
Adding Kotlin to an existing IntelliJ project
Converting Java into Kotlin
Converting Java files into Kotlin files
Converting pasted Java code
Summary
Questions
7. Crossing Over – Working across Java and Kotlin
Technical requirements
Working with Kotlin from Java
Basic interop
Creating class instances across languages
Inheritance across languages
Property access
Handling null
Function arguments
Lack of static
Working with Java from Kotlin
Using existing code
Enforcing null safety
Embracing Kotlin idioms
Goodbye helpers – embracing top-level and extension functions and properties Top-level functions
Extension functions
Top-level properties
Top-level constant properties
Top-level mutable properties
Companion objects
Are two languages better than one?
Project structure
Increased build size and speed
Annotation processing
Performance
Complexity
Summary
Questions
Further reading
8. Controlling the Story
Technical requirements
Improving generated class names
How are class names generated?
Renaming the generated class
Renaming a generated class name for top-level functions
Renaming a generated class name for top-level properties
Leveraging default values in Java
Better companions
How do companion objects work?
When should we use a companion object?
Modifying companion object names
Bringing static to Kotlin
Where can we use JvmStatic?
@JvmStatic properties
@JvmStatic methods
When should we use the @JvmStatic annotation?
Use-site annotation targets
What are use-site targets?
Specifying a use-site target
Default targets
Summary
Questions
Further reading
9. Baby Steps – Integration through Testing
Technical requirements
Test-first integration
Feature integration
Advantages
Disadvantages
Test integration
Advantages
Disadvantages
General impact of integration
Testing interop
Exercising your Kotlin code
Testing closed classes
Using Mockito
Using the compiler plugin
Exercising Java code from Kotlin
Exercising Kotlin code from Java
Improved testing with Kotlin
The kotlin.test library
Annotations
Helper functions
Mockito-Kotlin
Summary
Questions
Further reading
4. Section 4: Go Beyond – Exploring Advanced and Experimental Language Features 10. Practical Concurrency
Technical requirements
Understanding async patterns
Threading primitives
Thread
ExecutorService
Advanced threading
CompletableFuture
RxJava
Coroutines
The foundations of coroutines
What are coroutines?
Coroutines with Kotlin
Coroutines in practice
Coroutine primitives
Coroutine scopes
Coroutine builders
Suspending functions
Working with blocking code
Fetching data
Summary
Questions
Further reading
11. Building Your Own Tools – Domain-Specific Languages (DSLs)
Technical requirements
What is a DSL?
Domain-specific languages
Where are DSLs used?
HTML
Testing
Dependency injection
The building blocks of a DSL in Kotlin
Top-level and extension functions
Top-level functions
Extension functions
Function types with receivers
Scope control
Creating your first Kotlin DSL
What problem are you trying to solve?
Creating your starting point
Adding elements
Adding sodas
Adding pizzas
Making it easy to use
Summary
Questions
Further reading
12. Fully Functional – Embracing Functional Programming
Technical requirements
Understanding functional programming
Pure functions
Immutability
Limited side effects
Reduced complexity
Understanding advanced functions
Working with functional types
Functional variables
Functional arguments
Improving the performance of higher-order functions
The inline modifier
The noinline modifier
Leveraging the standard library
Manipulating collections
Filtering
Mapping
Associating
Searching
Exploring other useful functions
Functional programming with Arrow
What is Arrow?
Typeclasses
Data types
Effects
Summary
Questions
Further reading
5. Section 5: The Wide World of Kotlin – Using Kotlin across the Entire Development Stack 13. Kotlin on Android
Technical requirements
First class Kotlin for Android
Adopting Kotlin for Android
Kotlin first
The future of Android
Hello Android Kotlin
Creating an Android app with Kotlin support
Taking advantage of Kotlin on Android
Configuring a view reference
Responding to click events
Creating factory methods for activities and fragments
Handling savedInstanceState
Building with Kotlin
The Gradle Kotlin DSL
Migrating to the Kotlin buildscript
Simplifying dependency management with Kotlin
First-party tooling
Exploring Android KTX
Adding Core KTX to your project
Using Core KTX
Using Fragment KTX
Using Kotlin Android Extensions
Binding views with Kotlin Android Extensions
Generating Parcelable implementations
Summary
Questions
Further reading
14. Kotlin and Web Development
Technical requirements
Kotlin for the web
Compiling Kotlin to JavaScript
Transpiling to JavaScript
Targeting JavaScript
Using the compiled JavaScript
Targeting JavaScript with Kotlin
Building a Hello Kotlin project
Creating a Kotlin project with a JavaScript target
Writing Hello World for Kotlin JavaScript
Examining the compiled JavaScript
Consuming Kotlin through compiled JavaScript
Integrating with existing JavaScript
Working with other JavaScript frameworks
Manipulating the DOM via Kotlin
Summary
Questions
Further reading
15. Introducing Multiplatform Kotlin
Technical requirements
Introducing Kotlin multiplatform
Understanding how Kotlin approaches multiplatform
Understanding the value of Kotlin multiplatform
Targeting multiple platforms
Differentiating Kotlin multiplatform
Sharing logic, not UI
Limiting risk
Creating your first Kotlin multiplatform project
Creating a shared module
Adding an Android app
Adding an iOS app
Adding a web page
Building a Kotlin multiplatform project
Writing multiplatform Kotlin
Leveraging multiplatform libraries
Understanding the limitations of Kotlin multiplatform
Understanding operational requirements
Understanding Kotlin multiplatform ecosystem limitations Understanding framework and tooling limitations
Summary
Questions
Further reading
16. Taming the Monolith with Microservices
Technical requirements
Understanding microservices
Exploring the limits of the monolith
Embracing microservices
Writing microservices with Kotlin
Understanding Kotlin's relation to microservices
Choosing Kotlin for your microservices
Deploying your first Kotlin microservice
Creating a Ktor project
Writing a simple microservice
Adding a route
Deploying our microservice
Deploying Kotlin services in production
Deploying local Ktor services
Scaling our routes
Defining routes with extension functions
Installing additional routes
Summary
Questions
Further reading
17. Practical Design Patterns
Technical requirements
Understanding design patterns
Revisiting the Singleton pattern in Kotlin
Understanding the Singleton pattern
Implementing the Singleton pattern in Kotlin
Revisiting the Factory pattern in Kotlin
Understanding the Factory pattern
Implementing the Factory pattern in Kotlin
Revisiting the Builder pattern in Kotlin
Understanding the Builder pattern
Implementing the Builder pattern in Kotlin
Revisiting the Strategy pattern in Kotlin
Understanding the Strategy pattern
Implementing the Strategy pattern in Kotlin
Summary
Questions
Further reading
Assessments
Chapter 1: A New Challenger Approaches
Chapter 2: Programmer's Multi-Tool
Chapter 3: Understanding Programming Paradigms in Kotlin
Chapter 4: First-Class Functions
Chapter 5: Modeling Real-World Data
Chapter 6: Interoperability by Design
Chapter 7: Crossing Over – Working across Java and Kotlin
Chapter 8: Controlling the Story
Chapter 9: Baby Steps – Integration through Testing
Chapter 10: Practical Concurrency
Chapter 11: Building Your Own Tools – Domain-Specific Languages (DSLs) Chapter 12: Fully Functional – Embracing Functional Programming Chapter 13: Kotlin on Android
Chapter 14: Kotlin and Web Development
Chapter 15: Introducing Multiplatform Kotlin
Chapter 16: Taming the Monolith with Microservices
Chapter 17: Practical Design Patterns
Other Books You May Enjoy
Leave a review - let other readers know what you think
Preface
This book is written for software developers looking to expand their experience and understanding of the Kotlin programming language. It aims to bridge the gap between simple, practical examples and advanced language topics.
This book is designed to not only demonstrate how to write code in Kotlin, but to help you to understand the history of Kotlin and some of the motivations behind the language itself. Additionally, the book will demonstrate how features of the Kotlin language work behind the scenes. The goal is to help you to more fully understand Kotlin as a whole, rather than just as a language syntax.
Once a strong introduction to Kotlin and its features has been covered, the book will spend several chapters exploring a variety of more advanced topics, including how to build with Kotlin on a variety of platforms. These chapters aim to act as a quick-start guide for understanding what is possible with Kotlin and where and how you can apply the Kotlin language skills that you have learned for the development of real-world applications.
Who this book is for
This book is aimed at beginner and intermediate Kotlin developers who are looking to improve their understanding of the language, as well as experienced Java developers looking for simple, practical examples of how to solve familiar problems using Kotlin. You should be familiar with object-oriented programming and have some familiarity with Java.
What this book covers
Chapter 1, A New Challenger Approaches, provides context for what Kotlin is, how it came about, and why it is gaining popularity. It provides a high-level overview of where the book is headed and lays the foundation for the following chapters' focus on language features, patterns, best practices, and the ability to target multiple domains and platforms.
Chapter 2, Programmers' Multi-Tool – Flexible, Expressive, and Concise, dives into the basic details of the Kotlin language. It highlights some of the most popular language features, such as first-class functions, non-null types, and multiple programming paradigms. For each of these features, you will begin to understand how to take advantage of the feature, and what impact it can have on the overall application architecture.
Chapter 3, Understanding Programming Paradigms in Kotlin, provides an overview of different programming paradigms that Kotlin supports, including imperative, functional, and reactive programming. The chapter describes these paradigms, and details how Kotlin supports, but does not enforce, all three.
Chapter 4, First-Class Functions, introduces you to Kotlin's support for first-class functions. It describes, in detail, how Kotlin functions are flexible, concise, and powerful. You will learn how to leverage Kotlin features such as default parameter values, infix functions, extension functions, and higher-order functions.
Chapter 5, Modeling Real-World Data, exposes you to the fundamentals of inheritance and composition in Kotlin. This chapter details the differences between enums, data classes, sealed classes, and type classes, and aims to illustrate when and why you should choose one over another.
Chapter 6, Interoperability as a Design Goal, provides background into the design goals behind interoperability in Kotlin, why interoperability is so important to Kotlin, and teaches you how to quickly add Kotlin to an existing project.
Chapter 7, Crossing Over – Working across Java and Kotlin, explores the practical ramifications of adding Kotlin to an existing Java code base. It details how to work with both the language within the same project, and about some of the challenges associated with adding a second language to a project.
Chapter 8, Controlling the Story, details how Kotlin code can be modified to provide a better interoperability experience with Java. It highlights how to apply annotations, and how to design Kotlin APIs to make working with Kotlin from Java more idiomatic and enjoyable.
Chapter 9, Baby Steps – Integration through Testing, explores how to integrate Kotlin into an existing project through testing, and demonstrates how the testing experience can be improved using Kotlin and Kotlin-specific features such as DSLs.
Chapter 10, Practical Concurrency, introduces you to advanced threading concepts. It does so by starting from basic threads and working up to Kotlin coroutines as an idiomatic solution for writing asynchronous, non-blocking code.
Chapter 11, Building Your Own Tools – Domain-Specific Languages (DSLs), introduces the concept of custom Domain-Specific Languages (DSLs) written in Kotlin and how they can be used as a powerful tool to solve a variety of challenges.
Chapter 12, Fully Functional – Embracing Functional Programming, provides a deep dive into achieving functional programming with Kotlin. It focuses on how to effectively use the Kotlin Standard Library to write more functional code, and it also takes a look at the Arrow library for writing truly functional code with Kotlin.
Chapter 13, Kotlin on Android, explores the use of Kotlin for Android development. It details why Kotlin is so popular for Android development, how it makes a developer's life easier, and what Kotlin tooling is available for building Android applications.
Chapter 14, Kotlin and Web Development, introduces the use of Kotlin for frontend web development. This chapter will help you to understand where Kotlin can be used for web development, how to get started by building a simple project, and what the limitations of Kotlin for frontend web development are.
Chapter 15, Introducing Multiplatform Kotlin, explores the use of Kotlin for multiplatform projects. It describes how the Kotlin multiplatform approach is different from other cross-platform solutions, how to package and write code that targets multiple platforms, and where the current limitations exist. In this chapter, you will learn how to set up a multiplatform project that targets iOS, Android, and the web using common Kotlin code.
Chapter 16, Taming the Monolith with Microservices, introduces the use of Kotlin for backend services that can be used within a microservices architecture. It will describe how and where Kotlin can be used to write backend services and how those can interoperate with other services.
Chapter 17, Practical Design Patterns, revisits familiar Java design patterns and demonstrates how to reimagine those patterns using Kotlin features that have been explored throughout this book.
To get the most out of this book
You should be comfortable creating and running Kotlin projects from an IntelliJ-based IDE, installing IDEs such as IntelliJ, Android Studio, and Xcode, and also be familiar with how to run command-line tools on your machines. With the exception of Chapter 15, Introducing Multi-Platform Kotlin, all examples in this book should run regardless of your OS of choice. For Chapter 15, Introducing Multiplatform Kotlin, the portions of the example dedicated to setting up an iOS project require a computer running macOS and Xcode. You should be comfortable using GitHub and downloading or cloning a GitHub repository in order to make use of the examples presented in this book.
Download the example code files
You can download the example code files for this book from your account at www.packt.com. If you purchased this book elsewhere, you can visit www.packt.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
1. Log in or register at www.packt.com.
2. Select the SUPPORT tab.
3. Click on Code Downloads & Errata.
4. Enter the name of the book in the Search box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Mastering Kotlin. In case there's an update to the code, it will be updated on the existing GitHub repository.
We also have other code bundles from our rich catalog of books and videos available at https://github.com/ PacktPublishing/. Check them out!
Code in Action
Visit the following link to check out videos of the code being run: http://bit.ly/325fQhz
Conventions used
There are a number of text conventions used throughout this book.
CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "Demonstrations of null and non-null types."
A block of code is set as follows:
data class Language(val name: String)
fun main(args: Array) {
val language = Language("Kotlin")
println(language.name)
}
When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:
fun main(args: Array) {
var language: String = "Kotlin"
language = null // Error: Null can not be a value of a non-null type String
}
Any command-line input or output is written as follows:
$ mkdir css
$ cd css
Bold: Indicates a new term, an important word, or words that you see on screen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "Next, under the Client section, select Jetty HttpClient Engine and then click on Next."
Warnings or important notes appear like this.
Tips and tricks appear like this.
Get in touch
Feedback from our readers is always welcome.
General feedback: If you have questions about any aspect of this book, mention the book title in the subject of your message and email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www .packt.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Reviews
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packt.com.
Section 1: Kotlin – A Modern Solution to Application Development
Kotlin is a modern language for modern-day application development. It builds upon decades of experience with Java and modern influences to provide a programming experience that is powerful, flexible, and delightful. In this part, you'll learn about the Kotlin programming language, its goals, its features, and why it's one of the fastest-growing programming languages in the world.
This section comprises the following chapters:
Chapter 1, A New Challenger Approaches
Chapter 2, Programmers' Multi-Tool – Flexible, Expressive, and Concise
A New Challenger Approaches
In this chapter, you'll gain an understanding of what Kotlin is, how it came about, and why it's quickly gaining popularity. You'll find a high-level overview of key language features, as well as the design principles behind the language itself. Finally, this chapter will lay the foundations for the following chapters' focus on features, patterns, platforms, and best practices for improving your understanding of the Kotlin programming language.
This chapter covers the following topics:
Creating a modern language for the Java Virtual Machine (JVM)
Moving beyond the JVM
Designing Kotlin with best practices in mind
Checking in on the current state of Kotlin
Technical requirements
In order to download, compile, and execute the samples found in this chapter, you must have the following:
IntelliJ IDEA 2018.3 Community or Ultimate editions, or newer
An internet connection
Git and GitHub (optional)
To download all of the code in this chapter, including the examples and code snippets, please refer to the following GitHub link: https://github.com/PacktPublishing/Mastering-Kotlin/tree/master/Chapter01.
Creating a modern language for the JVM
Kotlin was born out of a desire for a modern programming language that could be run on the JVM while still being fully compatible with Java and existing Java tooling. With these goals in mind, Kotlin has evolved into one of the fastest growing programming languages in the world and continues to carve out space for itself across multiple domains.
GitHub's 2018 State of the Octoverse report listed Kotlin as the fastest growing language on GitHub: https://github.blog/201 8-11-15-state-of-the-octoverse-top-programming-languages/.
In this section, we're going to dive into what Kotlin is, how it came to be, and why it's great for developers.
What is Kotlin?
So, what exactly is Kotlin? Kotlin is a statically typed programming language designed to run on the JVM and to be 100% compatible with Java and existing Java tooling. Kotlin combines a modern set of features that gives it unique advantages over other JVM languages.
Kotlin is flexible
Kotlin supports, but does not strictly enforce, multiple programming paradigms. With Kotlin, you can write object-oriented, functional, imperative, and reactive code, both separately and combined. Kotlin also supports modern features such as type inference, allowing the compiler to worry about enforcing strict typing rather than the developer. Kotlin can also be run on a variety of different platforms, from IoT devices and mobile applications to the browser.
Kotlin is expressive and concise
Kotlin is designed to be both expressive and concise. Features such as type inference and default parameter values enable developers to accomplish their goals with less code while features such as data classes and object classes allow developers to express common patterns such as singletons with a single keyword.
Kotlin is powerful
Although relatively new, Kotlin is a fully featured, powerful programming language ready to tackle the demands of modern software requirements. Features such as higher-order functions, coroutines, and a comprehensive standard library give developers all the tools they need to ship high-quality software.
Hello Kotlin
The following snippet illustrates several interesting features available in Kotlin:
fun formatName(name: String?) = name ?: "Fellow Human"
fun greetReader(greeting: String = "Hey", name: String?) =
println("$greeting ${formatName(name)}")
fun main(args: Array) {
greetReader("Hello!", "Reader")
// Hello! Reader
}
As you look at these few lines of code, you will notice a few items of interest, which are as follows:
The use of the fun keyword to define a new function
Functions that exist outside of any enclosing class
Demonstrations of null and non-null types
Support for default parameter values and String templates
Who created Kotlin?
Kotlin was created by software company JetBrains who are best known for creating excellent development tools such as IntelliJ IDEA. JetBrains has continued to invest in Kotlin over the years and is still a driving force behind the advancement of the language.
Announcing Kotlin
Kotlin was first announced to the world in 2011 at the JVM Language Summit. Having already been in development for a year upon announcement, the first public release came in January 2012. The following month saw the open source release of Kotlin under the Apache License 2.0.
Motivations for Kotlin
According to JetBrains, their motivations for creating an entirely new programming language were threefold:
They wanted a more productive language for the JVM than was currently available. Existing solutions such as Java or Scala either lacked modern language features or suffered from slow compile times.
They expected Kotlin's adoption to drive sales of IntelliJ.
It was hoped that the increased discussion and awareness of the company would lead to greater trust in JetBrains itself and their philosophies around building quality development tools.
Community involvement
From the early days of Kotlin, lead language designer Andrey Breslav made it clear that several things were important in the development of the language such as first-class interoperability and community feedback.
Since the initial announcement of Kotlin, JetBrains has been open about motivations, design decisions, and the development process. This openness has worked in their favor and has contributed to the current success of the Kotlin programming language. Now, let's see what lies beyond all this.
Moving beyond the JVM
Kotlin may owe its origin to JVM interoperability, but it has quickly moved beyond pure JVM applications. One of the early wins for Kotlin was acceptance in the Android development community where most developers were required to use Java 6 or Java 7. Kotlin enabled Android developers to use language features, such as lambdas, which were not available on older versions of Java.
Outside of Android, Kotlin can now be transpiled to JavaScript, used in multiplatform mobile applications, or compiled to run natively on macOS, Windows, and Linux.
Kotlin for Android
To date, Kotlin has received the most popularity in the Android development community. Kotlin starting gaining traction for Android development in 2015, but it was 2017 when Kotlin really came to the forefront. At Google IO 2017, Google announced first-class support for the Kotlin programming language. It was to sit alongside Java and C++ as officially supported languages for the platform and this marked the beginning of the large-scale adoption of the language.
When Android Studio 3.0 was released in October of 2017, there was no longer a major blocker to adopting the language in established projects. Teams that had been concerned about prerelease versions of plugins or IDEs could now try the language on stable tooling with the full, long-term support of Google. This allowed teams and organizations to adopt the language with much more confidence and began the surge in Kotlin's popularity that we see today.
The official Android documentation now defaults to Kotlin when displaying code snippets. This is just one example of Google's commitment to long-term support for Kotlin on Android.
IntelliJ and Android Studio both make it incredibly easy to integrate Kotlin with existing Android projects, or to start new projects that are 100% Kotlin. Additionally, Google continues to invest in Kotlin with improved tooling and the Core-KTX Jetpack library, which makes building Android applications with Kotlin even more enjoyable.
Chapter 13, Kotlin on Android, will dive deeper into the usage of Kotlin for Android application development.
Kotlin for the web
From the beginning, Kotlin has been built with portability in mind. Because it is a JVM language, it can operate anywhere with an existing JVM stack, and with support for transpiling to JavaScript, you can write Kotlin code for a variety of web development needs, such as manipulating the DOM or interacting with Node.js.
Chapter 14, Kotlin and Web Development, will further explore the use of Kotlin in JVM and JavaScript web development.
Now, let's see how Kotlin works here.
Server-side Kotlin
Java remains one of the most popular programming languages in the world and much of that use is happening in server-side backend systems. Kotlin can integrate smoothly with any of these JVM supported systems and can be integrated all at once, or bit by bit as developers become more familiar with the language. Kotlin can be used to deploy these applications to any system that supports Java web applications.
Kotlin tooling for server-side work is great as well. IntelliJ IDEA has full support for the language and there are additional plugins for popular frameworks such as Spring. JetBrains has also developed Ktor, an unopinionated framework for developing web applications with Kotlin. These tools aim to make it as easy as possible to use Kotlin for your server-side work.
Kotlin to JavaScript
Not only can Kotlin be used to build JVM-compatible projects for the web, but it can additionally be transpiled to target client-side and server-side JavaScript. The transpiled code currently targets ECMAScript 5.1 and aim to provide as consistent an experience as possible between targeting the JVM and JavaScript.
Native and multiplatform Kotlin
JetBrains continues to work toward Kotlin becoming a more ubiquitous language, and a big part of that effort is in Kotlin/Native. Kotlin/Native enables developers to write Kotlin code that is compiled to native binaries. This enables Kotlin to be run on platforms such as iOS, macOS, Windows, and so on.
Kotlin/Native retains its great interoperability and can be used to integrate with other languages such as C++ or Objective-C. This allows Kotlin to be used in multiplatform projects where common functionality is written in Kotlin and then shared between other targets. A great example of this is in mobile development where Kotlin code can be shared between iOS and Android applications.
In Chapter 15, Introducing Multiplatform Kotlin, you'll learn more about how Kotlin/Native and multiplatform projects can bring your Kotlin code to additional platforms.
Having an understanding of these concepts, let's now understand some best practices with Kotlin in mind.
Designing Kotlin with best practices in mind
Kotlin has been designed based on decades of experience from working with Java and other programming languages. By building on this experience, JetBrains has worked to improve the developer experience with Kotlin by focusing on things such as first-class tooling support from day one, fast build times, and bringing modern features and best practices to the language design.
Learning from Java
Kotlin is 100% compatible with Java through the bytecode that allows both to target the JVM. Kotlin's origin stems from wanting modern language features and compile speeds that other JVM languages couldn't provide. Because of these, Kotlin is heavily influenced by Java, but can improve areas where deficiencies or best practices have been discovered over the years.
Best practice by design
By examining other languages, and common best practices, Kotlin's designers have been able to provide language features and syntax that make it easier to write safer, cleaner, more concise code by default.
A few examples of this include the following:
Non-null types
First-class support for functions and function types
Invariant arrays
Language support for singletons
Data classes
Long considered to be the billion dollar mistake, null, and how to handle it properly, is one of the most common challenges for Java developers. Kotlin looks to improve on this by making types non-null by default, and it requires developers to explicitly mark something as nullable.
Kotlin includes first-class support for functions and for function types. This makes Kotlin well suited to functional programming and can allow developers to reduce the number of classes in their projects. Features such as data classes, invariant arrays, and final-by-default classes all help enforce immutability in your code base.
By making it easier, or the default behavior, to enforce best practices, it makes it more likely that developers will follow them.
After understanding the best practices for learning Kotlin from Java and by design, we can now check the current state of Kotlin.
Checking in on the current state of Kotlin
Today, Kotlin is one of the fastest growing languages in the world. It has already proven itself for Android development and is now starting to find a home in other domains as well.
Developing Kotlin in the open
Since its public announcement, JetBrains has been very open with the development of Kotlin. This includes a public issue tracker, regular blog posts, conference talks, a yearly Kotlin census, and they even have their own conference now, KotlinConf.
You can submit your feedback, or leave your own issues and feature requests in the Kotlin issue tracker: https://youtrack.je tbrains.net/issues/KT.
Kotlin has seen four major stable releases to date, which are as follows:
v1.0: February 15, 2016
v1.1: March 1, 2017
v1.2: November 28, 2017
v1.3: October 29, 2018
Each of these releases has brought exciting new functionality to the language. Most recently, Kotlin v1.3 brought coroutine support for asynchronous programming.
Increasing popularity for Kotlin
The popularity of Kotlin can be seen in a number of ways. GitHub's 2018 The State of the Octoverse survey listed Kotlin as the number one fastest growing language by contributors, seeing a 2.6x increase in contributors over the previous year.
JetBrains is currently planning their third KotlinConf, which has welcomed over 1,200 attendees at each of the earlier events. The reception at the first event was so positive, and demand overseas was so high, that in 2018, the event was moved from San Francisco to Amsterdam.
As more and more developers are turning to Kotlin, we are now seeing an increase in learning tools as well. Companies such as Google and Udacity have partnered to develop Kotlin training courses. JetBrains now offers a Kotlin training certification for individuals or companies that want to certify the quality of their Kotlin instruction. Developers are writing and speaking about Kotlin all over the world at meetups, conferences, and on podcasts, webinars, and so on. Much of this is new over the past two years, and all indicators suggest that this will only increase as more and more organizations and individuals start using Kotlin in their projects.
Learning Kotlin
If you've never worked with Kotlin, there are a number of ways to try it out and to begin learning the language.
If you would like to jump right into using Kotlin in your existing code base, Kotlin is supported by a number of popular IDEs:
Android Studio
IntelliJ IDEA Community and IntelliJ IDEA Ultimate
Eclipse
Android Studio and IntelliJ IDEA both provide support for quickly converting Java to Kotlin and for examining the common generated bytecode. Additionally, both IDEs provide a REPLtool and scratch files that allow you to quickly run individual Kotlin commands or functions independently from the rest of the code base. This can make it very easy to start playing with Kotlin within a familiar tool.
If you would prefer to try Kotlin before downloading an IDE, there are several options for hands-on learning in your web browser:
Playground: https://play.kotlinlang.org
Kotlin examples: https://play.kotlinlang.org/byExample/overview
Koans: https://play.kotlinlang.org/koans/overview
Each of these will help you gain an understanding of Kotlin features, and extend from the basics up to more complex coding challenges where you can test your understanding.
In this book, we'll work through examples of many of Kotlin's features. We'll work to understand the features on their own, and then learn how they can be used to cleanly architect your applications and implement familiar design patterns. Additional resources for learning Kotlin can be found at the end of this chapter in the Further reading section.
Summary
Kotlin is a modern programming language that can be used to build applications across mobile, the web, and native platforms. Since its inception, JetBrains has developed Kotlin to provide an excellent developer and integration experience so Kotlin can be learned gradually and slowly integrated into existing projects. The design and development of the language has been done very much in the open, and you can view the Kotlin issue tracker and submit your own ideas, issues, and feedback to help contribute to the language. Kotlin's popularity continues to increase rapidly, and its ability to target a variety of platforms makes it likely that the popularity trend will continue.
In this book, you'll learn firsthand why Kotlin is growing so rapidly. We'll start by exploring different application architectures, and how to model data and manage state using Kotlin. We'll then explore how Kotlin can be integrated and tested with existing Java code. Advanced topics such as coroutines and functional programming will be examined, and finally, we'll take a look at how Kotlin can be used on different platforms such as Android and the web.
In Chapter 2, Programmers' Multi-Tool - Flexible, Expressive, and Concise, we'll dive into the building blocks of the language. You'll learn more about Kotlin's support for multiple programming paradigms, first-class functions, non-null types, and explore Kotlin's extensive standard library.
Questions
1. Which company started the development of the Kotlin programming language? 2. When was Kotlin announced to the world?
3. Who is the lead designer of Kotlin?
4. What platforms did Kotlin initially target?
5. Which platforms are currently supported by Kotlin?
6. For which platform has Kotlin gained the most popularity?
7. List two factors that have contributed to the rapid growth of Kotlin.
Further reading
Kotlin Quick Start Guide, published by Packt (https://www.packtpub.com/application-development/kotlin-quic k-start-guide)
Kotlin Programming By Example, published by Packt (https://www.packtpub.com/application-development/ko tlin-programming-example)
Learning Kotlin by Building Android Applications, published by Packt (https://www.packtpub.com/applic ation-development/learning-kotlin-building-android-applications)
Kotlin Programming By Example, published by Packt (https://www.packtpub.com/application-development/ko tlin-programming-example)
Programmers' Multi-Tool – Flexible, Expressive, and Concise
This chapter will dive into the building blocks of the language and will provide a foundation upon which the rest of this book can build. It will highlight some of the most popular language features such as first class functions, non-null types, the Standard library, and support for multiple programming paradigms. You'll begin to develop an understanding of how these features work on their own and how they may impact how you develop your applications.
This chapter is structured as follows:
Picking your programming paradigm
Embracing first-class functions
Fixing the billion-dollar mistake
Integrating with Java
Technical requirements
To download, compile, and execute the samples found in this chapter, you must have the following:
IntelliJ IDEA 2018.3 Community or Ultimate editions or newer
An internet connection
Git and GitHub (optional)
To download all of the code in this chapter, including the examples and code snippets, please see the following GitHub link: https://github.com/PacktPublishing/Mastering-Kotlin/tree/master/Chapter02.
Picking your programming paradigm
When learning about or discussing, a new programming language, it can be useful to understand the programming paradigms that the language can be classified with. A programming paradigm can be thought of as a means of classifying languages based on common features.
Object-oriented languages, such as Java and C++, all support some form of modeling data with logical representations such as classes. Functional programming languages, such as Common Lisp or JavaScript, perform operations as pure transformations of data without global state or mutable data.
Languages can fall into multiple paradigms at the same time. Kotlin allows developers to write imperative object-oriented code and functional code, as well as asynchronous reactive code. Developers can mix-and-match these methodologies as they see fit because, while Kotlin supports them all, it doesn't enforce any particular programming paradigm.
Object-Oriented Programming
Java developers are used to writing object-oriented code. In Java, everything must happen within a class, so it likely comes as no surprise that Kotlin fully supports Object-Oriented Programming. In fact, Kotlin improves upon Java's support and provides convenient solutions for common Object-Oriented Programming patterns such as defining singletons, creating immutable data classes, and providing getters/setters.
The following code snippet shows a basic example of programming in Kotlin using object-oriented principles. It demonstrates the implementation of a simple class along with accessing the public property of that class:
data class Language(val name: String)
fun main(args: Array) {
val language = Language("Kotlin")
println(language.name)
}
As you likely know, there is much more to Object-Oriented Programming than the simple snippet here. You'll learn more about using Kotlin to write effective object-oriented code in Chapter 4, First-Class Functions.
Functional programming
Functional programming languages rely on pure transformations of data to perform work. This approach differs from Object-Oriented Programming rather significantly because functional programming avoids mutable data and a global state.
With Kotlin's support for first-class functions and its large Standard library, it's possible to use it to write highly functional programs as well. The following snippet is a small example of how functional code can be written in Kotlin by chaining multiple function calls together and processing data without side-effects:
// Performing multiple filter operations on an input list
studentList
.filter { student -> student.grade == 11 }
.filter { student -> student.gpa > 3.5 }
In Chapter 12, Fully Functional – Embracing Functional Programming, you'll learn more about how to write functional programs in Kotlin as well as some tools that make this easier to accomplish.
Reactive programming
Reactive programming relies on asynchronous streams of data that can be observed, transformed, and responded to. Reactive programming has gained a great deal of popularity recently with the adoption of Redux and ReactiveX across various languages.
For Java developers, RxJava has become quite popular, especially in the Android development domain. Because of Kotlin's strong interoperability with Java, it's also possible to leverage RxJava and RxKotlin to write reactive code.
The following example demonstrates one way in which reactive code can be written in Kotlin:
studentsObservable
.filter { student -> student.grade == 11 }
.filter { student -> student.gpa > 3.5 }
.subscribeBy(
onNext = { displayStudents(it) },
onError = { error -> error.printStackTrace() },
onComplete = { println("Done!") }
)
Kotlin supports reactive programming via multiple means such as RxJava/RxKotlin and coroutine channels.
In Chapter 3, Understanding Programming Paradigms in Kotlin, you'll dive deeper into the specifics of each programming paradigm and how they are influenced and realized in Kotlin.
Now that we understand how to pick a programming paradigm, let's move on to find out about first-class functions and how they fit in.
Embracing first-class functions
Kotlin includes first-class support for functions, which means that functions can be invoked, and entire applications written, without having to rely on classes and methods as in Java. This represents a significant shift in how code is written using Kotlin.
This support for functions enables a variety of useful features in the language:
Functional programming can be achieved because of Kotlin's functions.
Extension functions give the ability to modify and adapt APIs to fit our needs.
Higher-order functions are the backbone of the Standard library.
First-class functions allow developers to remove entire categories of "helper" and "utility" classes that existed for the sole purpose of containing static methods.
Function types
There are several types of function in Kotlin that all have their unique traits and uses. Understanding these function types and when to use them is an important part of fully embracing Kotlin. By taking advantage of Kotlin's different function types, you'll be able to write cleaner, safer, and more idiomatic code.
Next, you'll see a subset of the function types that will be discussed, including top-level functions, extension functions, and higher-order functions. In Chapter 4, First-Class Functions, we will explore in some depth Kotlin's support for functions, their flexibility, and the different variations of functions available.
Top-level functions
In Kotlin, a function can be defined independently of any associated class. If a function is written within a Kotlin file, it will be available as a standalone, callable function within whatever visibility scope has been defined (public, internal, or private). This type of function is what's known as a top-level function.
This differs from other JVM languages such as Java and Scala where all functions are defined as methods of an associated class. This has implications within the Java interop story and will be discussed in more detail in Chapter 4, First-Class Functions. The following snippet demonstrates a basic, top-level function available within its declared module:
// defined within any *.kt class
fun printHello() = println("Hello!")
Extension functions
Similarly to C# or Swift, Kotlin supports extension functions. Extension functions allow you to extend the behavior of an existing type, even if you don't own that type. This can be extremely useful when working with cumbersome APIs or when building custom DSLs. Extension functions can be defined in any Kotlin file, but require special syntax.
The following snippet is taken from the Kotlin Standard library and demonstrates how extension functions can be used to extend common classes as well:
// forEach is defined as an extension function CharSequence
inline fun CharSequence.forEach(action: (Char) -> Unit)
The forEach function does not exist as a method on CharSequence but can be invoked as if it were a method. This not only gives the language's developers the freedom to extend classes as needed, but any developer is now free to modify existing types as they see fit.
Higher-order functions
Kotlin allows you to write functions that return another function or that take functions as arguments. This is a very powerful feature and is leveraged heavily across the Kotlin ecosystem. One way in which higher-order functions represent a large change from Java is in their ability to replace Single Abstract Method types (SAM-types) with function arguments and passed lambdas. It's no longer required that you define an interface for simple callbacks that could be treated as a function. You can see one example of this in the following snippet.
In the same example from the Kotlin Standard Library, we see that the forEach function takes another function as an argument. That function will define what should happen when each character in CharSequence is iterated over:
// 'action' is a function that is called for each char
// in the CharSequence
inline fun CharSequence.forEach(action: (Char) -> Unit)
Because of Kotlin's support for higher-order functions, it's not necessary to pass any type of class or interface as a callback: instead, pure functions can be used.
Standard library
The Kotlin Standard library provides numerous functions that make working with Kotlin much more idiomatic and enjoyable. These include functions and extension functions for working with strings, collections, and other common JDK classes. The Standard library also includes several functions such as let and apply, which really encapsulate what people often think of when they consider idiomatic Kotlin.
In Chapter 12, Fully Functional – Embracing Functional Programming, you'll discover more about Kotlin's rich Standard library of functions and learn about Arrow, a library for fully functional programming with Kotlin.
Let's now move on to understand some improvements to be made and kept in mind before being able to integrate Java with Kotlin.
Fixing the billion-dollar mistake
Many developers quickly learn about the challenges associated with handling null types in a programming language. One of the most common errors for Java developers is NullPointerException, which is caused by trying to access an object that is null. In fact, the frustrations attributed to null are so great, it's even been referred to as the "billion-dollar mistake."
Seeing, and understanding, the problems that null has caused in Java and other languages, Kotlin was designed to eliminate null as much as possible. In Kotlin, types are non-null by default. To work with a nullable type requires the explicit addition of the ? symbol. In this section, we'll look at how to define null and non-null types, and a few of the ways we can handle nullable types within our Kotlin code.
Defining null and non-null types
How to best work with, and eliminate, null from Kotlin is a very relevant and important topic, and the presence of non-null types is one of the biggest differences between Java and Kotlin. Having some discussion around this key distinction is important key to learning Kotlin and understanding further concepts around null-safe calls, scoping operators, and so on. Before learning more about working with null, let's look at how we would define a non-null value. In the following snippet, you'll see we create a variable named language of the String type:
fun main(args: Array) {
var language: String = "Kotlin"
}
If we want to assign a null value to our language variable, we will get a compiler error:
fun main(args: Array) {
var language: String = "Kotlin"
// Error: Null can not be a value of a non-null type String
language = null
}
This is because types in Kotlin are non-null by default, and so our language variable will only accept String (non-null) types. To allow a variable to accept a null reference, it must be explicitly declared as accepting nullable values:
fun main(args: Array) {
var language: String = "Kotlin"
language = null // Error: cannot be null
var name: String? = "Kotlin"
name = null // this is okay
}
In this case, the name variable is defined as the String? type. To indicate that a variable should accept null values, you must add ? after the type.
Working with null
Kotlin aims to eliminate null and NullPointerException from your code. This is why types are non-null by default. Unfortunately, it's not always possible to avoid null, especially if working within a mixed Java plus Kotlin code base. There are sometimes scenarios where null might be a reasonable option to represent your data, or you might be working with an API that uses null. For these types of cases, there are several ways in which you can safely work with null types, such as the following ones:
Safe calls
Non-null assertion
Conditionals
The Elvis operator
Safe casts
Null-safe calls
With a non-null type, you may safely call methods or access properties on a variable without worrying about NullPointerException. In this snippet, languages is inferred to be List. Because languages is of a non-null type, the isNotEmpty() method may be called without worrying about NullPointerException, as follows:
fun main(args: Array) {
var languages = listOf("Kotlin", "Java", "c++")
languages.isNotEmpty() // okay
}
If the list were defined as List?, this would not be the case. In this case, calling companies.isNotEmpty() would result in a compiler error. Because the compiler knows the value might be null, it will require you to handle that possibility in some way:
fun main(args: Array) {
var languages = listOf("Kotlin", "Java", "c++")
languages.isNotEmpty() // okay
var companies: List? = null
companies.isNotEmpty() // Error: Only safe (?.)
// or non-null asserted (!!.) calls are allowed
}
Perhaps the simplest way to handle the possible null value is to use a safe call. Safe calls are written using ?. and allow you to access properties or call methods without fear of NullPointerException. In this snippet, companies?.isNotEmpty() is a safe call and would return null if companies were null:
fun main(args: Array) {
...
var companies: List? = null
companies?.isNotEmpty() // okay
}
Safe calls can be chained together as well, making them extremely useful when accessing or assigning nested properties in a nullable type. In the following example, companies?.get(0)?.toLowerCase() will safely return null if any part of the expression evaluates to null:
fun main(args: Array) {
...
var companies: List? = null
companies?.get(0)?.toLowerCase() // okay
}
In this example, if student?.favoriteSubject evaluates to null, subject[0] will never be evaluated:
fun main(args: Array) {
val subject = listOf("CS", "Math", "Physics")
val student: Student? = null
student?.favoriteSubject = subject[0]
}
Non-null assertion
There may be situations in which a null safe call is not how you want to handle null. Another option is to use a non-null assertion call on the nullable variable. This will throw NullPointerException if the variable is null. This might be desirable if you're parsing input parameters and your program can't run without them. We can see an example of this in the following snippet:
fun parseArgs(args: Array?) {
val argCount = args!!.size // throw NPE if 'args' is null
}
In situations like this, it may then be desirable to fail quickly rather than providing a default value.
If you use a non-null assertion call on a variable and then use that variable again after the call, the compiler will SmartCast the variable to a non-null type and you can omit any further safe or non-null assertion calls.
Conditional checks
It's also completely possible to check for null using standard conditional if/else checks. In this snippet, if args is null, the expression will evaluate to 0:
fun parseArgs(args: Array?) {
val argCount = if(args != null) args.size else 0
}
This type of if/else expression makes working with val much easier as we can ensure our variable values are assigned only once, adding to the level of immutability within our programs.
The Elvis operator
The use of conditionals is not an uncommon occurrence; however, the syntax is a little verbose for such a common occurrence. For these cases, the Elvis operator, ?:, can be used to make the code a little more concise. The Elvis operator allows you to return a non-null value in an expression if the left-hand side of the expression evaluates to null. We'll find an example of this in the following snippet:
//if args?.size is non null, use args.size, otherwise return 0
fun parseArgs(args: Array?) {
val argCount2 = args?.size ?: 0 // return 0 if args?.size is null
}
In this code, if the null-safe call, args?.size, evaluates to null, then the Elvis operator will provide the value specified on the right-hand side, in this case, 0.
After sorting this mistake, let's finally see how to integrate Kotlin with Java.