Operator examples for statefulMapConcat #25468

This commit is contained in:
Johan Andrén 2020-03-10 10:36:07 +01:00 committed by GitHub
parent 52c83dca34
commit d8aed9e9d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 263 additions and 7 deletions

View file

@ -0,0 +1,119 @@
/*
* Copyright (C) 2009-2020 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.stream.operators.flow;
import akka.NotUsed;
import akka.actor.typed.ActorSystem;
import akka.japi.Pair;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Source;
import java.util.*;
public class StatefulMapConcat {
static final ActorSystem<?> system = null;
static void zipWithIndex() {
// #zip-with-index
Source<Pair<String, Long>, NotUsed> letterAndIndex =
Source.from(Arrays.asList("a", "b", "c", "d"))
.statefulMapConcat(
() -> {
// variables we close over with lambdas must be final, so we use a container,
// a 1 element array, for the actual value.
long[] counter = {0};
// we return the function that will be invoked for each element
return (element) -> {
counter[0] += 1;
// we return an iterable with the single element
return Arrays.asList(new Pair(element, counter[0]));
};
});
letterAndIndex.runForeach(System.out::println, system);
// prints
// Pair(a,1)
// Pair(b,2)
// Pair(c,3)
// Pair(d,4)
// #zip-with-index
}
static void blacklist() {
// #blacklist
Source<String, NotUsed> fruitsAndBlacklistCommands =
Source.from(
Arrays.asList(
"banana", "pear", "orange", "blacklist:banana", "banana", "pear", "banana"));
Flow<String, String, NotUsed> blacklistingFlow =
Flow.of(String.class)
.statefulMapConcat(
() -> {
Set<String> blacklist = new HashSet<>();
return (element) -> {
if (element.startsWith("blacklist:")) {
blacklist.add(element.substring(10));
return Collections
.emptyList(); // no element downstream when adding a blacklisted keyword
} else if (blacklist.contains(element)) {
return Collections
.emptyList(); // no element downstream if element is blacklisted
} else {
return Collections.singletonList(element);
}
};
});
fruitsAndBlacklistCommands.via(blacklistingFlow).runForeach(System.out::println, system);
// prints
// banana
// pear
// orange
// pear
// #blacklist
}
static void reactOnEnd() {
// #bs-last
Source<String, NotUsed> words =
Source.from(Arrays.asList("baboon", "crocodile", "bat", "flamingo", "hedgehog", "beaver"));
Flow<String, String, NotUsed> bWordsLast =
Flow.of(String.class)
.concat(Source.single("-end-"))
.statefulMapConcat(
() -> {
List<String> stashedBWords = new ArrayList<>();
return (element) -> {
if (element.startsWith("b")) {
// add to stash and emit no element
stashedBWords.add(element);
return Collections.emptyList();
} else if (element.equals("-end-")) {
// return in the stashed words in the order they got stashed
return stashedBWords;
} else {
// emit the element as is
return Collections.singletonList(element);
}
};
});
words.via(bWordsLast).runForeach(System.out::println, system);
// prints
// crocodile
// flamingo
// hedgehog
// baboon
// bat
// beaver
// #bs-last
}
}

View file

@ -0,0 +1,99 @@
/*
* Copyright (C) 2009-2020 Lightbend Inc. <https://www.lightbend.com>
*/
package docs.stream.operators.flow
import akka.actor.ActorSystem
import akka.stream.scaladsl.Flow
import akka.stream.scaladsl.Source
class StatefulMapConcat {
implicit val system: ActorSystem = ???
def zipWithIndex(): Unit = {
// #zip-with-index
val letterAndIndex = Source("a" :: "b" :: "c" :: "d" :: Nil).statefulMapConcat { () =>
var counter = 0L
// we return the function that will be invoked for each element
{ element =>
counter += 1
// we return an iterable with the single element
(element, counter) :: Nil
}
}
letterAndIndex.runForeach(println)
// prints
// (a,1)
// (b,2)
// (c,3)
// (d,4)
// #zip-with-index
}
def blacklist(): Unit = {
// #blacklist
val fruitsAndBlacklistCommands = Source(
"banana" :: "pear" :: "orange" :: "blacklist:banana" :: "banana" :: "pear" :: "banana" :: Nil)
val blacklistingFlow = Flow[String].statefulMapConcat { () =>
var blacklist = Set.empty[String]
{ element =>
if (element.startsWith("blacklist:")) {
blacklist += element.drop(10)
Nil // no element downstream when adding a blacklisted keyword
} else if (blacklist(element)) {
Nil // no element downstream if element is blacklisted
} else {
element :: Nil
}
}
}
fruitsAndBlacklistCommands.via(blacklistingFlow).runForeach(println)
// prints
// banana
// pear
// orange
// pear
// #blacklist
}
def reactOnEnd(): Unit = {
// #bs-last
val words = Source("baboon" :: "crocodile" :: "bat" :: "flamingo" :: "hedgehog" :: "beaver" :: Nil)
val bWordsLast = Flow[String].concat(Source.single("-end-")).statefulMapConcat { () =>
var stashedBWords: List[String] = Nil
{ element =>
if (element.startsWith("b")) {
// prepend to stash and emit no element
stashedBWords = element :: stashedBWords
Nil
} else if (element.equals("-end-")) {
// return in the stashed words in the order they got stashed
stashedBWords.reverse
} else {
// emit the element as is
element :: Nil
}
}
}
words.via(bWordsLast).runForeach(println)
// prints
// crocodile
// flamingo
// hedgehog
// baboon
// bat
// beaver
// #bs-last
}
}