#java #java-8 #java-stream
#java #java-8 #java-поток
Вопрос:
List<Entity> entities = ...
Map<Boolean, List<Entity>> entitiesByIsTest = entities.stream()
.collect(Collectors.groupingBy(Entity::isTest));
Очевидно, что результирующая карта имеет единственные ключи, которые присутствуют в свойстве группировки. Это должно работать так для типов с бесконечным набором значений. Но как насчет перечислений / логических значений / других определенных типов?
Можно ли реализовать инициализацию пустых коллекций более элегантно, чем в приведенном ниже фрагменте?
if (entitiesByIsTest.get(true) == null) {
entitiesByIsTest.put(true, new ArrayList());
}
Комментарии:
1. трудно понять вопрос. какова цель вашего кода?
2. Цель состоит в том, чтобы разделить набор на два независимых набора, а затем выполнить несколько разных действий — например, сохранить обычные объекты, но сохранить только количество тестовых объектов
Ответ №1:
Если вы хотите Boolean
, чтобы ключи и оба сопоставления всегда инициализировались, используйте partitioningBy
, который имеет именно те свойства, которые вам нужны.
Map<Boolean, List<Entity>> entitiesByIsTest = entities.stream()
.collect(Collectors.partitioningBy(Entity::isTest));
Если ключом является an enum
, вы должны остаться groupingBy
, но вы можете заменить последующие get
операции на
List<Entity> value=map.computeIfAbsent(key, x->new ArrayList<>());
который создаст и поместит новое ArrayList
тогда и только тогда, когда предыдущего сопоставления не было, и вернет фактическое сопоставленное значение в любом случае (в отличие putIfAbsent
от ).
Конечно, вместо этого вы могли бы добавить все отсутствующие значения в одну нетерпеливую операцию:
EnumSet.allOf(KeyType.class).forEach(key->map.computeIfAbsent(key, x->new ArrayList<>()));
Ответ №2:
Вы могли бы использовать entitiesByIsTest.putIfAbsent(true,new ArrayList());
это, чтобы добавить новый пустой список массивов только тогда, когда в map для этого ключа ничего нет
Комментарии:
1. Спасибо! хороший момент. Одно дело, что это не функциональный стиль. Моя главная цель — использовать все преимущества stream api, такие как понятный код, максимально избегая состояний
2. Совсем не понятно, о чем вы просите. У вас уже есть решение для этой
groupingBy
вещи — это уже работает для перечислений, логических значений или любых других типов. Этот ответ отвечает на ваш второй вопрос: как инициализировать пустые коллекции на карте.
Ответ №3:
Вы можете написать свой собственный коллектор.
Collectors.of(
//**Initialize map with all of your values**//,
entity -> map.get(entity.isTest()).add(entity),
(left, right) -> right.forEach(r -> left.get(r.getKey()).addAll(r.getValue)); return r;)
Ответ №4:
Просто передайте поставщику карты, уже содержащей пустые списки, в качестве значений для всех ожидаемых ключей.
Это должно группироваться по перечисляемым элементам:
Map<Type, List<Value>> emptyMap = EnumSet.allOf(Type.class)
.stream()
.collect(toMap(identity(), f -> new ArrayList<>()));
Function<Value, Type> fun = this::groupByType;
Map<Type, List<Value>> groups = values.stream()
.collect(groupingBy(fun, () -> emptyMap, toList()));