Kotlin is a statically typed programming language that runs on the Java Virtual Machine (JVM) and can be compiled to JavaScript or native binaries. This Kotlin introduction wouldn’t be complete without mentioning that Kotlin was officially announced by JetBrains in 2011 and became Google’s preferred language for Android development in 2019. The Kotlin language is designed to be fully interoperable with Java, which means you can use existing Java libraries and frameworks seamlessly in your Kotlin projects.
Kotlin combines object-oriented and functional programming features, making it incredibly versatile. The language prioritizes safety, conciseness, and expressiveness, which reduces boilerplate code significantly compared to Java. This Kotlin tutorial will show you how Kotlin’s modern syntax and powerful features can make your programming experience more enjoyable and productive.
One of Kotlin‘s most celebrated features is its null safety system. In this Kotlin introduction, you’ll learn how Kotlin eliminates the notorious NullPointerException that plagues many Java applications.
var name: String = "John" // Non-nullable string
var nullableName: String? = null // Nullable string
// This will cause a compilation error
// name = null
// This is allowed
nullableName = null
Kotlin distinguishes between nullable and non-nullable types at compile time. When you declare a variable without the question mark (?), Kotlin ensures it can never be null. This Kotlin tutorial demonstrates how this feature prevents runtime crashes and makes your code more reliable.
Kotlin features powerful type inference that reduces verbose code while maintaining type safety. The Kotlin compiler can automatically determine the type of variables based on their initial values.
val number = 42 // Kotlin infers this as Int
val message = "Hello Kotlin" // Kotlin infers this as String
val isActive = true // Kotlin infers this as Boolean
val price = 99.99 // Kotlin infers this as Double
This Kotlin introduction shows how type inference makes Kotlin code cleaner and more readable while preserving all the benefits of static typing.
Kotlin data classes automatically generate useful methods like toString()
, equals()
, hashCode()
, and copy()
. This feature significantly reduces boilerplate code that you’d typically write in Java.
data class User(val name: String, val age: Int, val email: String)
val user1 = User("Alice", 25, "alice@example.com")
val user2 = user1.copy(name = "Bob") // Creates a copy with modified name
In this Kotlin tutorial example, the User
data class automatically provides all necessary methods without any additional code. Kotlin generates these methods based on the properties defined in the primary constructor.
Kotlin allows you to extend existing classes with new functionality without inheriting from them or using design patterns like Decorator. Extension functions are a powerful feature that makes Kotlin code more expressive and readable.
fun String.removeSpaces(): String {
return this.replace(" ", "")
}
val text = "Hello World Kotlin"
val cleanText = text.removeSpaces() // Returns "HelloWorldKotlin"
This Kotlin introduction demonstrates how extension functions allow you to add new methods to existing classes, even classes you don’t own, making Kotlin incredibly flexible.
Kotlin has excellent support for functional programming concepts, including lambda expressions and higher-order functions. These features make Kotlin code more concise and expressive.
val numbers = listOf(1, 2, 3, 4, 5)
// Lambda expression with higher-order function
val doubled = numbers.map { it * 2 }
val evenNumbers = numbers.filter { it % 2 == 0 }
// Function that takes another function as parameter
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}
val sum = calculate(5, 3) { a, b -> a + b }
This Kotlin tutorial shows how lambda expressions and higher-order functions make Kotlin perfect for functional programming patterns while maintaining readability.
Kotlin uses two keywords for declaring variables: var
for mutable variables and val
for immutable values (constants).
var mutableCounter = 0 // Can be changed
val immutableName = "Kotlin" // Cannot be changed after initialization
mutableCounter = 10 // This is allowed
// immutableName = "Java" // This would cause a compilation error
This Kotlin introduction emphasizes that Kotlin encourages immutability by default, which leads to safer and more predictable code.
Kotlin functions are declared using the fun
keyword. They can have default parameters, named arguments, and variable-length argument lists.
// Simple function
fun greet(name: String): String {
return "Hello, $name!"
}
// Function with default parameter
fun createUser(name: String, age: Int = 18, isActive: Boolean = true): String {
return "User: $name, Age: $age, Active: $isActive"
}
// Single-expression function
fun multiply(a: Int, b: Int) = a * b
// Function with vararg parameter
fun printNumbers(vararg numbers: Int) {
for (number in numbers) {
println(number)
}
}
This Kotlin tutorial demonstrates how Kotlin functions are more flexible and expressive than their Java counterparts, with features like default parameters and single-expression functions.
Kotlin classes are declared using the class
keyword. Kotlin supports primary constructors, secondary constructors, and initialization blocks.
class Student(val name: String, var grade: Int) {
// Property with custom getter and setter
var status: String = "Active"
get() = field.uppercase()
set(value) {
field = if (value.isNotEmpty()) value else "Unknown"
}
// Secondary constructor
constructor(name: String) : this(name, 0)
// Method
fun study(subject: String) {
println("$name is studying $subject")
}
}
// Object declaration (Singleton)
object DatabaseManager {
fun connect() {
println("Connected to database")
}
}
This Kotlin introduction shows how Kotlin classes are more concise than Java classes while providing the same functionality and more.
Kotlin provides familiar control flow structures with some enhancements that make them more powerful and expressive.
// When expression (enhanced switch)
fun getGrade(score: Int): String = when (score) {
in 90..100 -> "A"
in 80..89 -> "B"
in 70..79 -> "C"
in 60..69 -> "D"
else -> "F"
}
// For loops
val languages = listOf("Kotlin", "Java", "Python", "JavaScript")
for (language in languages) {
println("Learning $language")
}
for (i in 1..5) {
println("Number: $i")
}
// If as expression
fun getMax(a: Int, b: Int) = if (a > b) a else b
This Kotlin tutorial demonstrates how Kotlin’s control flow structures are more powerful and expressive than traditional programming languages.
Kotlin provides rich collection APIs that make working with data structures intuitive and functional. Kotlin distinguishes between mutable and immutable collections.
// Immutable collections
val readOnlyList = listOf("Apple", "Banana", "Cherry")
val readOnlySet = setOf(1, 2, 3, 2) // Duplicates are removed
val readOnlyMap = mapOf("name" to "John", "age" to 30)
// Mutable collections
val mutableList = mutableListOf("Red", "Green", "Blue")
val mutableSet = mutableSetOf("Cat", "Dog", "Bird")
val mutableMap = mutableMapOf("country" to "USA", "city" to "New York")
// Adding elements to mutable collections
mutableList.add("Yellow")
mutableSet.add("Fish")
mutableMap["state"] = "California"
// Collection operations
val fruits = listOf("apple", "banana", "cherry", "date")
val longFruits = fruits.filter { it.length > 5 }
val upperCaseFruits = fruits.map { it.uppercase() }
val totalLength = fruits.sumOf { it.length }
This Kotlin introduction shows how Kotlin collections provide powerful functional programming capabilities while maintaining type safety and performance.
Here’s a comprehensive Kotlin example that demonstrates multiple concepts covered in this Kotlin tutorial:
import kotlin.random.Random
// Data class for representing a book
data class Book(
val title: String,
val author: String,
val pages: Int,
var isAvailable: Boolean = true
) {
fun getInfo(): String = "$title by $author ($pages pages)"
}
// Extension function for List<Book>
fun List<Book>.findByAuthor(author: String): List<Book> {
return this.filter { it.author.contains(author, ignoreCase = true) }
}
// Class for managing a library
class Library(private val name: String) {
private val books = mutableListOf<Book>()
private val borrowedBooks = mutableMapOf<String, Book>()
fun addBook(book: Book) {
books.add(book)
println("Added '${book.title}' to $name library")
}
fun borrowBook(title: String, borrowerName: String): Boolean {
val book = books.find { it.title.equals(title, ignoreCase = true) && it.isAvailable }
return if (book != null) {
book.isAvailable = false
borrowedBooks[borrowerName] = book
println("$borrowerName borrowed '${book.title}'")
true
} else {
println("Book '$title' is not available")
false
}
}
fun returnBook(borrowerName: String): Boolean {
val book = borrowedBooks[borrowerName]
return if (book != null) {
book.isAvailable = true
borrowedBooks.remove(borrowerName)
println("$borrowerName returned '${book.title}'")
true
} else {
println("No book found for $borrowerName")
false
}
}
fun displayAvailableBooks() {
val available = books.filter { it.isAvailable }
println("\nAvailable books in $name:")
available.forEach { book ->
println("- ${book.getInfo()}")
}
}
fun searchBooks(query: String): List<Book> {
return books.filter {
it.title.contains(query, ignoreCase = true) ||
it.author.contains(query, ignoreCase = true)
}
}
fun getStatistics(): String {
val total = books.size
val available = books.count { it.isAvailable }
val borrowed = total - available
val avgPages = books.map { it.pages }.average().toInt()
return """
Library Statistics for $name:
- Total books: $total
- Available: $available
- Borrowed: $borrowed
- Average pages: $avgPages
""".trimIndent()
}
}
// Higher-order function for processing books
fun processBooks(books: List<Book>, processor: (Book) -> String): List<String> {
return books.map(processor)
}
// Main function demonstrating all concepts
fun main() {
println("=== Kotlin Library Management System ===")
// Create library instance
val library = Library("Central Library")
// Create sample books using data class
val books = listOf(
Book("The Kotlin Programming Language", "JetBrains Team", 450),
Book("Android Development with Kotlin", "Marcin Moskala", 380),
Book("Effective Kotlin", "Marcin Moskala", 320),
Book("Kotlin in Action", "Dmitry Jemerov", 360),
Book("Head First Kotlin", "Dawn Griffiths", 480)
)
// Add books to library
books.forEach { library.addBook(it) }
// Display initial state
library.displayAvailableBooks()
// Demonstrate borrowing and returning
println("\n=== Borrowing Books ===")
library.borrowBook("Kotlin in Action", "Alice")
library.borrowBook("Effective Kotlin", "Bob")
library.borrowBook("Non-existent Book", "Charlie")
// Display books after borrowing
library.displayAvailableBooks()
// Return a book
println("\n=== Returning Books ===")
library.returnBook("Alice")
// Search functionality
println("\n=== Search Results ===")
val searchResults = library.searchBooks("Marcin")
println("Books by Marcin:")
searchResults.forEach { println("- ${it.getInfo()}") }
// Extension function usage
val moskalaBbooks = books.findByAuthor("Moskala")
println("\nBooks by Moskala (using extension function):")
moskalaBbooks.forEach { println("- ${it.getInfo()}") }
// Higher-order function usage
println("\n=== Book Processing ===")
val bookTitles = processBooks(books) { book -> book.title.uppercase() }
println("Book titles in uppercase:")
bookTitles.forEach { println("- $it") }
val bookSummaries = processBooks(books) { book ->
"${book.title} has ${book.pages} pages"
}
println("\nBook summaries:")
bookSummaries.forEach { println("- $it") }
// Lambda expressions with collections
println("\n=== Collection Operations ===")
val longBooks = books.filter { it.pages > 400 }
println("Books with more than 400 pages:")
longBooks.forEach { println("- ${it.getInfo()}") }
val totalPages = books.sumOf { it.pages }
println("Total pages in all books: $totalPages")
val authorCount = books.groupBy { it.author }.mapValues { it.value.size }
println("Books per author:")
authorCount.forEach { (author, count) ->
println("- $author: $count book${if (count > 1) "s" else ""}")
}
// Statistics
println("\n${library.getStatistics()}")
// Demonstrate when expression
fun categorizeBook(pages: Int): String = when {
pages < 200 -> "Short book"
pages < 400 -> "Medium book"
pages < 600 -> "Long book"
else -> "Very long book"
}
println("\n=== Book Categories ===")
books.forEach { book ->
val category = categorizeBook(book.pages)
println("${book.title}: $category")
}
// Null safety demonstration
var optionalBook: Book? = null
optionalBook = books.randomOrNull()
optionalBook?.let { book ->
println("\nRandomly selected book: ${book.getInfo()}")
} ?: println("\nNo book was selected")
// Safe call operator
println("Selected book pages: ${optionalBook?.pages ?: "Unknown"}")
println("\n=== Kotlin Tutorial Complete! ===")
}
Output:
=== Kotlin Library Management System ===
Added 'The Kotlin Programming Language' to Central Library library
Added 'Android Development with Kotlin' to Central Library library
Added 'Effective Kotlin' to Central Library library
Added 'Kotlin in Action' to Central Library library
Added 'Head First Kotlin' to Central Library library
Available books in Central Library:
=== Borrowing Books ===
Alice borrowed 'Kotlin in Action'
Bob borrowed 'Effective Kotlin'
Book 'Non-existent Book' is not available
Available books in Central Library:
=== Returning Books ===
Alice returned 'Kotlin in Action'
=== Search Results ===
Books by Marcin:
Books by Moskala (using extension function):
=== Book Processing ===
Book titles in uppercase:
Book summaries:
=== Collection Operations ===
Books with more than 400 pages:
Library Statistics for Central Library:
=== Book Categories ===
The Kotlin Programming Language: Long book
Android Development with Kotlin: Medium book
Effective Kotlin: Medium book
Kotlin in Action: Medium book
Head First Kotlin: Long book
Randomly selected book: Head First Kotlin by Dawn Griffiths (480 pages)
Selected book pages: 480
=== Kotlin Tutorial Complete! ===
This comprehensive Kotlin example demonstrates all the key concepts covered in this Kotlin introduction. To run this Kotlin tutorial code, you need:
Dependencies and Setup:
To run the code:
LibrarySystem.kt
kotlinc LibrarySystem.kt -include-runtime -d LibrarySystem.jar
java -jar LibrarySystem.jar
Alternatively, you can run this Kotlin code in:
This Kotlin tutorial example showcases data classes, extension functions, higher-order functions, lambda expressions, null safety, collections, when expressions, and object-oriented programming concepts. The code demonstrates real-world Kotlin usage patterns that you’ll encounter in professional Kotlin development, making this Kotlin introduction both educational and practical for your programming journey.