There are 2 types of variables in Kotlin. Variables declared with val
are immutable. Whereas variables declared with var
are mutable.
Kotlin can infer a Variable's type at compile time. Variables that cannot be inferred can be explicitly typed.
val x:Int = 2
Variables can be passed to functions. Variables passed to functions are called parameters. Functions parameters have a type, and an optional default value.
fun add(a: Int, b: Int = 0) = a + b
Control statements like IF and ELSE do not require a parenthesis. However, they follow the same syntax as other languages that take after C.
if (number > 0) {
println("Number is positive")
} else if (number < 0) {
println("Number is negative")
} else {
println("Number is zero")
}
Loops use the for in
syntax to iterate over objects in an array
val fruits = arrayOf("Apple", "Banana", "Orange")
println("Fruits:")
for (fruit in fruits) {
println(fruit)
}
}
Loops that iterate for a given number of iterations use the for in until
syntax
for (i in 0 until 100) {
// Your code here using the loop variable 'i'
println(i)
}
For quick declarations, a modified version of the ternary operator is available.
val x = 5
val y = 10
val max = if (x > y) x else y
println("The maximum value is: $max")
The default constructor in Kotlin is defined in paranthesis as part of the class definition.
class Event(val dayOfWeek: String, val timeOfDay: Int) {
private val participants: MutableList<String> = mutableListOf()
init() {
if dayOfWeek == "Tuesday" {
participants.add('Lee')
}
}
constructor(dayOfWeek: String) : this(dayOfWeek, 100)
}
the init() function is always called. It is the code of the default constructor. Even if another constructor is added, the init() function will be called following the execution of the constructor.
For mutable array's Kotlin uses the MutableList<>
type.
val participants: MutableList<Person> = mutableListOf()
participants.add(lee);
Arrays can be quickly constructed using arrayOf
, arrayOfNulls
, and emptyArray
val fruits = arrayOf("Apple", "Banana", "Orange")
Other common array types include List and ArrayList.
Special functions called accessors give access to read a property of class. While mutators give access to change a class property. For example: getFoo()
and setFoo(value)
.
As a convenience of Kotlin, all class properties have these methods by default.
class Example {
var myProperty: String
}
For added flexibility, special mutator and accessor functions can be defined.
class Example {
var myProperty: String
get() = field
set(value) {
field = value
// Additional code to run when the property is set
}
}
The variable field
is a reserved keyword refering to the field backing the property.
Note that there is no didSet
or willSet
equivalent in Kotlin.
Kotlin, similar to Swift, discourages the use of null values.
Rules are as follow
Declaring a val
with no initial value results in a compiler error.
val x:Int
Declaring a var
with no initial value is allowed. However, if the var is accessed before being assigned a value, a compiler error will be produced.
Use the lateinit
specifier to declare class properties that do not have an initial value. lateinit
is a promise to the compiler, that a value will be set before accessing the property. Failure to do so will result in a null pointer exception.
note
lateinit
is different from force unwrapping var x:Int!
in Swift. lateinit
can only be used on class properties. While force unwrap from Swift can be used anywhere.
The not-null assertion operator (!!) in Kotlin is used to assert that an expression or variable is not null. When you use !!, you are telling the compiler to treat the expression as non-null, even if its type is nullable.
val nullableString: String? = "Hello"
val nonNullableString: String = nullableString!!
All Strings in Kotlin are double quoted. Single quotes are reserved for single characters.
var s = "my string"
Strings are concatenated using the + operator
var s1 = "hello, "
var s2 = "World."
println(s1+s2)
A Raw string makes escaping characters unecessary. It also alows for multiple lines of input to define a single string
val multiLineString = """
This is a raw string
that spans
multiple lines.
"""
println(multiLineString)
Strings can have their leading and trailing whitespace removed using the .trimMargin()
function.
Strings in Kotlin are compared lexicographically. When result
is equal to 0 then the strings are identical.
val result = string1.compareTo(string2, ignoreCase = true)
if (result < 0) {
println("$string1 comes before $string2")
} else if (result > 0) {
println("$string1 comes after $string2")
} else {
println("$string1 is equal to $string2")
}
Strings can be reference variables using the $ operator.
val foo = "World"
println("Hello, $foo")
val a = 1
val b = 2
println("$a + $b = ${a + b}")
Note*, values inserted into strings can be computed, but only if the value is known at compile time. This is to prevent complex computations from being performed inside a string.
Traditional nil coalescing can be achieved in Swift using this syntax:
let p = a ?? 1
However, Kotlin has more advanced nil coalescing. The programmer must identify the nullable part of the expression using the 'safe call' operator in conjunction with the 'elvis operator'. In the example, if 'a' is nil then the value of p will be 1.
let p = a?.foo ?: 1
Similarly, in Swift this would require a much more contrived line of code to achieve the same thing
Here is a more advanced example of the elvis operator.
val result = obj?.property1?.method1() ?: defaultValue
Simple Class
a class does not have a primary constructor or an init block, and it doesn't inherit from another class
Access Modifiers
Used to control the level of access to a property, function or class. Kotlin has the same access levels as Java
- public(default)
- private
- protected
- internal
Use raw strings to avoid escaping
val regexPattern = Regex("""[A-Z]* """)
val regexPattern = Regex("\\d{3}-\\d{2}-\\d{4}") // Example: Social Security Number
val inputString = "123-45-6789"
if (regexPattern.matches(inputString)) {
println("String matches the pattern")
} else {
println("String does not match the pattern")
}
import okhttp3.*
import java.io.IOException
class HttpClient {
fun makeHttpRequest(url: String, callback: (String?, Exception?) -> Unit) {
val client = OkHttpClient()
val request = Request.Builder()
.url(url)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
val responseBody = response.body?.string()
callback(responseBody, null)
}
override fun onFailure(call: Call, e: IOException) {
callback(null, e)
}
})
}
}
fun main() {
val httpClient = HttpClient()
val url = "https://www.example.com"
println("Making HTTP request...")
httpClient.makeHttpRequest(url) { responseBody, exception ->
if (exception != null) {
println("HTTP request failed: $exception")
} else {
println("HTTP request successful. Response: $responseBody")
}
}
}