equals()
`, `hashCode()
`, `toString()
`, and `copy()
`. Data classes are ideal for holding data and are commonly used in Kotlin for modeling objects.
* Coroutines : Kotlin has built-in support for coroutines, which are lightweight concurrency primitives. Coroutines enable writing asynchronous code in a sequential and more readable manner, allowing developers to handle asynchronous operations without blocking the main thread.==
” operator :==
operator is used.compareTo()
function is given below :fun String.compareTo(
other: String,
ignoreCase: Boolean = false
): Int​
fun main(args: Array & lt; String & gt;) {
val x: String = "Kotlin is simple"
val y: String = "Kotlin language is" + " easy"
if (x == y) {
println(" x and y are similar.")
} else {
println(" x and y are not similar.")
}
}​
val number = 42 // The type of 'number' is inferred as Int
val name = "John" // The type of 'name' is inferred as String
val pi = 3.14 // The type of 'pi' is inferred as Double
val flag = true // The type of 'flag' is inferred as Boolean​
number
`, `name
`, `pi
`, and `flag
`) are inferred based on the assigned values. The compiler analyzes the values (`42
`, `"John
"`, `3.14
`, and `true
`) and deduces the most appropriate type.?
`) to the type declaration.?
`) are considered non-nullable, meaning they cannot hold a null value. This is different from Java, where any reference type can hold a null value by default. By making nullability explicit in Kotlin's type system, the compiler can enforce null safety and provide compile-time checks to prevent null-related errors.var name: String? = "John" // 'name' is nullable, it can hold a String or null
var age: Int = 25 // 'age' is non-nullable, it can only hold an Int
name = null // Assigning null to a nullable variable is allowed
age = null // Compilation error: Null cannot be a value of a non-null type Int​
In the above code snippet, the `name
` variable is declared as nullable by appending `?
` to the type declaration (`String?
`). It can hold a String value or a null value. On the other hand, the `age
` variable is declared as non-nullable (`Int
`), and assigning null to it would result in a compilation error.?.
`), the Elvis operator (`?:
`), and the safe cast operator (`as?
`). These constructs allow developers to safely access properties, call methods, or provide default values in scenarios where the value might be null.T!
`), which are used when interoperating with Java code that has unknown nullability information. Platform types are treated as nullable in Kotlin and require careful handling to ensure null safety. val
` and `var
` are used to declare variables, but they have different characteristics:val
` keyword is used to declare a read-only variable, meaning its value cannot be changed once it is assigned.val
` is effectively a final variable.val
` variable must be determined at the time of declaration or in the constructor if it's a member variable. val pi = 3.14​
var counter = 0
counter += 1​
Key differences between `val
` and `var
`:val
` variables are read-only and cannot be reassigned, while `var
` variables are mutable and can be reassigned with new values.val
` is used when you need a variable whose value remains constant or unchangeable. It is similar to declaring a constant. `var
` is used when you need a variable whose value can change over time.val
`, you communicate the intention that the value should not change, which can help improve code readability and prevent accidental modifications.val
`: It is generally recommended to use `val
` whenever possible, as it promotes immutability and reduces the chances of introducing bugs due to mutable state. Immutable variables are often preferred in functional programming and concurrent programming paradigms.val
` is used for read-only variables, while `var
` is used for mutable variables. The choice between them depends on whether you need the variable to hold a constant value or a value that can change. ?
`) to the type declaration. Nullable types allow variables to hold either a non-null value or a null value.?.
`) : The safe call operator (`?.
`) is used to safely access properties or call methods on nullable objects. If an object reference is null, the safe call operator returns null instead of throwing a null pointer exception. It provides a concise and safe way to handle nullable objects.?:
`) : The Elvis operator (`?:
`) is used to provide a default value when a nullable expression evaluates to null. It allows developers to specify an alternative value to use if a nullable expression is null.
4. Non-Null Assertion (`!!
`) : The non-null assertion operator (`!!
`) is used to assert that an expression is non-null. It converts a nullable type to a non-nullable type explicitly. If the expression evaluates to null, a `NullPointerException` will be thrown. It should be used with caution and only when the developer is certain that the value is not null.?:
`) is a useful operator in Kotlin that provides a concise way to handle nullability and provide default values when dealing with nullable expressions. It allows you to specify an alternative value to be used when a nullable expression evaluates to null.expression ?: defaultValue​
?:
` operator is not null, the value of that expression is returned.val nullableValue: String? = getNullableValue()
val nonNullValue: String = nullableValue ?: "Default Value"
// Using the Elvis operator in an assignment
val result: Int = computeResult() ?: throw IllegalStateException("Result is null")​
In the above code snippet, `nullableValue
` is a nullable String that may or may not be null. The Elvis operator is used to assign the value of `nullableValue
` to `nonNullValue
`. If `nullableValue
` is not null, its value is assigned to `nonNullValue
`. Otherwise, the default value `"Default Value
"` is assigned.computeResult()
` returns a nullable `Int
`. If the result is not null, it is assigned to `result
`. However, if the result is null, an `IllegalStateException
` is thrown.true
` or `false
`.IntArray
`, `CharArray
`, etc., for arrays of specific primitive types.
List
`, `Set
`, and `Map
` for working with collections of elements...
`) to represent a sequence of values between a start and end point.?
` to the type declaration.equals()
`, `hashCode()
`, `toString()
`, and `copy()
`. These functions are generated by the compiler based on the properties defined in the primary constructor of the data class.val
) properties. data class Person(val name: String, val age: Int)​
3. Comparison and Copying :equals()
` function, which compares the values of properties for equality.hashCode()
` function is also generated based on the properties of the data class, ensuring that equal objects have the same hash code.copy()
` function is generated, allowing you to create a copy of an existing data class instance with the option to modify some properties.component1()
`, `component2()
`, etc.) that allow destructuring declarations to extract properties easily.val (name, age) = person
` to extract values into individual variables.equals()
`, `hashCode()
`, or `toString()
`) or uses `copy()
` with named arguments, the compiler won't generate them automatically.lateinit
` modifier in Kotlin is used to indicate that a non-null property will be initialized at a later point before it is accessed. It is primarily used with mutable properties that cannot be initialized during object construction or immediately upon declaration.lateinit
` works :lateinit
` modifier is applied to a `var
` property declaration, indicating that it will be initialized later. lateinit var name: String​
lateinit
` property must be assigned a value before it is accessed, using the assignment operator (`=
`). name = "John"​
lateinit
` property is initialized, it can be used like any other property. println(name)​
It's important to note the following characteristics and considerations when using `lateinit
`:lateinit
` can only be applied to `var
` properties (mutable properties), as it allows the property value to be assigned or changed after initialization.lateinit
` can only be used with non-null types, as it implies that the property will eventually be assigned a non-null value.lateinit
` property before it is initialized will result in a `lateinit property has not been initialized` exception.lateinit
` properties are not thread-safe. If multiple threads can access and modify the property concurrently, appropriate synchronization mechanisms should be used.lateinit
` should be limited to cases where the property cannot be assigned a value during object construction and where it is guaranteed to be initialized before accessing it.lateinit
` is commonly used in frameworks like dependency injection or when working with certain lifecycle callbacks, where properties need to be initialized by an external entity. init
` block is used to initialize the properties or execute code during the initialization phase of an object. It is a special block that is part of a class and is executed when an instance of that class is created. The `init
` block is commonly used to perform initialization logic that cannot be achieved through direct property initialization or constructor parameters.init
` block works :init
` keyword followed by a code block enclosed in curly braces. class MyClass {
// Properties
// ...
// Init block
init {
// Initialization code
// ...
}
}​
init
` block is executed before the constructor body. It allows you to perform any required initialization tasks or computations.init
` block, you can access and manipulate the properties of the class, as well as call other functions or perform any necessary operations.
4. Multiple `init
` Blocks : A class can have multiple `init
` blocks, and they are executed in the order they appear in the class body. This allows you to organize and separate different initialization tasks.init
` blocks :class Person(firstName: String, lastName: String) {
val fullName: String
init {
fullName = "$firstName $lastName"
println("Person initialized")
}
init {
println("Additional initialization logic")
// Additional initialization code
}
}
fun main() {
val person = Person("John", "Doe")
println(person.fullName)
}​
Person
` class has two `init
` blocks. The first `init
` block initializes the `fullName
` property by concatenating the `firstName
` and `lastName
` parameters. The second `init` block demonstrates additional initialization logic. When an instance of `Person
` is created, both `init
` blocks are executed in the order they are defined.init
` block is useful for performing complex initialization tasks, initializing properties based on constructor parameters, or executing other required initialization logic before using an object. It provides a way to consolidate initialization code within the class and ensures that it is executed whenever an object is created. object SomeSingleton ​
The above Kotlin object will be compiled to the following equivalent Java code:public final class SomeSingleton {
public static final SomeSingleton INSTANCE;
private SomeSingleton() {
INSTANCE = (SomeSingleton)this;
System.out.println("init complete");
}
static {
new SomeSingleton();
}
} ​
The above way is preferred to implement singletons on a JVM because it enables thread-safe lazy initialization without relying on a locking algorithm like the complex double-checked locking. class Person constructor(name: String, age: Int, salary: Int) {
} ​
Just like functions or methods, it takes a series of parameters with their type. These parameters initialize the variables present in the class.class Person (name: String, age: Int, salary: Int) {
} ​
By removing the constructor keyword, you can get code that is simplified and easy to understand. companion
` keyword. class MyClass {
// ...
companion object {
// Properties and functions
// ...
}
}​
MyClass.myFunction()
MyClass.myProperty​
Companion
". However, you can provide a custom name by explicitly declaring the companion object. class MyClass {
// ...
companion object MyCompanion {
// Properties and functions
// ...
}
}​
class MyClass {
companion object {
const val CONSTANT_VALUE = 42
fun myFunction() {
println("Hello from myFunction()")
}
}
}
fun main() {
println(MyClass.CONSTANT_VALUE)
MyClass.myFunction()
}​
MyClass
` class contains a constant value (`CONSTANT_VALUE
`) and a function (`myFunction()
`). These members can be accessed directly on the class name without creating an instance of `MyClass
`. The output of the program will be:42
Hello from myFunction()​
Companion objects provide a way to define class-level members and share functionality across instances of a class. They are useful for encapsulating common functionality and constants, without the need for an explicit instance. init
` blocks. class MyClass(val name: String, val age: Int) {
// Initialization code can go in init blocks
init {
// ...
}
}​
this
` keyword or to another secondary constructor using the `this
` keyword followed by the appropriate constructor call. class MyClass {
constructor(name: String) {
// Secondary constructor logic
}
constructor(name: String, age: Int) : this(name) {
// Secondary constructor logic
}
}​
3. Init Blocks :init
` blocks are used to initialize properties or execute code during the initialization phase of an object.init
` blocks, which are executed in the order they appear in the class body. class MyClass(val name: String, val age: Int) {
init {
// Initialization code
}
init {
// Additional initialization code
}
}​
fun ClassName.functionName(parameters): ReturnType {
// Function implementation
}​
val result = myObject.functionName()​
fun String.removeWhitespace(): String {
return this.replace(" ", "")
}
fun Int.isEven(): Boolean {
return this % 2 == 0
}
fun main() {
val text = "Hello, World!"
val modifiedText = text.removeWhitespace()
println(modifiedText) // Output: Hello,World!
val number = 7
val isNumberEven = number.isEven()
println(isNumberEven) // Output: false
}​
In the above example, two extension functions are defined. The `removeWhitespace()
` extension function extends the `String
` class and removes whitespace characters from a string. The `isEven()
` extension function extends the `Int
` class and checks whether a number is even. These extension functions can be invoked directly on objects of their respective types, as shown in the `main()
` function.->
`), and then the body of the function. val lambdaName: (ParameterType) -> ReturnType = { parameter ->
// Function body
// ...
}​
it
` within the lambda body. val double: (Int) -> Int = { number ->
number * 2
}
val square: (Int) -> Int = { it * it }​
->
`) : The arrow separates the parameter list from the body of the lambda expression. It indicates the start of the function body.
4. Function Body : The function body contains the code that is executed when the lambda expression is invoked. It can be a single expression or a block of multiple statements. If it's a block, the last expression is treated as the return value. val sum: (Int, Int) -> Int = { a, b ->
val result = a + b
result // Last expression is the return value
}
val greet: () -> Unit = {
println("Hello, World!")
}​
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
val evenNumbers = numbers.filter { it % 2 == 0 }
val sum = numbers.reduce { acc, number -> acc + number }​
Lambda expressions provide a concise and flexible way to define anonymous functions in Kotlin. They are commonly used in functional programming, for defining behavior inline, and as arguments for higher-order functions. Lambda expressions make code more expressive and allow for more concise and readable functional-style programming constructs. constructor
` keyword. They provide additional ways to instantiate objects with different parameter sets.this
` keyword. It allows parameter values to be passed from the primary constructor to secondary constructors or between secondary constructors.this
` keyword followed by the appropriate constructor call.init
` blocks.constructor
` keyword. They are invoked when an object is created using the secondary constructor, providing an alternative way to instantiate objects.init
` blocks associated with the primary constructor. The primary constructor itself does not contain executable code.class Person(val name: String, val age: Int) {
// Primary constructor with property declarations
constructor(name: String) : this(name, 0) {
// Secondary constructor delegating to the primary constructor with age set to 0
}
constructor() : this("", 0) {
// Secondary constructor delegating to the primary constructor with empty name and age set to 0
}
}​
Person
` class has a primary constructor with `name
` and `age
` as parameters. It also has two secondary constructors that delegate to the primary constructor, providing default values for `age` when only the `name` is provided or when no parameters are given. ?.
`) and null checks (`!!
`) are two different approaches to handle null values and avoid NullPointerExceptions. Here's the difference between them: val length: Int? = text?.length​
!!
`) : val length: Int = text!!.length​
Here are some important points to consider when using these operators :?.
`) provide a safer approach to accessing properties and methods on nullable objects. They allow you to handle null values gracefully and avoid NullPointerExceptions by returning null instead.!!
`) are more risky because they explicitly assert that an expression is not null. If the expression is actually null, a NullPointerException will be thrown, potentially causing a program crash.?.
`) are typically used when you expect the possibility of a null value and want to handle it gracefully by providing an alternative behavior or a default value.!!
`) are used when you are certain that an object reference is not null and want to enforce it, bypassing the nullability checks of the compiler. They should be used with caution and only when you are confident that the expression cannot be null.?.
`) and handle null values gracefully by providing appropriate fallback or alternative behaviors. Null checks (`!!
`) should be used sparingly and only when you have explicit knowledge that an expression cannot be null. fun performOperation(operation: (Int, Int) -> Int) {
val result = operation(5, 3)
println("Result: $result")
}​
fun getOperation(): (Int, Int) -> Int {
return { a, b -> a + b }
}
​
3. Lambda Expressions and Function References : val multiply: (Int, Int) -> Int = { a, b -> a * b }
performOperation { a, b -> a + b }
performOperation(multiply)​
fun compose(f: (Int) -> Int, g: (Int) -> Int): (Int) -> Int {
return { x -> f(g(x)) }
}​
run
` function is a scope function that is used to execute a block of code on an object within its context. It provides a concise way to perform operations on an object and access its properties and functions without the need for repetitive object references.run
` function :run
` function is invoked on an object, and the object becomes the context within which the block of code is executed. val person = Person("John", 25)
val description = person.run {
"Name: $name, Age: $age"
}
​
run
` function is the result of the last expression within the block. val person = Person("John", 25)
val modifiedPerson = person.run {
age += 1
this
}​
3. Nullable Context :run
` function allows you to perform operations on the object only if it is not null.run
` function is null. val person: Person? = ...
val description = person?.run {
"Name: $name, Age: $age"
}​
run
` function can be used in conjunction with other scope functions like `let
`, `apply
`, `also
`, and `with
` to chain operations and further customize the behavior. val person = Person("John", 25)
val result = person.let { p ->
p.age += 1
p.name
}.run {
"Modified name: $this"
}​
run
` function provides a convenient way to work with objects and execute a block of code within their context. It helps eliminate repetitive object references, enables concise transformations, and allows for nullable context handling. It is particularly useful when you want to perform operations on an object and obtain a result without introducing additional variables or breaking the flow of the code. let
`, `run
`, `with
`, `apply
`, and `also
` are scope functions that provide a concise way to work with objects and perform operations within a specific context. Although they have similarities, each scope function has its distinct characteristics and intended use cases. Here's a breakdown of the differences between these scope functions:let
`:let
` to execute a block of code on a non-null object and access it as a parameter (`it
`). val nullableValue: String? = ...
val length = nullableValue?.let { value ->
// Safe access to 'value'
value.length
} ?: 0​
run
` :run
` to execute a block of code on an object and access its properties and functions without repetition. val person = Person("John", 25)
val description = person.run {
// Access properties without repetition
"Name: $name, Age: $age"
}​
with
`:with
` to execute a block of code on an object, similar to `run
`, but it does not provide an explicit receiver. val person = Person("John", 25)
val description = with(person) {
// Access properties without repetition
"Name: $name, Age: $age"
}​
4. `apply
` :apply
` to configure properties and perform initialization on an object. val person = Person().apply {
name = "John"
age = 25
}​
also
` :also
` to perform additional actions on an object, similar to `apply
`, but it does not affect the object's properties. val person = Person("John", 25)
val modifiedPerson = person.also {
// Perform additional actions without modifying the object
log("Person: $it")
}​
let
`: Safely accesses properties of a non-null object and performs transformations.run
`: Executes code on an object within its context, accessing properties and functions.with
`: Executes code on an object without an explicit receiver, reducing repetition.apply
`: Configures properties and performs initialization on an object, allowing method chaining.also
`: Performs additional actions on an object, such as logging or side effects, while preserving the object.hash()
, tostring()
, and copy()
functions. data class company(var name: string)
Function main(args array<string>)
{
Val company= company("Manhas Industries")
}​
switch
` statement from languages like Java is replaced with the more powerful and flexible `when
` expression. The `when
` expression allows you to perform conditional branching based on the value of an expression. It offers a more concise and versatile syntax compared to the `switch
` statement. when
` as a replacement for `switch
`:when
` Expression : when (variable) {
value1 -> {
// Code block for value1
}
value2 -> {
// Code block for value2
}
else -> {
// Default code block
}
}​
when (variable) {
value1, value2 -> {
// Code block for value1 or value2
}
else -> {
// Default code block
}
}​
when (variable) {
in range1 -> {
// Code block for values within range1
}
in range2 -> {
// Code block for values within range2
}
else -> {
// Default code block
}
}
4. Checking Type : when (variable) {
is Type1 -> {
// Code block for Type1
}
is Type2 -> {
// Code block for Type2
}
else -> {
// Default code block
}
}​
when {
condition1() -> {
// Code block if condition1() is true
}
condition2() -> {
// Code block if condition2() is true
}
else -> {
// Default code block
}
}​
when
` expression is more flexible than the traditional `switch
` statement as it allows for complex conditions, type checks, range checks, and multiple values. It eliminates the need for `break
` statements and supports more expressive and readable code. Additionally, the `when
` expression can be used as an expression itself, allowing it to be assigned to a variable or used directly in function return statements.when
` expression in Kotlin serves as a powerful replacement for the `switch
` statement, providing enhanced functionality and improved readability. open class B
{
}
class c = B()
{
} ​
for(i 1...15)
print (i)​
Basis | Kotlin | Java |
---|---|---|
Null Safety | By default, all sorts of variables in Kotlin are non-nullable (that is, we can't assign null values to any variables or objects). Kotlin code will fail to build if we try to assign or return null values. If we absolutely want a null value for a variable, we can declare it as follows: value num: Int? = null |
NullPointerExceptions are a big source of annoyance for Java developers. Users can assign null to any variable, however, when accessing an object reference with a null value, a null pointer exception is thrown, which the user must manage. |
Coroutines Support | We can perform long-running expensive tasks in several threads in Kotlin, but we also have coroutines support, which halt execution at a given moment without blocking threads while doing long-running demanding operations. | The corresponding thread in Java will be blocked anytime we launch a long-running network I/0 or CPU-intensive task. Android is a single-threaded operating system by default. Java allows you to create and execute numerous threads in the background, but managing them is a difficult operation. |
Data Classes | If we need to have data-holding classes in Kotlin, we may define a class with the keyword "data " in the class declaration, and the compiler will take care of everything, including constructing constructors, getter, and setter methods for various fields. |
Let's say we need a class in Java that only holds data and nothing else. Constructors, variables to store data, getter and setter methods, hashcode() , function toString() , and equals() functions are all required to be written explicitly by the developer. |
Functional Programming | Kotlin is procedural and functional programming (a programming paradigm where we aim to bind everything in functional units) language that has numerous useful features such as lambda expressions, operator overloading, higher-order functions, and lazy evaluation, among others. | Java does not allow functional programming until Java 8, however it does support a subset of Java 8 features when developing Android apps. |
Extension Functions | Kotlin gives developers the ability to add new functionality to an existing class. By prefixing the name of a class to the name of the new function, we can build extended functions. | In Java, we must create a new class and inherit the parent class if we want to enhance the functionality of an existing class. As a result, Java does not have any extension functions. |
Data Type Inference | We don't have to declare the type of each variable based on the assignment it will handle in Kotlin. We can specify explicitly if we want to. | When declaring variables in Java, we must declare the type of each variable explicitly. |
Smart Casting | Smart casts in Kotlin will take care of these casting checks with the keyword "is-checks," which checks for immutable values and conducts implicit casting. | We must examine the type of variables in Java and cast them appropriately for our operation. |
Checked Exceptions | We don't have checked exceptions in Kotlin. As a result, developers do not need to declare or catch exceptions, which has both benefits and drawbacks. | We have checked exceptions support in Java, which enables developers to declare and catch exceptions, resulting in more robust code with better error handling. |
listOf(1, 2, 3).fold(0) { sum, element -> sum + element } ​
The first call to the lambda will be with parameters 0 and 1. The ability to pass in an initial value is useful if you have to provide a default value or parameter for your operation.reduce
" doesn't take an initial value. Instead, it starts with the first element of the collection as the accumulator.listOf(1, 2, 3).reduce { sum, element -> sum + element } ​
In the above example, it is denoted by sum. The first call to the lambda here will be with parameters 1 and 2. ?:
var name:String? = "Mindorks"
val namenameLength = name?.length ?: -1
println(nameLength) ​
?:
) we are using will return the length of the name if the value is not null; otherwise, if the value is null, then it will return -1
. listOf
`, `mutableListOf
`, and `arrayListOf
` are functions used to create different types of lists. listOf
` function creates an immutable list (read-only) in Kotlin.List<T>
`, where `T
` is the type of the elements in the list. val immutableList = listOf("apple", "banana", "orange")​
mutableListOf
` function creates a mutable list in Kotlin.MutableList<T>
`, where `T
` is the type of the elements in the list. val mutableList = mutableListOf("apple", "banana", "orange")
mutableList.add("grape")
mutableList.removeAt(0)​
arrayListOf
` function is similar to `mutableListOf
` and creates a mutable list in Kotlin.ArrayList<T>
`, which is a specific implementation of `MutableList<T>
`. val arrayList = arrayListOf("apple", "banana", "orange")
arrayList.add("grape")
arrayList.removeAt(0)​
launch
` and `async
` are both functions used to initiate concurrent execution of code. However, they have distinct differences in terms of their behavior and return values. Here's an explanation of the difference between `launch
` and `async
`:launch
` :launch
` function is used to launch a new coroutine without expecting any result.launch
` function returns a `Job
` object, which represents the coroutine and can be used to control or cancel the coroutine if needed. val job = GlobalScope.launch {
// Code to be executed concurrently
}​
async
`:async
` function is used to launch a new coroutine and explicitly return a `Deferred
` object, representing a future result of the computation.Deferred
` object allows you to explicitly await the result using the `await()
` function, which suspends the coroutine until the result is available.async
` function returns a `Deferred<T>
` object, where `T
` is the type of the result. val deferred = GlobalScope.async {
// Code to be executed concurrently and return a result
return@async "Result"
}
val result = deferred.await()​
launch
` and `async
` lies in the return value and purpose:launch
` is used for concurrent execution without expecting a specific result. It returns a `Job
` object.async
` is used for concurrent execution with an explicitly returned result. It returns a `Deferred<T>
` object and allows you to await the result using `await()
`.launch
` and `async
` are essential components of Kotlin coroutines, and the choice between them depends on whether you need to retrieve a result from the concurrent computation or simply perform concurrent tasks without expecting a specific outcome. suspend
` modifier in Kotlin is used to define functions that can be suspended and resumed later without blocking the thread. It is a fundamental part of Kotlin coroutines, which are used for asynchronous and concurrent programming. Here's the purpose and significance of the `suspend
` modifier :suspend
` modifier can perform long-running or blocking operations without blocking the calling thread.suspend
` function is called, it can suspend its execution at specific suspension points without blocking the thread, allowing other code to run in the meantime.suspend
` modifier is specifically designed to work with Kotlin coroutines.suspend
` modifier to indicate that a function can suspend its execution, enabling other coroutines or threads to continue execution.suspend
` functions, along with other coroutine constructs, allows for the creation of sequential and structured asynchronous code.launch
` and `async
` can invoke `suspend
` functions and handle the suspension and resumption of execution transparently.suspend
` modifier is often used with functions that perform operations that can be suspended, such as I/O operations, network requests, or database queries.suspend
` functions allows them to be performed asynchronously without blocking the thread. is
` operator or use the `!is
` operator for a negated type check.as
` operator) in your code, making it more concise and less error-prone.T?
`).!= null` or `== null
`), the compiler smart casts the nullable type to a non-null type within the corresponding block of code.fun processString(str: String?) {
if (str != null) {
// Compiler smart casts 'str' to non-null 'String' type
println(str.length)
}
}​
str != null
`). Within the block, the compiler automatically treats `str
` as a non-null `String
` type, allowing access to its `length
` property without the need for an explicit cast.sealed class Result
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
fun processResult(result: Result) {
when (result) {
is Success -> println(result.data)
is Error -> println(result.message)
Loading -> println("Loading")
}
}​
Result
` is a sealed class with three subclasses: `Success
`, `Error
`, and `Loading
`. These subclasses represent different cases or variations of the `Result
` type. The sealed class ensures that these subclasses are limited and known in advance. The `processResult
` function uses a when expression to handle each possible case of the sealed class.lazy()
function is used that takes a lambda and returns an instance of lazy, which can serve as a delegate for implementing a lazy property: the first call to get()
executes the lambda passed to lazy()
and remembers the result, subsequent calls to get()
simply return the remembered result.val test: String by lazy {
val testString = "some value"
} ​
lateinit var test: String
fun doSomething() {
test = "Some value"
println("Length of string is "+test.length)
test = "change value"
} ​
This is mainly used in the following cases :for(item in collection) {
// code
}​
Here, collection refers to the data structure to be iterated and item refers to each element of the data structure.fun main(args: Array<String>) {
var numbersArray = arrayOf(1,2,3,4,5,6,7,8,9,10)
for (num in numbersArray){
if(num % 2 == 0){
print("$num ")
}
}
}
2 4 6 8 10​
while(condition) {
// code
}​
Example :fun main(args: Array<String>) {
var number = 1
while(number <= 5) {
println(number)
number++;
}
}​
Output :1
2
3
4
5​
do {
// code
{
while(condition)​
Example :fun main(args: Array<String>) {
var number = 4
var sum = 0
do {
sum += number
number--
}while(number > 0)
println("Sum of first four natural numbers is $sum")
}​
Output :Sum of first four natural numbers is 10​
val s1 = "FreeTime"
val s2 = "Learning"
val s3 = "$s1 $s2" // stores "FreeTime Learning"​
+
’ operator to concatenate the two strings and store them in a third variable.val s1 = "FreeTime"
val s2 = "Learning"
val s3 = s1 + s2 // stores "FreeTimeLearning"
val s4 = s1.plus(s2) // stores "FreeTimeLearning"​
val s1 = "FreeTime"
val s2 = "Learning"
val s3 = StringBuilder()
s3.append(s1).append(s2)
val s4 = s3.toString() // stores "FreeTimeLearning"​
launch
`, `async
`, `runBlocking
`, and `withContext
`, to initiate coroutines.suspend
` modifier and can perform long-running or blocking operations without blocking the calling thread.Dispatchers.IO
`, `Dispatchers.Default
`, and `Dispatchers.Main
` to control the thread or thread pool used by coroutines.try-catch-finally
` blocks within coroutines to handle exceptions in a familiar way.filter
` and `map
` functions are both higher-order functions used for transforming and manipulating collections. However, they have distinct purposes and behaviors. Here's an explanation of the difference between `filter
` and `map
`:filter
` Function :true
`. val numbers = listOf(1, 2, 3, 4, 5)
val filtered = numbers.filter { it % 2 == 0 } // Keep only even numbers
// filtered: [2, 4]​
map
` Function :map
` function is used to transform each element in a collection by applying a transformation function (a lambda expression) to each element. val numbers = listOf(1, 2, 3, 4, 5)
val mapped = numbers.map { it * it } // Square each number
// mapped: [1, 4, 9, 16, 25]​
In the key differences between `filter` and `map
` are:filter
` is used to select or filter elements from a collection based on a predicate, returning a new collection with only the matching elements.map
` is used to transform each element in a collection by applying a transformation function, returning a new collection with the transformed elements.filter
` allows you to select elements that meet certain conditions, `map
` enables you to transform each element into something else. Both functions are valuable for working with collections and can often be used together in combination to achieve the desired result. groupBy
` function in Kotlin is a higher-order function used to group elements of a collection based on a specific key or property. It allows you to categorize and organize elements into groups based on a common characteristic. groupBy
` function:groupBy
` function takes a lambda expression or a function that defines the key for grouping elements.groupBy
` function returns a map where each key corresponds to a group, and the corresponding value is a list of elements in that group. data class Person(val name: String, val age: Int)
val people = listOf(
Person("Alice", 20),
Person("Bob", 25),
Person("Charlie", 20),
Person("Dave", 25)
)
val groupedByAge = people.groupBy { it.age }
// Result: {20=[Person(name=Alice, age=20), Person(name=Charlie, age=20)],
// 25=[Person(name=Bob, age=25), Person(name=Dave, age=25)]}​
age
` property using the `groupBy
` function. The resulting map (`groupedByAge
`) has keys corresponding to the distinct age values (20 and 25), and the values are lists of `Person
` objects with the same age.groupBy
` function is useful in various scenarios where you need to categorize elements based on specific criteria. It allows you to efficiently group elements and provides a convenient way to organize and process data. ReadOnlyProperty
` or `ReadWriteProperty
` interface, depending on whether the property is read-only or read-write.by
` keyword followed by the delegate instance.getValue
` and `setValue
`) matching the delegated property.lazy
`, `observable
`, `vetoable
`, and more.ReadOnlyProperty
` or `ReadWriteProperty
` interfaces. class Example {
var value: String by Delegate()
}
class Delegate {
private var backingField: String = "Default"
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return backingField
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
backingField = value
}
}
fun main() {
val example = Example()
println(example.value) // Prints "Default"
example.value = "New Value"
println(example.value) // Prints "New Value"
}​
Example
` class has a `value
` property that is delegated to the `Delegate
` class. The `Delegate
` class handles the actual storage and retrieval of the property value. When accessing or modifying the `value
` property, the corresponding methods in the `Delegate
` class (`getValue
` and `setValue
`) are invoked.==
` and `===
` operators are used for equality comparisons, but they have different behaviors based on the type of comparison being performed:==
` Operator (Structural Equality) :==
` operator is used for structural equality comparisons.==
` operator is equivalent to the `equals()
` method. val a: String = "Hello"
val b: String = "Hello"
val c: String? = "Hello"
println(a == b) // true
println(a == c) // true​
==
` operator checks if the content of `a
` and `b
` (both strings) are equal, which is true. It also compares `a
` with the nullable `String
` `c
`, and the result is true.
2. `===
` Operator (Referential Equality) :===
` operator is used for referential equality comparisons.===
` operator is similar to the `==
` operator in Java when comparing object references. val x: String = "Hello"
val y: String = "Hello"
val z: String? = "Hello"
println(x === y) // true
println(x === z) // false​
===
` operator compares the references of `x
` and `y
` (both strings) and returns true because they refer to the same object instance. However, comparing `x
` with the nullable `String
` `z
` using `===
` returns false since they don't refer to the same object instance. !!
` operator is called the "not-null assertion operator
," and its purpose is to assert that a value is not null. It is used when you are certain that a nullable reference is not null at a specific point in your code, and you want to communicate this assurance to the compiler. Here's an explanation of the purpose and usage of the `!!
` operator:!!
` operator is used to assert that a nullable reference is not null at a particular point in the code.?
` to the type declaration.!!
` operator, you are explicitly telling the compiler that you are aware of the potential nullability risks and are taking responsibility for handling null values.NullPointerException
` will be thrown.
4. Use with Caution :!!
` operator should be used sparingly and with caution because it bypasses the null safety checks provided by the Kotlin type system.?.
`) or null checks (`!= null
`) along with safe operators like the Elvis operator (`?:
`) or safe casts (`as?
`) to handle nullable references in a safer manner.!!
` operator excessively or without proper understanding can lead to null pointer exceptions, which Kotlin aims to prevent. Therefore, it's generally recommended to utilize safe practices and favor null safety features provided by the language whenever possible. @JvmStatic
, @JvmOverloads
, and @JvmFiled
in Kotlin :@JvmStatic
: The @JvmStatic annotation is used to tell the compiler that the method is a static method, and you can use it in Java code.@JvmOverloads
: The @JvmOverloads annotation is required when we need to use the default values passed as an argument in Kotlin code from the Java code.@JvmField
: The @JvmField annotation is used to access the fields of a Kotlin class from Java code without any getters and setters. We need to use the @JvmField
in the Kotlin code. java.io.File
:bufferedReader()
: It is used for reading the contents of a file into BufferedReader.readBytes()
: It is used for reading the contents of the file to ByteArray.readLines()
: It is used for reading lines in the file to List.readText()
: It is used for reading contents of the file to a single String.forEachLine()
: It is used for reading a file line by line in Kotlin. Lateinit | Lazy |
---|---|
The lateinit can be initialized from anywhere the object is seen. | The lazy can only be initialized from the initializer lambda. |
In lateinit, multiple initializations are possible. | The lazy can be initialized a single time only. |
The lateinit is non-thread safe. It is up to the user to initialize it correctly in a multi-threaded environment. | The lazy support thread-safety by default and ensures that the initializer is invoked once. |
It is not eligible for nonnull properties. | It is also not eligible for nonnull properties. |
You can use it only for var. | You can use it only for val. |
It adds an isInitialized method to check whether the value has been initialized before. | In this, the property is never able to un-initialize. |
It is not allowed on properties of primitive types. | It is allowed on properties of primitive types. |
enum
` keyword. Enum classes are used to represent a fixed number of constants or values. Each constant in an enum class is an instance of the enum class itself. Here's the syntax to define an enum class in Kotlin :enum class EnumClassName {
CONSTANT1,
CONSTANT2,
CONSTANT3,
// ...
}​
Let's break down the syntax :enum
` keyword is used to indicate the declaration of an enum class.EnumClassName
` is the name you choose for your enum class. You can use any valid identifier as the class name.{}
`, you list the constant values of the enum class, separated by commas.Color
` with three constants: `RED
`, `GREEN
`, and `BLUE
`:enum class Color {
RED,
GREEN,
BLUE
}​
You can use enum constants like any other value in Kotlin. For example, you can access them using dot notation (`Color.RED
`, `Color.GREEN
`, etc.), compare them for equality (`==
`), iterate over them, and use them in switch-like expressions (when statements) to perform different actions based on the enum value.=
`) must match the number of properties in the data class. data class Person(val name: String, val age: Int)
val person = Person("Alice", 25)
val (name, age) = person
println(name) // Alice
println(age) // 25​
val numbers = arrayOf(1, 2, 3)
val (a, b, c) = numbers
println(a) // 1
println(b) // 2
println(c) // 3​
3. Destructuring Declarations with Custom Types : class Point(val x: Int, val y: Int) {
operator fun component1() = x
operator fun component2() = y
}
val point = Point(3, 5)
val (x, y) = point
println(x) // 3
println(y) // 5​
_
`) as the variable name to indicate that the value should be ignored. val (_, age) = person
println(age) // 25​
Destructuring declarations provide a convenient way to extract values from structured objects and assign them to individual variables in a concise and readable manner. It improves code readability and reduces boilerplate code when working with complex objects or collections.