Java Map <String, Set <String>> типы инициализации

У меня есть следующая карта: 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 -cautiouslyoptimistic- 02.11.2018 09:34

@chrylis Несоответствие типов: невозможно преобразовать из LinkedHashMap <String, LinkedHashSet <String>> в Map <String, Set <String>>

XtremeBaumer 02.11.2018 09:35

Вам не нужно менять общий тип на LinkedHashSet <String> Просто используйте оператор ромба. Однако вам нужно только поместить на карту экземпляры LinkedHashSet.

JB Nizet 02.11.2018 09:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
424
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Затем выполните инициализацию следующим образом.

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 02.11.2018 09:43

@XtremeBaumer Я изо всех сил пытаюсь понять, что именно вы делаете. Я уверен, что API map / set / stream можно использовать для упрощения этой реализации. Можете ли вы поделиться этим кодом здесь или задать другой вопрос?

ernest_k 02.11.2018 10:06

@XtremeBaumer Пожалуйста, проверьте правку и замечание о вашем примере

ernest_k 02.11.2018 10:57

Спасибо за код, но я думаю, что он не делает то, что мне нужно. Мне нужно получить keySet() только на 1 конкретную дату. Тем не менее, вы все равно помогли мне сократить код с помощью внутреннего цикла. Возможно, вы можете настроить потоковое решение для нового кода, если это возможно.

XtremeBaumer 02.11.2018 11:05

@XtremeBaumer Я не учел фильтр, извините. Я редактировал

ernest_k 02.11.2018 11:15

Другие вопросы по теме