3

Other reactive libraries like project reactor offer sort methods for Publishers but there is no such method in mutiny. Their documentation doesn't even talk about it.

https://smallrye.io/smallrye-mutiny

Right now i'm achieving the said functionality by doing this

multi.collectItems()
.asList()
.map(
list -> {
  list.sort();
  return list;
})
.convert()
.with(listUni -> Multi.createFrom().iterable(listUni.await().indefinitely()))

Is there a better way to do the same ?

3 Answers3

2

I don't believe there is a built-in/better way to do this.

Mutiny generally prizes itself on having a "cut-down" set of operators in its core, and letting you build up other, more complex operators as needed. They're trying to avoid the reactor situation where you have 100+ methods on a couple of core types, and without a lot of background knowledge it's often difficult to know what ones are relevant.

IMHO that's no bad thing. Other reactive frameworks definitely have these built-in sort() operators, but there's a danger here - people assume they can still treat them as infinite, magically sorted publishers, because there's no sign of any collections anywhere. You can't of course - internally these frameworks have to maintain an underlying collection to sort the data, and then just output the contents of that when the stream is complete. This isn't that clear however, and ignorance of this fact can often lead to unintended slowdowns and OutOfMemoryError. On the contrary, in your example, it's immediately obvious that this stream uses an underlying collection for sorting your data.

There's just one minor thing I'd change in your example, but not really related to your question - I'd use:

list.stream().sorted().collect(Collectors.toList())

...in your map call instead of sorting a mutable list. Mutating data structures in a reactive stream is a bit of a code smell.

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
  • 1
    I can only second this response. The common `sort` operator is buffering and sorting when the stream is complete. It can lead to out of memory or people seeing it as _blocking_ (that's a perception). In Mutiny, collect your item in the collection of your choice and sort it as you want (pass a comparator or make the item comparable). So, you understand what's going on: It collects items; once done, it sorts them and emits the resulting collection. If you want to emit a sorted stream, just add: ``` .onItem().transformToMulti(sorted -> Multi.createFrom().iterable(sorted)); ``` – Clement Oct 23 '20 at 06:53
1

Another approach I used - combine multis into TreeMap as soon as they come with .collect().in(TREE_MAP_SUPPLIER, MULTI_MAP_ACCUMULATOR)

Dexter
  • 98
  • 7
0
  1. Convert the Multi to Uni (list).
  2. Sort the list from Uni.
  3. Convert the Uni to a Multi
multi.collect().asList() //1
.onItem()
.transform(list -> list.stream().sorted(Comparator.comparing(item::getId)).toList()) //2
.onItem()
.transformToMulti(list -> Multi.createFrom().iterable(list)); //3
Swe77
  • 21
  • 4