Commit 7634de0e authored by Julien SADAOUI's avatar Julien SADAOUI
Browse files

feat: rxjava level 5

parent cec16093
......@@ -31,22 +31,18 @@ public class Level1 {
* <li>Chick Hicks</li>
* <li>The King</li>
* <li>Completed</li>
* <li>Stop</li>
* </ul>
* <p>
* REMARQUE:
* la sortie du flux est synchrone !
*/
private static void exercise1() {
log.info("Start Level1/Exercise1");
Observable.just("Flash McQueen", "Chick Hicks", "The King")
.subscribe(
log::info,
(error) -> log.error("Error: {}", error.getMessage()),
() -> log.info("Completed"));
log.info("Stop");
}
/**
......@@ -59,13 +55,11 @@ public class Level1 {
* <li>Martin</li>
* <li>Sally Carrera</li>
* <li>Completed</li>
* <li>Stop</li>
* </ul>
* <p>
* REMARQUE: La sortie du flux est encore synchrone, parce que la liste est consommée de manière synchrone
*/
private static void exercise2() {
var data = List.of("Flash McQueen", "Martin", "Sally Carrera");
log.info("Start Level1/Exercise2");
......@@ -74,8 +68,6 @@ public class Level1 {
log::info,
(error) -> log.error("Error: {}", error.getMessage()),
() -> log.info("Completed"));
log.info("Stop");
}
/**
......@@ -86,26 +78,23 @@ public class Level1 {
* <li>Start Level1/Exercise3</li>
* <li>Winner: Flash McQueen</li>
* <li>Completed</li>
* <li>Stop</li>
* </ul>
* <p>
* REMARQUE: La tâche est exécutée de manière synchrone, le {@link Thread} principal attend le résultat de la tâche.
*/
private static void exercise3() {
log.info("Start Level1/Exercise3");
Callable<String> callable = () -> {
Helpers.sleep(5, TimeUnit.SECONDS);
return "Flash McQueen";
};
log.info("Start Level1/Exercise3");
Observable.fromCallable(callable)
.subscribe(
winner -> log.info("Winner: {}", winner),
(error) -> log.error("Error: {}", error.getMessage()),
() -> log.info("Completed"));
log.info("Stop");
}
/**
......@@ -116,23 +105,20 @@ public class Level1 {
* <li>Start Level1/Exercise4</li>
* <li>Winner: The king</li>
* <li>Completed</li>
* <li>Stop</li>
* </ul>
* <p>
* REMARQUE: La tâche est encore exécutée de manière synchrone !
*/
public static void exercise4() {
log.info("Start Level1/Exercise4");
var future = Executors.newSingleThreadScheduledExecutor().schedule(() -> "The king", 3, TimeUnit.SECONDS);
log.info("Start Level1/Exercise4");
Observable.fromFuture(future)
.subscribe(
winner -> log.info("Winner: {}", winner),
(error) -> log.error("Error: {}", error.getMessage()),
() -> log.info("Completed"));
log.info("stop");
}
......
......@@ -29,7 +29,6 @@ public class Level2 {
* <li>Next: Martin</li>
* <li>Next: Sally Carrera</li>
* <li>Completed</li>
* <li>Stop</li>
* </ul>
*/
public static void exercise1() {
......@@ -41,7 +40,6 @@ public class Level2 {
.doOnNext(item -> log.info("Next: " + item))
.doOnComplete(() -> log.info("Completed"))
.subscribe();
log.info("Stop");
}
/**
......@@ -54,17 +52,15 @@ public class Level2 {
* <li>Next: Flash McQueen</li>
* <li>Next: The King</li>
* <li>Error: Unknown Character !</li>
* <li>Stop</li>
* </ul>
* <p>
* REMARQUE:
* Une fois l'erreur déclenchée, plus aucun élément n'est émis. La méthode `onComplete n'est pas appelée.
*/
public static void exercise2() {
log.info("Start Level2/Exercise2");
var data = List.of("Flash McQueen", "The King", "Unknown Character", "Martin", "Sally Carrera");
log.info("Start Level2/Exercise2");
Observable.fromIterable(data)
.map(item -> {
if (item.startsWith("Unknown")) {
......@@ -76,8 +72,6 @@ public class Level2 {
.doOnComplete(() -> log.info("Never called !"))
.doOnError(err -> log.error("Error: " + err.getMessage()))
.subscribe();
log.info("Stop");
}
/**
......@@ -97,22 +91,18 @@ public class Level2 {
* <li>Next: The King</li>
* <li>Next: Chick Hicks</li>
* <li>Completed</li>
* <li>Stop</li>
* </ul>
*/
public static void exercise3() {
log.info("Start Level2/Exercise3");
var data = List.of("Flash McQueen", "The King", "Chick Hicks");
log.info("Start Level2/Exercise3");
Observable.fromIterable(data)
.subscribe(
item -> log.info("Next: " + item),
error -> log.error("Error: {}", error.getMessage()),
() -> log.info("Completed")
);
log.info("Stop");
}
/**
......@@ -129,12 +119,10 @@ public class Level2 {
* <li>Next: Martin</li>
* <li>Next: Sally Carrera</li>
* <li>Completed</li>
* <li>Stop</li>
* </ul>
*
*/
public static void exercise4() {
log.info("Start Level2/Exercise4");
Observable<String> observable = Observable.create(subscriber -> {
......@@ -152,8 +140,6 @@ public class Level2 {
error -> log.error("Error: {}", error.getMessage()),
() -> log.info("Completed")
);
log.info("Stop");
}
}
......@@ -27,7 +27,6 @@ public class Level3 {
*
* <ul>
* <li>Start Level3/Exercise1</li>
* <li>Stop</li>
* <li>[1] Next: Flash McQueen</li>
* <li>[1] Next: The King</li>
* <li>[1] Next: Chick Hicks</li>
......@@ -48,7 +47,6 @@ public class Level3 {
log.info("Start Level3/Exercise1");
Observable<String> observable = Observable.just("Flash McQueen", "The King", "Chick Hicks");
log.info("Stop");
observable.subscribe(
item -> log.info("[1] Next: {}", item),
......@@ -71,7 +69,6 @@ public class Level3 {
*
* <ul>
* <li>Start Level3/Exercise2</li>
* <li>Stop</li>
* <li>[1] Next: Date1 -> {generated_date}</li>
* <li>[1] Next: Date2 -> {generated_date}</li>
* <li>[1] Next: Date3 -> {generated_date}</li>
......@@ -97,7 +94,6 @@ public class Level3 {
subscriber.onNext("Date3 -> " + LocalDateTime.now());
subscriber.onComplete();
});
log.info("Stop");
observable.subscribe(
item -> log.info("[1] Next: {}", item),
......@@ -126,7 +122,6 @@ public class Level3 {
*
* <ul>
* <li>Start Level3/Exercise1</li>
* <li>Stop</li>
* <li>[1] Next: 1</li>
* <li>[1] Next: 2</li>
* <li>[1] Next: 3</li>
......@@ -151,7 +146,6 @@ public class Level3 {
error -> log.error("[1] Error: {}", error.getMessage()),
() -> log.info("[1] Completed")
);
log.info("Stop");
Helpers.sleep(3, TimeUnit.SECONDS);
......
......@@ -5,11 +5,6 @@ import io.reactivex.Maybe;
import io.reactivex.Single;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicBoolean;
/**
*
*/
@Slf4j
public class Level4 {
......@@ -28,9 +23,8 @@ public class Level4 {
* <p><p>
* Note : sortie attendue
* <li>
* <ul>Start Level4/exercise1</ul>
* <ul>Start Level4/Exercise1</ul>
* <ul>Value: Flash McQueen</ul>
* <ul>Stop</ul>
* </li>
* <p>
* Remarque : Les méthodes {@link io.reactivex.Observable#doOnNext} et {@link io.reactivex.Observable#doOnComplete}
......@@ -41,7 +35,6 @@ public class Level4 {
Single.just("Flash McQueen")
.doOnSuccess(item -> log.info("Value: " + item))
.subscribe();
log.info("Stop");
}
/**
......@@ -50,20 +43,18 @@ public class Level4 {
* <p><p>
* Note : sortie attendue
* <li>
* <ul>Start Level4/exercise2</ul>
* <ul>Start Level4/Exercise2</ul>
* <ul>Value: Flash McQueen</ul>
* <ul>Stop</ul>
* </li>
* <p>
* Remarque : La méthode {@link Maybe#doOnSuccess} notifie le consommateur de la valeur émise.
*/
public static void exercise2() {
log.info("Start Level4/exercise2");
log.info("Start Level4/Exercise2");
Maybe.just("The King")
.doOnSuccess(value -> log.info("Value: {}", value))
.doOnComplete(() -> log.info("Completed"))
.subscribe();
log.info("Stop");
}
/**
......@@ -72,33 +63,37 @@ public class Level4 {
* <p><p>
* Note : sortie attendue
* <li>
* <ul>Start Level4/exercise2</ul>
* <ul>Start Level4/Exercise3</ul>
* <ul>Completed</ul>
* <ul>Stop</ul>
* </li>
* <p>
* Remarque : La méthode {@link Maybe#doOnComplete} notifie le consommateur de la fin du flux vide. Cette méthode
* est appelée seulement quand un {@link Maybe} est vide.
*/
public static void exercise3() {
log.info("Start Level4/exercise3");
log.info("Start Level4/Exercise3");
Maybe.empty()
.doOnSuccess(value -> log.info("Value: {}", value))
.doOnComplete(() -> log.info("Completed"))
.subscribe();
log.info("Stop");
}
/**
* Crée un {@link Completable} qui déclenche une action. Cette action n'émet pas de valeur.
*
* <p><p>
* Note : sortie attendue
* <li>
* <ul>Start Level4/Exercise4</ul>
* <ul>Action !</ul>
* <ul>Completed</ul>
* </li>
* <p>
*/
public static void exercise4() {
AtomicBoolean flag = new AtomicBoolean();
log.info("Start Level4/exercise4");
Completable.fromAction(() -> log.info("Action !"))
.doOnComplete(() -> log.info("Completed"))
.subscribe();
log.info("Stop");
}
}
package fr.ippon.codingdojo.reactive;
import fr.ippon.codingdojo.reactive.util.Helpers;
import io.reactivex.Flowable;
import io.reactivex.Single;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
public class Level5 {
public static void main(String[] args) {
exercise1();
exercise2();
exercise3();
exercise4();
exercise5();
exercise6();
exercise7();
exercise8();
exercise9();
}
/**
* Génére un flux de données de 1 à 20, ignore les 5 premiers éléments et filtre les nombres pair.
*
* <p><p>
* Note: Sortie attendue
*
* <ul>
* <li>Start Level5/Exercise1</li>
* <li>Next: 6</li>
* <li>Next: 8</li>
* <li>Next: 10</li>
* <li>Next: 12</li>
* <li>Next: 14</li>
* <li>Next: 16</li>
* <li>Next: 18</li>
* <li>Next: 20</li>
* <li>Completed</li>
* </ul>
*/
public static void exercise1() {
log.info("Start Level5/Exercise1");
Flowable.range(1, 20)
.skip(5)
.filter(value -> value % 2 == 0)
.doOnComplete(() -> log.info("Completed"))
.subscribe(value -> log.info("Next: {}", value));
}
/**
* Recherche un personnage qui n'existe pas dans le flux et retourne une valeur par défaut.
*
* <p><p>
* Note: Sortie attendue
*
* <ul>
* <li>Start Level5/Exercise2</li>
* <li>Next: Unknown Character !</li>
* <li>Completed</li>
* </ul>
*/
public static void exercise2() {
log.info("Start Level5/Exercise2");
var data = List.of("Flash McQueen", "The King");
Flowable.fromIterable(data)
.filter(character -> character.equals("Chick Hicks"))
.defaultIfEmpty("Unknown Character !")
.doOnComplete(() -> log.info("Completed"))
.subscribe(value -> log.info("Next: {}", value));
}
/**
* Convertit en majuscules le flux de chaines de caractères.
*
* <p><p>
* Note: Sortie attendue
*
* <ul>
* <li>Start Level5/Exercise3</li>
* <li>Next: FLASH MCQUEEN</li>
* <li>Next: THE KING</li>
* <li>Next: MARTIN</li>
* <li>Next: SALLY CARRERA</li>
* <li>Completed</li>
* </ul>
*/
public static void exercise3() {
log.info("Start Level5/Exercise3");
var data = List.of("Flash McQueen", "The King");
Flowable.fromIterable(data)
.map(String::toUpperCase)
.doOnComplete(() -> log.info("Completed"))
.subscribe(value -> log.info("Next: {}", value));
}
/**
* Calcule la somme des nombres du flux et affiche les valeurs intermédiaires.
* <p><p>
* Note: Sortie attendue
* <ul>
* <li>Start Level5/Exercise4</li>
* <li>Next: 1</li>
* <li>Next: 3</li>
* <li>Next: 6</li>
* <li>Next: 10</li>
* <li>Next: 15</li>
* <li>Completed</li>
* </ul>
*
* Note: La méthode {@link Flowable#scan} émet chaque éléments transformés alors que la méthode
* {@link Flowable#reduce} émet le résultat final.
*/
public static void exercise4() {
log.info("Start Level5/Exercise4");
Flowable.range(1, 5)
.scan((result, item) -> result + item)
.doOnComplete(() -> log.info("Completed"))
.subscribe(value -> log.info("Next: {}", value));
}
/**
* Génére un nouveau flux avec la méthode {@link Flowable#flatMap}.
*
* <p><p>
* Note: Sortie attendue
*
* <ul>
* <li>Start Level5/Exercise5</li>
* <li>Next: a</li>
* <li>Next: b</li>
* <li>Next: b</li>
* <li>Next: c</li>
* <li>Next: c</li>
* <li>Next: c</li>
* <li>Next: d</li>
* <li>Next: d</li>
* <li>Next: d</li>
* <li>Next: d</li>
* <li>Completed</li>
* </ul>
*/
public static void exercise5() {
log.info("Start Level5/Exercise5");
List<String> letters = Arrays.asList("a", "b", "c", "d");
Flowable.range(1, 4)
.flatMap(i -> Single.just(letters.get(i - 1)).repeat(i))
.doOnComplete(() -> log.info("Completed"))
.subscribe(value -> log.info("Next: {}", value));
}
/**
* Concate deux flux de données.
* <ul>
* <li>Le premier émet les valeurs de 1 à 5 toutes les 2 secondes</li>
* <li>Le second émet les valeurs de 6 à 10 toutes les 100 millisecondes</li>
* </ul>
*
* <p><p>
* Note: Sortie attendue
*
* <ul>
* <li>Start Level5/Exercise6</li>
* <li>Next: 1</li>
* <li>Next: 2</li>
* <li>Next: 3</li>
* <li>Next: 4</li>
* <li>Next: 5</li>
* <li>Next: 6</li>
* <li>Next: 7</li>
* <li>Next: 8</li>
* <li>Next: 9</li>
* <li>Next: 10</li>
* <li>Completed</li>
* </ul>
*
* Note : La méthode {@Flowable#concat} génère un flux ou les éléments du premier flux apparaissent avant les éléments du second flux.
*/
public static void exercise6() {
log.info("Start Level5/Exercise6");
Flowable<Long> f1 = Flowable.intervalRange(1, 5, 0, 2, TimeUnit.SECONDS);
Flowable<Long> f2 = Flowable.intervalRange(6, 5, 0, 100, TimeUnit.MILLISECONDS);
Flowable.concat(f1, f2)
.doOnComplete(() -> log.info("Completed"))
.subscribe(value -> log.info("Next: {}", value));
Helpers.sleep(10, TimeUnit.SECONDS);
}
/**
* Merge deux flux de données.
* <ul>
* <li>Le premier émet les valeurs de 1 à 5 toutes les secondes</li>
* <li>Le second émet les valeurs de 6 à 10 toutes les 100 millisecondes</li>
* </ul>
*
* <p><p>
* Note: Sortie attendue
*
* <ul>
* <li>Start Level5/Exercise7</li>
* <li>Next: 1</li>
* <li>Next: 6</li>
* <li>Next: 7</li>
* <li>Next: 8</li>
* <li>Next: 9</li>
* <li>Next: 10</li>
* <li>Next: 2</li>
* <li>Next: 3</li>
* <li>Next: 4</li>
* <li>Next: 5</li>
* <li>Completed</li>
* </ul>
*
* Note : La méthode {@Observable#merge} génère un flux ou les éléments des deux flux apparaissent au fur et à mesure
* qu'ils sont émis par l'un des deux flux.
*/
public static void exercise7() {
log.info("Start Level5/Exercise7");
Flowable<Long> f1 = Flowable.intervalRange(1, 5, 0, 1, TimeUnit.SECONDS);
Flowable<Long> f2 = Flowable.intervalRange(6, 5, 100, 100, TimeUnit.MILLISECONDS);
Flowable.merge(f1, f2)
.doOnComplete(() -> log.info("Completed"))
.subscribe(value -> log.info("Next: {}", value));
Helpers.sleep(5, TimeUnit.SECONDS);
}
/**
* Merge deux flux de données, supprime les doublons et retourne le nombre d'éléments.
*
* <ul>
* <li>Le premier émet les valeurs de 1 à 10</li>
* <li>Le second émet les valeurs de 6 à 15</li>
* </ul>
* <p>
* Note: Sortie attendue
* <ul>
* <li>Start Level5/Exercice8</li>
* <li>Number of items: 15</li>
* </ul>
*
* Note: La méthode {@link Flowable#mergeWith} merge le flux courant avec un autre.
*/
public static void exercise8() {
log.info("Start Level5/Exercise8");
Flowable<Integer> f1 = Flowable.range(1, 10);
Flowable<Integer> f2 = Flowable.range(6, 10);
f1.mergeWith(f2)
.distinct()
.count()
.subscribe(number -> log.info("Number of items: {}", number));
}
/**
* Utilise la méthode {@link Flowable#zip} pour combiner l'émission de deux flux avec d'une méthode spécifique.