Условия и циклы
Условное выражение if
В языке Kotlin if
является выражением, т.е. оно возвращает значение.
Это позволяет отказаться от тернарного оператора (условие ? условие истинно : условие ложно
), потому что обычному if
вполне по силам его заменить.
// обычное использование
var max = a
if (a < b) max = b
// с блоком else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// в виде выражения
val max = if (a > b) a else b
“Ветви” выражения if
могут быть блоками, т.е. содержать несколько строк кода, при этом последнее выражение является
значением блока:
val max = if (a > b) {
print("возвращаем a")
a
} else {
print("возвращаем b")
b
}
Если вы используете if
в качестве выражения (например, возвращая его значение или присваивая его переменной), то
использование ветки else
является обязательным.
Условное выражение when
when
определяет условное выражение с несколькими “ветвями”. Оно похоже на оператор switch
, присутствующий в
C-подобных языках.
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // обратите внимание на блок
print("x не равен ни 1, ни 2")
}
}
when
последовательно сравнивает свой аргумент со всеми указанными значениями, пока не выполнится какое-либо из условий
ветвей.
when
можно использовать и как выражение, и как оператор. При использовании его в виде выражения значение первой ветки,
удовлетворяющей условию, становится значением всего выражения. При использовании в виде оператора значения отдельных
веток отбрасываются. В точности как if
: каждая ветвь может быть блоком и её значением является значение последнего
выражения блока.
Значение ветки else
вычисляется в том случае, когда ни одно из условий в других ветках не удовлетворено.
Если when
используется как выражение, то ветка else
является обязательной, за исключением случаев, в которых
компилятор может убедиться, что ветки покрывают все возможные значения. Так происходит, например с записями
класса enum
и с подтипами sealed
(изолированных) классов.
enum class Bit {
ZERO, ONE
}
val numericValue = when (getRandomBit()) {
Bit.ZERO -> 0
Bit.ONE -> 1
// 'else' не требуется, потому что все случаи учтены
}
В операторах when
ветка else
является обязательной в следующих условиях:
when
имеет объект типаBoolean
,enum
,sealed
или их nullable-аналоги;- ветки
when
не охватывают все возможные случаи для этого объекта.
enum class Color {
RED, GREEN, BLUE
}
when (getColor()) {
Color.RED -> println("red")
Color.GREEN -> println("green")
Color.BLUE -> println("blue")
// 'else' не требуется, потому что все случаи учтены
}
when (getColor()) {
Color.RED -> println("red") // нет веток для GREEN и BLUE
else -> println("not red") // 'else' обязателен
}
Если для нескольких значений выполняется одно и то же действие, то условия можно перечислять в одной ветке через запятую.
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
Помимо констант в ветках можно использовать произвольные выражения.
when (x) {
s.toInt() -> print("s encodes x")
else -> print("s does not encode x")
}
Также можно проверять вхождение аргумента в интервал in
или !in
или его наличие в коллекции:
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
Помимо этого Kotlin позволяет с помощью is
или !is
проверить тип аргумента. Обратите внимание,
что благодаря умным приведениям вы можете получить доступ к методам и свойствам типа без
дополнительной проверки.
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
when
удобно использовать вместо цепочки условий вида if
-else
if
.
При отсутствии аргумента условия работают как простые логические выражения, а тело ветки выполняется при его истинности.
when {
x.isOdd() -> print("x is odd")
y.isEven() -> print("y is even")
else -> print("x+y is odd")
}
Можно получать переменную внутри when
условия по следующему синтаксису:
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
Такая переменная, объявленная внутри условия when
может быть видна только внутри тела этого when
.
Цикл for
Цикл for
обеспечивает перебор всех значений, поставляемых итератором. Он эквивалентен циклу foreach
в таких языках,
как C#.
for (item in collection) print(item)
Телом цикла может быть блок кода.
for (item: Int in ints) {
// ...
}
Как отмечено выше, цикл for
позволяет проходить по всем элементам объекта, имеющего итератор, например:
- обладающего внутренней или внешней функцией
iterator()
, возвращаемый тип которойIterator<>
:- обладает внутренней или внешней функцией
next()
- обладает внутренней или внешней функцией
hasNext()
, возвращающейBoolean
.
- обладает внутренней или внешней функцией
Все три указанные функции должны быть объявлены как operator
.
Чтобы перебрать диапазон чисел, используйте выражение диапазона:
for (i in 1..3) {
println(i)
}
for (i in 6 downTo 0 step 2) {
println(i)
}
Цикл for
по диапазону или массиву компилируется в основанный на индексе цикл, который не создает объект итератора.
Если при проходе по массиву или списку необходим порядковый номер элемента, используйте следующий подход:
for (i in array.indices) {
println(array[i])
}
Также вы можете использовать библиотечную функцию withIndex
.
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
Цикл while
Тело циклов while
и do-while
выполняется до тех пор, пока их условие выполняется.
Разница между ними заключается во времени проверки условия:
while
проверяет условие и, если оно истинно, выполняет тело, а затем возвращается к проверке условия;do-while
выполняет тело и только затем проверяет условие. Если оно выполняется, цикл повторяется. Таким образом, телоdo-while
выполняется по крайней мере один раз независимо от условия.
while (x > 0) {
x--
}
do {
val y = retrieveData()
} while (y != null) // y здесь доступно!
Break и continue в циклах
Kotlin поддерживает привычные операторы break
и continue
в циклах. См. Операторы перехода.