Java 8: перебор списка и добавление к карте на основе условия

#java #java-8 #java-stream

#java #java-8 #java-stream

Вопрос:

У меня есть список, который я повторяю, и при некотором условии каждого элемента я добавляю каждый элемент списка в структуру данных в определенной позиции, ниже приведен код в Java 7.

Структура данных, в которую я добавляю каждый элемент из списка, является,

 /* The data structure has two slots, one for parents and another for children */
MenuBar menuBar = new MenuBar();
 

Теперь фрагмент кода,

 MenuBar menuBar = new MenuBar();
for (Menu menu : menuList) {
    if (isParentMenu(menu.getId())) {
        menuBar.addMenu(menu);
    } else {
        Menu parent = getMenuById(menu.getParentId());
        menuBar.addChildMenu(parent, menu);
    }
}
 

Теперь я изо всех сил пытаюсь создать код Java 8, эквивалентный тому же, ниже приведено то, что я пытаюсь,

 // The following code is not complete , just trying
   menuList.stream().filter(menu -> isParentMenu(menu.getId()))
   .map(menu -> menuBar.addMenu(menu))
 

Комментарии:

1. Вам НЕ нужен java8, чтобы сделать это. Вместо этого используйте итеративный подход. Java8 — это НЕ серебряная пуля, которая решает все ваши проблемы.

2. и, согласно многим тестам, такой простой код с потоками работает медленнее, чем цикл for ….

Ответ №1:

Честно говоря, я не думаю, что ваш код нуждается в изменении. Как и сейчас, это достаточно ясно. Изменение его на streams может даже добавить некоторые накладные расходы, что сделает его менее производительным, чем цикл.

Действительно простым решением для потоков было бы:

 MenuBar menuBar = new MenuBar();
menuList.stream().forEach(x -> {
    if (isParentMenu(x.getId())) {
        menuBar.addMenu(x);
    } else {
        Menu parent = getMenuById(x.getParentId());
        menuBar.addChildMenu(parent, x);
    }
});
 

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

 Map<Boolean, List<Menu>> map = menuList.stream().collect(Collectors.partitioningBy(x -> isParentMenu(x.getId())));
map.get(true).stream().forEach(menuBar::addMenu);
map.get(false).stream().forEach(x -> {
    Menu parent = getMenuById(x.getParentId());
    menuBar.addChildMenu(parent, x);
});
 

Ответ №2:

Если вы хотите использовать filter, вам нужно запустить forEach дважды, или вы пишете if-else внутри одного forEach . Что-то вроде этого:

 menuList.stream().forEach(
                    menu -> {
                        if(isParentMenu(menu.getId()) {
                            menuBar.addMenu(menu);
                        } else {
                            Menu parent = getMenuById(menu.getParentId());
                            menuBar.addChildMenu(parent, menu);
                        }
                    }
            );