Одной из недостающих функций API Streams является преобразование "разделение", например, как определено в Clojure. Скажем, я хочу воспроизвести соединение Hibernate fetch: я хочу выпустить одну инструкцию SQL SELECT для получения таких объектов из результата:
class Family {
String surname;
List<String> members;
}
Я выпускаю:
SELECT f.name, m.name
FROM Family f JOIN Member m on m.family_id = f.id
ORDER BY f.name
и я получаю плоский поток записей (f.name, m.name)
. Теперь мне нужно преобразовать его в поток объектов Family
, со списком его членов внутри. Предположим, что у меня уже есть Stream<ResultRow>
; теперь мне нужно преобразовать его в Stream<List<ResultRow>>
, а затем действовать на него с преобразованием отображения, которое превращает его в Stream<Family>
.
Семантика преобразования заключается в следующем: продолжайте собирать поток в List
до тех пор, пока предоставленная функция дискриминатора продолжает возвращать одно и то же значение; как только значение изменится, испустите List
как элемент выходного потока и начните собирать новый List
.
Я надеюсь, что смогу написать такой код (у меня уже есть метод resultStream
):
Stream<ResultRow> dbStream = resultStream(queryBuilder.createQuery(
"SELECT f.name, m.name"
+ " FROM Family f JOIN Member m on m.family_id = f.id"
+ " ORDER BY f.name"));
Stream<List<ResultRow> partitioned = partitionBy(r -> r.string(0), dbStream);
Stream<Family> = partitioned.map(rs -> {
Family f = new Family(rs.get(0).string(0));
f.members = rs.stream().map(r -> r.string(1)).collect(toList());
return f;
});
Разумеется, я ожидаю, что результирующий поток останется ленивым (не материализованным), поскольку я хочу иметь возможность обрабатывать результирующий набор любого размера, не затрагивая никаких ограничений памяти O (n). Без этого важного требования я был бы доволен предоставленным коллекционером groupingBy
.