Streams compose with .where(pred) and .map(fn) just like lists. Each source value is tested first, matching values are transformed, and the resulting stream can be consumed with await for.

Program

Play the program to filter source values, transform the matches, and collect the result.

stream_transform.dart
Replay: real traced execution (multi-file project)
bool isEven(int n) => n % 2 == 0;
int timesTen(int n) => n * 10;

Stream<int> source() => Stream.fromIterable([1, 2, 3, 4]);

Future<List<int>> scaledEvens(Stream<int> s) async {
  var out = <int>[];
  await for (var n in s.where(isEven).map(timesTen)) {
    out.add(n);
  }
  return out;
}

Future<void> main() async {
  var result = await scaledEvens(source());
  print('evens scaled = $result');
}
  1. return ← Stream of 1, 2, 3, 4

    4Stream<int> source() => Stream.fromIterable([1, 2, 3, 4]);
    values this stepStream of 1, 2, 3, 4return
  2. out ← []

    6Future<List<int>> scaledEvens(Stream<int> s) async {7  var out = <int>[];8  await for (var n in s.where(isEven).map(timesTen)) {
    values this step[]out
  3. keep ← false

    1bool isEven(int n) => n % 2 == 0;2int timesTen(int n) => n * 10;
    values this stepfalsekeep1n
  4. keep ← true

    1bool isEven(int n) => n % 2 == 0;2int timesTen(int n) => n * 10;
    values this steptruekeep2n
  5. return ← 20

    1bool isEven(int n) => n % 2 == 0;2int timesTen(int n) => n * 10;
    values this step20return2n
  6. stream value ← 20

    7var out = <int>[];8await for (var n in s.where(isEven).map(timesTen)) {9  out.add(n);
    values this step20stream value
  7. out ← [20]

    8await for (var n in s.where(isEven).map(timesTen)) {9  out.add(n);10}
    values this step[] [20]out20n
  8. keep ← false

    1bool isEven(int n) => n % 2 == 0;2int timesTen(int n) => n * 10;
    values this stepfalsekeep3n
  9. keep ← true

    1bool isEven(int n) => n % 2 == 0;2int timesTen(int n) => n * 10;
    values this steptruekeep4n
  10. return ← 40

    1bool isEven(int n) => n % 2 == 0;2int timesTen(int n) => n * 10;
    values this step40return4n
  11. stream value ← 40

    7var out = <int>[];8await for (var n in s.where(isEven).map(timesTen)) {9  out.add(n);
    values this step40stream value
  12. out ← [20, 40]

    8await for (var n in s.where(isEven).map(timesTen)) {9  out.add(n);10}
    values this step[20] [20, 40]out40n
  13. stream value ← done (closed)

    7var out = <int>[];8await for (var n in s.where(isEven).map(timesTen)) {9  out.add(n);
    values this stepdone (closed)stream value
  14. return ← [20, 40]

    10  }11  return out;12}
    values this step[20, 40]return[20, 40]out
  15. result ← [20, 40]

    14Future<void> main() async {15  var result = await scaledEvens(source());16  print('evens scaled = $result');
    values this step[20, 40]result
  16. print('evens scaled = $result');

    15  var result = await scaledEvens(source());16  print('evens scaled = $result');17}
    outputevens scaled = [20, 40]
    values this step[20, 40]result
Stream.fromIterable `Stream.fromIterable([...])` emits each value in order from a finite source.
.where `.where(isEven)` calls the predicate for each source value and lets only `2` and `4` continue.
.map `.map(timesTen)` transforms each kept value, so `2` becomes `20` and `4` becomes `40`.
await for collect `await for` consumes one transformed value at a time; appending into a list lets the caller see the full result.