RxJava набирает все большую популярность в нынешнее время. На ней написаны многие библиотеки для Java и Android, а обладание знаниями в этой области стало синонимом избранности. В резюме строка с описанием того что вы спец в реактивном программировании поднимает вашу привлекательность для работодателей перед вашими конкурентами.
И вот я тоже решил присоединиться к этому течению, освоить и начать применять в своих проектах RxJava. В процессе чтения нескольких книг и статей все было абсолютно понятно. «Эти знания и правда в разы укоротят код и придадут читабельности» — думал я. Но как только книги были закончены и я сел переписывать свой проект на реактивщину — стало понятно что я не понимаю даже с чего начинать…
Еще куча времени было потрачено на практику и блуждание в операторах. Для большей эффективности я придумал себе несколько задачек, и поставил целью решить их, применяя только операторы Rx. Предлагаю вам тоже испытать свои знания!
Если вы считаете себя специалистом в этой области — открывайте IDE и попробуйте решить пять задачек. Предполагается что вы обладаете начальными знаниями и с легкостью напишете простой Observable. Только давайте условимся — не подсматривайте в решение сразу! Ведь уверенные знания рождаются только в усердной практике. В данных задачах не буду проводить описание операторов, которые были использованы. Если какие то задачи вызывают затруднения — просто остановитесь — загляните сюда и попробуйте выбрать тот оператор, который поможет вам решить нужную задачу.
Давайте начнем с очень простой задачи:
Задача 1:
У вас есть список городов, уложенный в контейнер List. Необходимо вывести его на печать.
Исходные данные:
List<String> cities = Arrays.asList("Париж", "Лондон", "Рим", "Москва");
Что в результате должны увидеть в консоли:
город Париж
город Лондон
город Рим
город Москва
Observable.from(list)
.map(s -> "город "+s)
.subscribe(System.out::println);
Задача проще простого! Уверен вы решили еще мгновенно. Давайте попробуем что нибудь посложнее.
Задача 2:
У вас есть список городов и стран, уложенных в контейнеры List. Необходимо вывести список, упорядоченный по алфавиту, в формате <название города> — столица <название страны> на печать.
Исходные данные:
List<String> cities = Arrays.asList("Париж", "Лондон", "Рим", "Москва");
List<String> countries = Arrays.asList("Франция", "Англия", "Италия", "Россия");
Что в результате ожидаем увидеть в консоли:
Лондон — столица Англии
Москва — столица России
Париж — столица Франции
Рим — столица Италии
Observable.from(countries)
.map(s -> s.substring(0, s.length() - 1).concat("и"))
.zipWith(cities, (country, city) -> city+" - столица "+country)
.toSortedList()
.flatMap(Observable::from)
.subscribe(System.out::println);
Задача 3:
Вывести на печать все простые числа меньше ста.
Для справки:
Вдруг кто забыл — простые числа те, что делятся без остатка только на себя и на единицу. 0 и 1 за простые числа принято не считать
Исходные данные:
Для облегчения задачи — метод для определения простого числа:
private boolean isPrime(int n) {
for(int i=2; i<n; i++) {
if (n % i == 0) return false;
}
return true;
}
Что в результате должны увидеть в консоли:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
Observable.range(0, Integer.MAX_VALUE)
.skip(2)
.filter(this::isPrime)
.takeWhile(integer -> integer < 100)
.map(String::valueOf)
.reduce((s1, s2) -> s1+" "+s2)
.subscribe(System.out::println);
Задача 4:
Определить какие числа, в промежутку от 1 до 20 делятся без остатка на 3 и 7 соответственно.
Исходные данные:
Для справки — для разделения на разные типы делителей воспользовался вот таким методом:
private int whatDivider(int n) {
if (n % 3 == 0) return 3;
if (n % 7 == 0) return 7;
return 0;
}
Что в результате должны увидеть в консоли:
Делится без остатка на 3: 3 6 9 12 15 18
Делится без остатка на 7: 7 14
Observable.range(1, 20)
.groupBy(this::whatDivider)
.filter(observable -> observable.getKey() != 0)
.subscribe(observable -> observable
.map(String::valueOf)
.reduce((s1, s2) -> s1+" "+s2)
.map(s -> "Делится без остатка на "+observable.getKey()+": "+s)
.subscribe(System.out::println));
Задача 5:
Необходимо найти сумму первых десяти членов ряда Фибоначчи.
Для справки:
Ряд Фибоначчи — каждое последующее число равно сумме двух предыдущих чисел, и первые десять членов ряда его — 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, и их сумма равна 88.
Исходные данные:
Для решения задачи я воспользовался написанным рядом классом Pair:
private static class Pair {
final int n1;
final int n2;
Pair(int n1, int n2) {
this.n1 = n1;
this.n2 = n2;
}
}
Если получится обойтись без него — будет рад поучиться у вас!
Что в результате должны увидеть в консоли:
88
Observable.range(0, 9)
.map(integer -> new Pair(0, 1))
.scan((source, result) -> new Pair(source.n2, source.n1 + source.n2))
.map(pair -> pair.n2)
.reduce((integer, integer2) -> integer + integer2)
.subscribe(System.out::println);
Если ваши решения получились лаконичнее, чем приведены здесь — пишите в комментариях, буду рад подчерпнуть новые способы, так как я не претендую на абсолютные знания в области Rx и сам только учусь. Пишите если вам понравилось, на примете есть еще цикл задачек с использованием кастомных операторов, и если вам будет интересно — попробую продолжить идею в следующих статьях.
Автор: Netyaga