У меня есть следующая карта: Map<String, Set<String>>, которую мне нужно инициализировать. Проблема не в этом. Тем не менее, поскольку я хочу, чтобы Set сохранял порядок вставки, я подумал об инициализации всей конструкции с помощью new LinkedHashMap<String, LinkedHashSet<String>>();, но это вынудило меня затем изменить карту на: Map<String, LinkedHashSet<String>>.
Почему я не могу использовать интерфейс, если при инициализации указываю конкретный тип? Или как лучше обеспечить реализацию вложенного типа?
Чтобы было более понятно, почему я хочу это сделать, вот код:
private void sortMap(Map<String, Map<Date, Map<String, Long>>> dataMap) {
Map<String, Set<String>> sortedNames = new LinkedHashMap<String, Set<String>>(); // <-- this initialization
for (Map.Entry<String, Map<Date, Map<String, Long>>> entry : dataMap.entrySet()) {
sortedNames.put(entry.getKey(), entry.getValue().get(getCurrentMonthDate()).keySet());
}
}
РЕДАКТИРОВАТЬ
С помощью принятого ответа я придумал это решение, которое, похоже, отлично работает для меня:
Map<String, Set<String>> sortedNames = dataMap.entrySet().stream()
.map(e -> new AbstractMap.SimpleEntry<String, LinkedHashSet<String>>(e.getKey(),
e.getValue().get(getCurrentMonthDate()).keySet().stream()
.collect(Collectors.toCollection(LinkedHashSet<String>::new))))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
@chrylis Несоответствие типов: невозможно преобразовать из LinkedHashMap <String, LinkedHashSet <String>> в Map <String, Set <String>>
Вам не нужно менять общий тип на LinkedHashSet <String> Просто используйте оператор ромба. Однако вам нужно только поместить на карту экземпляры LinkedHashSet.




Затем выполните инициализацию следующим образом.
Map<String, Set<String>> test = new LinkedHashMap<>();
// initialize to LinkedHashSet<> when putting elements
test.put("key", new LinkedHashSet<>());
Вы не можете использовать Map<String, Set<String>> test = new LinkedHashMap<String, LinkedHashSet<String>>(), потому что LinkedHashMap<String, LinkedHashSet<String>>(); не является подтипом Map<String, Set<String>>.
Не то чтобы универсальные типы в Java не были ковариантный или контравариантный, если вы не используете подстановочные знаки.
Универсальные типы не являются ковариантными, поэтому вы не можете назначить LinkedHashMap<String, LinkedHashSet<String>> на Map<String, Set<String>>.
Если вам нужно заставить значения карты быть только LinkedHashSet, тогда вы должны объявить карту как Map<String, LinkedHashSet<String>>.
Однако в этом нет необходимости, поскольку вы можете вызвать map.put с подтипом Set<String>:
Map<String, Set<String>> map = new LinkedHashMap<>();
map.put("key", new LinkedHashSet<String>());
Что по-прежнему позволяет программировать интерфейс Set.
Вот более простая версия вашего кода, использующая потоковый API.
Date curretMonthDate = getCurrentMonthDate();
Map<String, Set<String>> sortedNames = dataMap.entrySet().stream()
.map(e -> new AbstractMap.SimpleEntry<String, LinkedHashSet<String>>(e.getKey(),
e.getValue()
.entrySet()
.stream()
.filter(inner -> inner.getKey().equals(curretMonthDate))
.flatMap(subEntry -> subEntry
.getValue()
.entrySet()
.stream()
.map(Entry::getKey))
.collect(Collectors.toCollection(LinkedHashSet<String>::new))))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
Это было бы решением. Тем не менее, я пытаюсь использовать Map.Entry<Date, Map<String, Long>>.getValue().keySet() для получения всех значений, которые я хочу добавить к этому Set. Было бы удобнее, если бы мне не пришлось сначала ставить LinkedHashSet, а потом проверять, null он или нет. Каким-либо образом обойти это?
@XtremeBaumer Я изо всех сил пытаюсь понять, что именно вы делаете. Я уверен, что API map / set / stream можно использовать для упрощения этой реализации. Можете ли вы поделиться этим кодом здесь или задать другой вопрос?
@XtremeBaumer Пожалуйста, проверьте правку и замечание о вашем примере
Спасибо за код, но я думаю, что он не делает то, что мне нужно. Мне нужно получить keySet() только на 1 конкретную дату. Тем не менее, вы все равно помогли мне сократить код с помощью внутреннего цикла. Возможно, вы можете настроить потоковое решение для нового кода, если это возможно.
@XtremeBaumer Я не учел фильтр, извините. Я редактировал