format()
function For example, instead of writing val n: Int = 3
, we can simply write
val n = 3
You can still declare the type of a variable explicitly. In that case the compiler checks that the declared type agrees with the type of the initializing expresssion, and gives an error message if they don’t.
Array<B>
.Array<String>
, Array<Array<Int>>
, etc. Thus, array types allow us to construct an infinite number of new types.a[3]
is the element of a
at index 3.BooleanArray
CharArray
ByteArray
ShortArray
IntArray
LongArray
FloatArray
DoubleArray
Kotlin does not provide a way to write array literals. The only way to create a new array is by calling some special function. Here are example declarations of arrays of primitive types:
val a1 = IntArray(5)
val a2 = intArrayOf(3, 5, 2)
a1
to be an IntArray
, creates an array of 5 Int
s, initializes all elements to zero, then makes a1
point to the beginning of this array.a2
to be an IntArray
, creates an array of 3 elements, initializes the 0th element to 3, the 1st element to 5, and the 2nd element to 2, then makes a2
point to the beginning of this array.You will learn later that IntArray(5)
is calling an array constructor while intArrayOf(3, 5, 2)
is calling a factory function.
BooleanArray(n)
for constructing a BooleanArray
of size n and initializing all elements to false
ByteArray(n)
for constructing a ByteArray
of size n and initializing all elements to 0
ShortArray(n)
for constructing a ShortArray
of size n and initializing all elements to 0
LongArray(n)
for constructing a LongArray
of size n and initializing all elements to 0
FloatArray(n)
for constructing a FloatArray
of size n and initializing all elements to 0.0F
DoubleArray(n)
for constructing a DoubleArray
of size n and initializing all elements to 0.0
booleanArrayOf(...)
, byteArrayOf(...)
, shortArrayOf(...)
, longArrayOf(...)
, floatArrayOf(...)
, and doubleArrayOf(...)
for creating and initializing arrays of the other primitive types to the values you provide as arguments.Here is an example of performing various operations on arrays.
val a = intArrayOf(0, 1, 2, 3, 4)
println("originally a = ${a.joinToString()}")
for (i in 0 until a.size)
a[i] *= a[i]
println("after the for loop, a is now = ${a.joinToString()}")
val b = a
println("originally b = ${b.joinToString()}")
b[0] = b[2] - b[1]
println("after modifying b[0], b = ${b.joinToString()}")
println("and a = ${a.joinToString()}")
Executing the code gives this output
originally a = 0, 1, 2, 3, 4
after the for loop, a is now = 0, 1, 4, 9, 16
originally b = 0, 1, 4, 9, 16
after modifying b[0], b = 3, 1, 4, 9, 16
and a = 3, 1, 4, 9, 16
When we execute the code snippet
val b = a
where a, b are variables of the same reference type, the variable b
is made to point to the same object that a
is pointing to. Modifying the content that b
points to will change the content that a
points to as well since they are the same!
The lesson here is that being a val
variable does not mean the data itself is immutable. It just means that you can’t change that variable to make it reference something else.
for
loop to walk through them to perform some task on their elements without having to refer to their indexes at all.For example, you can print all the elements by
val a = intArrayOf(1, 2, 3)
for (e in a)
println(e)
If you also want the indexes, you can write
for ((i, e) in a.withIndex())
println("$i: $e")
instead of the usual
for (i in 0 until a.size)
println("$i: ${a[i]}")
String
value is essentially a sequence of Char
values.String
is not a primitive type, it is so heavily used that Kotlin provides literals for it like for the primitive types. It also has the concatenation operator +
that returns another string that results from appending the second string to the first.String
is an immutable type. You can’t change its data.size
property; it has a length
property instead.Here is some code that manipulates strings.
val message = "Hello"
println(message + " World")
println(message.length)
for (c in message)
println(c)
for (i in 0 until message.length)
println(message[i])
for ((i, c) in message.withIndex())
println("$i: ${message[i]}")
Strings can be compared using these operators as well:
== != < <= > >= in !in
Comparison is done in dictionary order.
Char
data represents 16-bit Unicode characters. The Unicode characters are supposed to represent all the symbols used in all languages in the world, whether the language is alphabet-based or not, and then some. However, some Unicode characters are either not printable or not easy to see when printed; Kotlin provides a special notation called escape sequences for writing these characters.These are the escape sequences and their meanings:
Escape Sequence Represented Character
\t Tab
\b Backspace
\n Newline
\r Carriage Return
\' Single Quotation Mark
\" Double Quotation Mark
\\ Backslash
\$ Dollar sign
You can also write any Unicode character using the escape sequence syntax like ‘\uFF00’.
A raw string does not understand escape sequences. Instead of using just one quotation mark "
to enclose a string, a raw string uses three quotation marks """
like this:
"""Roses are red,
Violets are blue,
sugar is sweet,
And so are you."""
If you try to print out the raw string in the last slide you’ll find it has undesirable blanks at the beginning of the last 3 lines. To eliminate them, Kotlin provides a function trimMargin()
so we can write the above raw string as
"""
|Roses are red,
|Violets are blue,
|sugar is sweet,
|And so are you.
""".trimMargin()
The default margin prefix is the | character but you can provide your own and pass it in as argument to trimMargin()
like this:
"""
>Roses are red,
>Violets are blue,
>sugar is sweet,
>And so are you.
""".trimMargin(">")
For example,
val name = "John"
val age = 20
println("Last year $name was ${age-1} years old.")
will print
Last year John was 19 years old.
The escape sequences can be used both within character literals and regular (non raw) string literals. Escape sequences do not work within raw strings but we can write the newline character directly within it. Therefore, the two string variables s1
and s2
below have the same content.
val s1 = "One\nTwo\n\Three"
val s2 = """One
Two
Three"""
However, raw strings don’t treat backslash in a special way, so there must be some other way to specify the dollar sign within raw strings. We can do it this way
"""That item costs ${'$'}20."""
There are lots of string functions that you will find helpful in your programming. We list some of them here.
indexOf( contains(s: CharSequence): Boolean
char: Char, compareTo(other: String,
startIndex: Int = 0, ignoreCase: Boolean = false): Int
ignoreCase: Boolean = false startsWith(prefix: String): Boolean
): Int endsWith(suffix: String): Boolean
isBlank(): Boolean replace(
isNotBlank(): Boolean oldChar: Char,
isEmpty(): Boolean newChar: Char
isNotEmpty(): Boolean ): String
last(): Char replace(
lastIndexOf( target: CharSequence,
char: Char, replacement: CharSequence
startIndex: Int = lastIndex, ): String
ignoreCase: Boolean = false toLowerCase(): String
): Int toUpperCase(): String
repeat(n: Int): String toBoolean(): Boolean
reversed(): String toByte(): Byte
substring(startIndex: Int): String toShort(): Short
substring( toInt(): Int
startIndex: Int, toLong(): Long
endIndex: Int ...
): String trim(): String
Let’s look at an example of how to scan the standard input. Suppose our input consists of a sequence of lines that look like this:
Albania 2.99 11100
Belgium 10.43 11787
Cuba 11.09 42803
Denmark 5.53 16639
We can use the scanner to parse the data like this.
val scanner = java.util.Scanner(System.`in`)
while (scanner.hasNext()) {
val country = scanner.next()
val population = scanner.nextDouble()
val area = scanner.nextInt()
// process data for this country here
}
Here is a list of some useful Scanner functions:
hasNext() next()
hasNextLine() nextLine()
hasNextBoolean() nextBoolean()
hasNextByte() nextByte()
hasNextShort() nextShort()
hasNextInt() nextInt()
hasNextLong() nextLong()
hasNextFloat() nextFloat()
hasNextDouble() nextDouble()
String.format
function.Let’s first learn the concept of a format specifier. It’s a string consisting of one required part and three optional parts
"[flags][width][.precision]type"
Only type is required.
This table shows most of the possible types and their meanings.
type specifier | meaning |
---|---|
%b | Boolean |
%c | Char |
%d | integral type |
%e | floating point type in scientific notation |
%f | floating point type in decimal format |
%g | floating point type in either decimal or scientific notation, depending on value |
%n | line separator |
%s | string |
%x | integer in hex |
%% | The % symbol itself |
This table shows examples of format specifiers and their effect on the output string.
type | code | typical literal | sample format strings | converted string values for output |
---|---|---|---|---|
Int | d | 512 | “%14d” | “ 512” |
Long | d | 512L | “-14d” | “512 ” |
Float | f | 1595.1680010754388F | “14.2f” | “ 1595.17” |
Double | f | 1595.1680010754388 | “.7f” | “1595.1680011” |
Double | e | 1595.1680010754388 | “14.4e” | “ 15952e+03” |
String | s | “Hello, world” | “14s” | “ Hello, world” |
String | s | “Hello, world” | “-14s” | “Hello, world ” |
String | s | “Hello, world” | “-14.5s” | “Hello ” |
format
is a String function. You call it using the . operator on the string whose content is the format specifier, and provide it with as many arguments as specified in the specifier. Examples:
"%s %d pounds.".format("The baby weighs", 3)
gives the string
"The baby weighs 3 pounds."