In Kotlin, everything is an object in the sense that we can call member functions and properties on any variable. Some types can have a special internal representation - for example, numbers, characters and booleans can be represented as primitive values at runtime - but to the user they look like ordinary classes. In this section we describe the basic types used in Kotlin: numbers, booleans, characters, strings, and arrays.
Kotlin provides a set of built-in types that represent numbers.
For integer numbers, there are four types with different sizes and, hence, value ranges.
|Type||Size (bits)||Min value||Max value|
|Int||32||-2,147,483,648 (-2 31)||2,147,483,647 (2 31- 1)|
|Long||64||-9,223,372,036,854,775,808 (-2 63)||9,223,372,036,854,775,807 (2 63- 1)|
All variables initialized with integer values not exceeding the maximum value of
Int have the inferred type
Int. If the initial value exceeds this value, then the type is
Long. To specify the
Long value explicitly, append the suffix
L to the value.
For real numbers, Kotlin provides floating-point types
Double. According to the IEEE 754 standard, floating point types differ by their decimal place, that is, how many decimal digits they can store.
Float reflects the IEEE 754 single precision, while
Double provides double precision.
|Type||Size (bits)||Significant bits||Exponent bits||Decimal digits|
You can initialize
Float variables with numbers having a fractional part. It's separated from the integer part by a period (
.) For variables initialized with fractional numbers, the compiler infers the
To explicitly specify the
Float type for a value, add the suffix
F. If such a value contains more than 6-7 decimal digits, it will be rounded.
Note that unlike some other languages, there are no implicit widening conversions for numbers in Kotlin. For example, a function with a
Double parameter can be called only on
Double values, but not
Int, or other numeric values.
To convert numeric values to different types, use Explicit conversions.
There are the following kinds of literal constants for integral values:
Longs are tagged by a capital
Kotlin also supports a conventional notation for floating-point numbers:
Doubles by default:
Floats are tagged by
You can use underscores to make number constants more readable:
Numbers representation on the JVM
On the JVM platform, numbers are stored as primitive types:
double, and so on. Exceptions are cases when you create a nullable number reference such as
Int? or use generics. In these cases numbers are boxed in Java classes
Double, and so on.
Note that nullable references to the same number can be different objects:
All nullable references to
a are actually the same object because of the memory optimization that JVM applies to
Integer s between
127. It doesn't apply to the
b references, so they are different objects.
On the other hand, they are still equal:
Due to different representations, smaller types are not subtypes of bigger ones. If they were, we would have troubles of the following sort:
So equality would have been lost silently, not to mention identity.
As a consequence, smaller types are NOT implicitly converted to bigger types. This means that assigning a value of type
Byte to an
Int variable requires an explicit conversion.
All number types support conversions to other types:
In many cases, there is no need in explicit conversions because the type is inferred from the context, and arithmetical operations are overloaded for appropriate conversions, for example:
Kotlin supports the standard set of arithmetical operations over numbers:
%. They are declared as members of appropriate classes.
You can also override these operators for custom classes. See Operator overloading for details.
Division of integers
Division between integers numbers always returns an integer number. Any fractional part is discarded.
This is true for a division between any two integer types.
To return a floating-point type, explicitly convert one of the arguments to a floating-point type.
Kotlin provides a set of bitwise operations on integer numbers. They operate on the binary level directly with bits of the numbers' representation. Bitwise operations are represented by functions that can be called in infix form. They can be applied only to
Here is the complete list of bitwise operations:
shl(bits)– signed shift left
shr(bits)– signed shift right
ushr(bits)– unsigned shift right
and(bits)– bitwise and
or(bits)– bitwise or
xor(bits)– bitwise xor
inv()– bitwise inversion
Floating-point numbers comparison
The operations on floating-point numbers discussed in this section are:
a == band
a != b
a < b,
a > b,
a <= b,
a >= b
Range instantiation and range checks:
x in a..b,
x !in a..b
When the operands
b are statically known to be
Double or their nullable counterparts (the type is declared or inferred or is a result of a smart cast ), the operations on the numbers and the range that they form follow the IEEE 754 Standard for Floating-Point Arithmetic.
However, to support generic use cases and provide total ordering, when the operands are not statically typed as floating point numbers (e.g.
Comparable<...>, a type parameter), the operations use the
compareTo implementations for
Double, which disagree with the standard, so that:
NaNis considered equal to itself
NaNis considered greater than any other element including
-0.0is considered less than
In addition to integer types, Kotlin provides the following types for unsigned integer numbers:
UByte: an unsigned 8-bit integer, ranges from 0 to 255
UShort: an unsigned 16-bit integer, ranges from 0 to 65535
UInt: an unsigned 32-bit integer, ranges from 0 to 2^32 - 1
ULong: an unsigned 64-bit integer, ranges from 0 to 2^64 - 1
Unsigned types support most of the operations of their signed counterparts.
Unsigned types are implemented using feature that's not yet stable, namely inline classes.
Unsigned arrays and ranges
Same as for primitives, each of unsigned type has corresponding type that represents arrays of that type:
UByteArray: an array of unsigned bytes
UShortArray: an array of unsigned shorts
UIntArray: an array of unsigned ints
ULongArray: an array of unsigned longs
Same as for signed integer arrays, they provide similar API to
Array class without boxing overhead.
When you use unsigned arrays, you'll get a warning that indicates that this feature is not stable yet. To remove the warning, opt in using the
@ExperimentalUnsignedTypes annotation. It's up to you to decide if your clients have to explicitly opt-in into usage of your API, but keep in mind that unsigned array are not a stable feature, so API which uses them can be broken by changes in the language. Learn more about opt-in requirements.
Ranges and progressions are supported for
ULong by classes
ULongProgression. Together with the unsigned integer types, these classes are stable.
To make unsigned integers easier to use, Kotlin provides an ability to tag an integer literal with a suffix indicating a specific unsigned type (similarly to
Utag unsigned literals. The exact type is determined based on the expected type. If no expected type is provided, compiler will use
ULongdepending on the size of literal.
ULexplicitly tag literal as unsigned long.
See language proposal for unsigned types for technical details and further discussion.
Boolean represents boolean objects that can have two values:
Boolean has a nullable counterpart
Boolean? that also has the
Built-in operations on booleans include:
||– disjunction (logical OR)
&&– conjunction (logical AND)
!- negation (logical NOT)
&& work lazily.
Characters are represented by the type
Char. Character literals go in single quotes:
Special characters start from an escaping backslash
\. The following escape sequences are supported:
To encode any other character, use the Unicode escape sequence syntax:
If a value of character variable is a digit, you can explicitly convert it to an
Int number using the
Strings in Kotlin are represented by the type
String. 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
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.
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:
Note that in most cases using string templates or raw strings is preferable to string concatenation.
Kotlin has two types of string literals:
escaped strings that may contain escaped characters
raw strings that can contain newlines and arbitrary text
Here's an example of an escaped string:
Escaping is done in the conventional way, with a backslash (
\ ). See Characters above for the list of supported escape sequences.
A raw string is delimited by a triple quote (
""" ), contains no escaping and can contain newlines and any other characters:
To remove leading whitespace from raw strings, use the
| is used as margin prefix, but you can choose another character and pass it as a parameter, like
String literals may contain template expressions - pieces of code that are evaluated and whose results are concatenated into the string. A template expression starts with a dollar sign (
$) and consists of either a name:
or an expression in curly braces:
You can use templates both in raw and escaped strings. To insert the
$ character in a raw string (which doesn't support backslash escaping) before any symbol, which is allowed as a beginning of an identifier, use the following syntax:
Arrays in Kotlin are represented by the
Array class. It has
set functions that turn into
 by operator overloading conventions, and the
size property, along with other useful member functions:
To create an array, use the function
arrayOf() and pass the item values to it, so that
arrayOf(1, 2, 3) creates an array
[1, 2, 3]. Alternatively, the
arrayOfNulls() function can be used to create an array of a given size filled with
Another option is to use the
Array constructor that takes the array size and the function that returns values of array elements given its index:
As we said above, the
 operation stands for calls to member functions
Arrays in Kotlin are invariant. This means that Kotlin does not let us assign an
Array<String> to an
Array<Any>, which prevents a possible runtime failure (but you can use
Array<out Any>, see Type Projections ).
Primitive type arrays
Kotlin also has classes that represent arrays of primitive types without boxing overhead:
IntArray, and so on. These classes have no inheritance relation to the
Array class, but they have the same set of methods and properties. Each of them also has a corresponding factory function: