Привет! Сегодня будет небольшая заметка про FizzBuzz. Недавно наткнулся на статью на Хабре под названием «FizzBuzz, или почему программисты не умеют программировать«. Там автор сокрушался о том, что многие программисты при приеме на работу не способы решить тривиальные задания с использованием циклов, рекурсии и т.д.
В качестве одного из примеров приводилась известная задача по написанию программы FizzBuzz, которая выводит числа от 1 до 100. По словам автора, этот простой способ для того, чтобы отфильтровывать кандидатов.
Задача FizzBuzz решение
Итак, условие гласит: «Нужно написать программу, выводящую на экран числа в пределах от 1 до 100. Если число будет кратно 3, то вместо него вывести Fizz, а если число кратно пяти — слово Buzz. При этом, если число будет кратно 15, то вывести строку Fizz Buzz». Напишем простое решение.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fun fizzBuzz() {
for (n in 1..100){
if(n % 15 == 0) {
println("Fizz Buzz = $n")
continue
} else if (n % 5 == 0) {
println("Buzz = $n")
continue
} else if (n % 3 == 0) {
println("Fizz = $n")
continue
}
println("$n")
}
}
Результат выполнения — то что надо!.
1
2
3
4
5
1
2
Fizz = 3
4
...
Готово! Но это решение не единственное. К примеру в Kotlin можно использовать оператор when
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fun fizzBuzzWhen() {
for (it in 1..100) {
when {
it % 15 == 0 -> {
println("Fizz Buzz = $it")
continue
}
it % 5 == 0 -> {
println("Buzz = $it")
continue
}
it % 3 == 0 -> {
println("Fizz = $it")
continue
}
else -> println("$it")
}
}
}
Мда… Читаемость стала хуже, и строчек прибавилось… Давайте перепишем нашу функцию, позаимствовав фичи из Java 8.
1
2
3
4
5
6
7
8
fun fizzBuzzJava() = IntStream.rangeClosed(1, 100)
.mapToObj { num: Int -> if (num % 3 == 0)
if (num % 5 == 0) "Fizz Buzz = $num"
else "Fizz = $num"
else if (num % 5 == 0) "Buzz = $num"
else num
}
.forEach { x: Serializable? -> println(x) }
Теперь разберем что да как. Одним из основных нововведений в Java 8 являются потоки — Streams. IntStream — один из интерфейсов Stream для работы с примитивами. Зачем он нужен, если хватило бы одного? Как написано в доках Stream API — примитивные «стримы» быстрее.
При помощи метода rangeClosed() создаем необходимый набор цифр от 1 до 100. Далее метод mapToObj() возвращает новый поток Stream, в котором к каждому элементу мы применяем промежуточные операции. Далее при помощи стандартного forEach выводим каждый элемент потока в консоль.
Кстати, в Kotlin тоже есть потоки — Flow, с которыми можно работать при использовании корутин. Этот способ разберем в одной из следующих статей