Java 8 отдельных элементов списка по классам - PullRequest
4 голосов
/ 22 марта 2019

учитывая, что у меня есть список элементов, которые все наследуются от одного базового класса:

class Item {
    protected String name;

    public Item(String name) {

        this.name = name;
  }

  getName() {

      return name;
  }
}

class ItemA extends Item {...}
class ItemB extends Item {...}

List<Item> itemList = Arrays.asList(new ItemA("itemA"), new ItemB("itemB"));

В моем случае я не контролирую, как эти классы реализованы, но мне нужно разделить список на два разных списка, содержащих имя соответствующего элемента.

Вот первая попытка решения, содержащего множество операторов if и instanceof:

List<String> itemAList = new ArrayList<>();
List<String> itemBList = new ArrayList<>();

itemList.forEach(item -> {

    if(item instanceof ItemA) {

        itemAList.add(item.getName());
    }        
    else if(item instanceof ItemB) {

        itemBList.add(item.getName());
    }
});

Так что это работает, но я немного подумал, как избежать операторов if. Поскольку я использую Java 8, я могу сделать это:

List<String> itemAList = itemList.stream()
    .filter(ItemA.class::isInstance)
    .map(item -> item.getName())
    .collect(Collectors.toList());

List<String> itemBList = itemList.stream()
    .filter(ItemB.class::isInstance)
    .map(item -> item.getName())
    .collect(Collectors.toList());

Это также работает, но это означает, что мне нужно обработать список два раза.

Как я уже сказал, я не имею никакого отношения к реализации классов Item, так как лучше всего реализовать такое поведение?

Привет

[edit:] Спасибо за все ответы. Сегодня я узнал что-то новое.

Ответы [ 3 ]

5 голосов
/ 22 марта 2019

Вы можете сгруппировать контент, основываясь на классе элементов:

Map<Class, List<String>> grouped = itemList.stream()
        .collect(Collectors.groupingBy(Item::getClass,
                Collectors.mapping(Item::getName, Collectors.toList())));

и получить к нему доступ:

List<String> itemAList = grouped.get(ItemA.class);
2 голосов
/ 22 марта 2019

Вы также можете сделать:

Map<Boolean, List<Item>> classMap = itemList.stream()
                .collect(Collectors.partitioningBy(ItemA.class::isInstance));

который выводит

 {
    false=[ItemB [getClass()=class stackoverflow.ItemB]],
    true =[ItemA [getClass()=class stackoverflow.ItemA]]
 }
2 голосов
/ 22 марта 2019

Как вы сказали, у вас есть разные экземпляры, которые вы не можете контролировать, поэтому вы не можете быть уверены, что в списке присутствуют только ItemA и ItemB.

Вам лучше использовать карту с именем в качестве ключа и List из Item s в качестве значений:

Map<String, List<Item>> map = itemList.stream()
    .collect(Collectors.groupingBy(Item::getName, Function.identity()));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...