Java потоковая функция высшего порядка - PullRequest
4 голосов
/ 18 марта 2019

Я пытаюсь обработать объект, который имеет вложенные списки глубиной 2 уровня. Например, мой объект может быть разбит на что-то вроде этого:

TopLevel: [
    MidLevel: [
        LowLevel,
        LowLevel,
        .
        .
    ],
    MidLevel: [
        LowLevel,
        LowLevel,
        .
        .
    ]
    .
    .
]

По существу TopLevel содержит список MidLevel объектов, каждый из которых, в свою очередь, содержит список LowLevel объектов. В конце обработки я хотел бы построить SomeObj для каждого из LowLevel объектов. Однако для SomeObj требуется информация от TopLevel, MidLevel и LowLevel.

В последние несколько месяцев я пытался написать код в более функциональном стиле, поэтому моей первой мыслью было создание функции более высокого порядка, которую я мог бы построить на каждом уровне объекта. Функция выглядит так:

Function<MidLevel, Function<LowLevel, SomeObj>> buildObjects(TopLevel topLevel) {
    return midLevel ->
        lowLevel -> {
            return buildSomeObj(topLevel, midLevel, lowLevel);
        };
}

Я намерен использовать эту функцию некоторым образом, как показано ниже (предположим, у меня есть служебные функции, которые предоставляют поток списков):

Function<MidLevel, Function<LowLevel, SomeObj>> topBuilder = buildObjects(topLevel);
List<SomeObj> objs = topLevel.streamMid()
    .map(topBuilder)
    .streamLow()
    .map(Function::apply)
    .collect(/*collect to list*/);

Однако это, очевидно, не работает, потому что после применения объектов MidLevel к функции topBuilder мой поток теперь является потоком функций, а не объектов MidLevel, поэтому у меня нет доступа к списку LowLevel объектов в потоке больше.

Есть ли какое-то решение для этого или я пытаюсь решить это функционально, когда оно не подходит для этого? Есть ли способ как применить функцию, так и получить доступ к исходному объекту, который был применен к этой функции?

Ответы [ 2 ]

6 голосов
/ 18 марта 2019

flatMap() и вложение - путь.Попробуйте это:

topLevelStream() //create a stream of top level elements
  .flatMap( top -> top.streamMid() //create a stream of mid level elements
    .flatMap( mid -> mid.streamLow() //create a stream of low level elements
      .map(low -> "use top, mid and low here") 
    ) 
  )
  .collect( ... );

Благодаря такому вложению у вас все еще есть доступ к элементам во внешних функциях, а комбинация flatMap() и map() открывает поток, к которому map() вызывается collect().

1 голос
/ 18 марта 2019

Вы можете просто использовать flatMap как:

List<SomeObj> objs = topLevel.getMidLevels().stream()
        .flatMap(a -> a.getLowLevels().stream().map(b -> topBuilder.apply(a).apply(b)))
        .collect(Collectors.toList());

с вашими сущностями, аналогичными:

class TopLevel {
    List<MidLevel> midLevels;
}

class MidLevel {
    List<LowLevel> lowLevels;
}

class LowLevel {
}

class SomeObj {
}
...