Read more about basic types in Kotlin from the official documentation.
In Kotlin, everything is an object in the sense that you can call member functions and properties on any variable. While certain types have an optimized internal representation as primitive values at runtime (such as numbers, characters, booleans and others), they appear and behave like regular classes to you.
- The basic types in Kotlin are:
- Numbers
- Characters
- Booleans
- Arrays
- Strings
Numbers
- Kotlin supports the following number types:
- Byte (8-bit signed integer, from -128 to 127)
- Short (16-bit signed integer, from -32768 to 32767)
- Int (32-bit signed integer, from -2^31 to 2^31 - 1)
- Long (64-bit signed integer, from -2^63 to 2^63 - 1)
- Float (32-bit floating point number)
- Double (64-bit floating point number)
1
2
3
4
| val one = 1 // Int
val threeBillion = 3000000000 // Long
val oneLong = 1L // Long
val oneByte: Byte = 1
|
Float
- Floats are represented by 32-bit floating point numbers.
- They can be declared using the
f
suffix (at the end of the number).
1
2
| val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float
|
- Floated numbers are rounded off to 6 decimal places by default!π΅
Double
- Doubles are represented by 64-bit floating point numbers.
- They are the default floating point type in Kotlin.
1
| val pi = 3.141592653589793 // Double
|
Unsigned Numbers
- These are positive numbers, from
0 to 2^n - 1
. - They are represented by the following types:
u
and U
tag is for unsigned literals.- The exact type is determined based on the expected type.
- If no expected type is provided, compiler will use UInt or ULong depending on the size of literal:
- Unsigned types are not allowed to be negative.
1
2
3
4
5
6
| val b: UByte = 1u // UByte, expected type provided
val s: UShort = 1u // UShort, expected type provided
val l: ULong = 1u // ULong, expected type provided
val a1 = 42u // UInt: no expected type provided, constant fits in UInt
val a2 = 0xFFFF_FFFF_FFFFu // ULong: no expected type provided, constant doesn't fit in UInt
|
Use cases
- Unsigned types are useful when you need to represent a positive number and you want to avoid the overhead of checking for negative values. For example an age, a length, a position in a list, etc.
1
2
| val age: Ushort = 25u
val length: UByte = 10u
|
Booleans
- Booleans are represented by the
Boolean
type. - The type Boolean represents boolean objects that can have two values:
true
and false
. - Boolean has a nullable counterpart declared as
Boolean?
. - Built-in operations on booleans include:
||
β disjunction
(logical OR
)&&
β conjunction
(logical AND
)!
β negation
(logical NOT
)
1
2
3
4
5
6
7
8
9
10
11
12
| val myTrue: Boolean = true
val myFalse: Boolean = false
val boolNull: Boolean? = null
println(myTrue || myFalse)
// true
println(myTrue && myFalse)
// false
println(!myTrue)
// false
println(boolNull)
// null
|
Characters
- Characters are represented by the
Char
type. - They are represented by single quotes (
'
).
1
2
| val letterA: Char = 'A'
val letterB = 'B' // Type inference
|
- Characters are represented by the Unicode values.
- You can use escape characters to represent special characters.
1
2
| val tab = '\t'
val infinity = '\u221E'
|
- Special characters start from an escaping backslash . The following escape sequences are supported:
\t
β tab\b
β backspace\n
β newline\r
β carriage return\'
β single quote\"
β double quote\\
β backslash\$
β dollar sign
Strings
- Generally, a string value is a sequence of characters in
double quotes (")
: - Elements of a string are characters that you can access via the indexing operation: s[i]. You can iterate over these characters with a for loop:
1
2
3
4
5
6
| fun main() {
val str = "abcd"
for (c in str) {
println(c)
}
}
|
- Strings are
immutable
. - Once you initialize a string, you canβt change its value or assign a new value to it.
- All operations that transform strings return their results in a new String object, leaving the original string unchanged:
1
2
3
4
5
6
7
8
9
10
11
| fun main() {
val str = "abcd"
// Creates and prints a new String object
println(str.uppercase())
// ABCD
// The original string remains the same
println(str)
// abcd
}
|
- To concatenate strings, use the + operator. This also works for concatenating strings with values of other types, as long as the first element in the expression is a string:
1
2
3
4
5
| fun main() {
val str = "Hello, " + "World!"
println(str)
// Hello, World!
}
|
String Literals
Escaped Strings
- Escaped strings may have escaped characters that are prefixed with a backslash
\
.
1
| val s = "Hello, world!\n"
|
Multiline Strings
- Multiline strings can contain newlines and arbitrary text. It is delimited by a triple quote (βββ), contains no escaping and can contain newlines and any other characters:
1
2
3
4
| val text = """
for (c in "foo")
print(c)
"""
|
- To remove leading whitespace from multiline strings, use the trimMargin() function:
1
2
3
4
5
6
| val text = """
|Tell me and I forget.
|Teach me and I remember.
|Involve me and I learn.
|(Benjamin Franklin)
""".trimMargin()
|
- By default, a
pipe symbol |
is used as margin prefix, but you can choose another character and pass it as a parameter, like trimMargin(">")
.
String Templates
- String templates allow you to include variables and expressions in strings.
- A string template starts with a dollar sign
$
followed by a variable name or an expression in curly braces {}
.
1
2
3
4
| fun main() {
val i = 10
println("i = $i") // prints "i = 10"
}
|
1
2
3
4
5
6
7
8
9
10
| fun main() {
val i = 10
println("i = $i")
// i = 10
val letters = listOf("a","b","c","d","e")
println("Letters: $letters")
// Letters: [a, b, c, d, e]
}
|
1
2
3
4
5
| fun main() {
val s = "abc"
println("$s.length is ${s.length}")
// abc.length is 3
}
|
- You can use templates both in multiline and escaped strings.
- To insert the dollar sign
$
in a multiline string (which doesnβt support backslash escaping) before any symbol, which is allowed as a beginning of an identifier, use the following syntax:
1
2
3
| val price = """
${'$'}9.99
"""
|
- You can use the
format()
function to format strings. - The String.format() function accepts a format string and one or more arguments.
- The format string contains one placeholder (indicated by
%
) for a given argument, followed by format specifiers
. - Format specifiers are formatting instructions for the respective argument, consisting of:
flags
,width
,precision
, andconversion
type.
- Collectively, format specifiers shape the outputβs formatting.
- Common format specifiers include:
%d
for integers,%f
for floating-point numbers, and%s
for strings.
- You can also use the
argument_index$
syntax to reference the same argument multiple times within the format string in different formats.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| fun main() {
// Formats an integer, adding leading zeroes to reach a length of seven characters
val integerNumber = String.format("%07d", 31416)
println(integerNumber)
// 0031416
// Formats a floating-point number to display with a + sign and four decimal places
val floatNumber = String.format("%+.4f", 3.141592)
println(floatNumber)
// +3.1416
// Formats two strings to uppercase, each taking one placeholder
val helloString = String.format("%S %S", "hello", "world")
println(helloString)
// HELLO WORLD
// Formats a negative number to be enclosed in parentheses, then repeats the same number in a different format (without parentheses) using `argument_index$`.
val negativeNumberInParentheses = String.format("%(d means %1\$d", -31416))
println(negativeNumberInParentheses)
//(31416) means -31416
}
|
- Be careful when using the String.format() function because it can be easy to mismatch the number or position of the arguments with their corresponding placeholders.
Arrays
- An array is a data structure that holds a fixed number of values of the same type or its subtypes. The most common type of array in Kotlin is the object-type
array
, represented by the Array
class.
When to use arrays
- Use arrays in Kotlin when you have specialized low-level requirements that you need to meet. For example, if you have performance requirements beyond what is needed for regular applications, or you need to build custom data structures. If you donβt have these sorts of restrictions, use
collections
instead. Collections have the following benefits compared to arrays:- Collections can be read-only, which gives you more control and allows you to write robust code that has a clear intent.
- It is easy to add or remove elements from collections. In comparison, arrays are fixed in size. The only way to add or remove elements from an array is to create a new array each time, which is very inefficient:
1
2
3
4
5
6
7
8
9
| fun main() {
var riversArray = arrayOf("Nile", "Amazon", "Yangtze")
// Using the += assignment operation creates a new riversArray,
// copies over the original elements and adds "Mississippi"
riversArray += "Mississippi"
println(riversArray.joinToString())
// Nile, Amazon, Yangtze, Mississippi
}
|
- You can use the
equality operator (==)
to check if collections are structurally equal. You canβt use this operator for arrays. Instead, you have to use special functions π΅.
For more information on arrays, read the official documentation.