У меня есть статическая карта:
private static final Map<String, String> queries;
static {
Map<String, String> tmpMap = new HashMap<>();
tmpMap.put("USER_WITHOUT_ROLE_QUERY","...");
tmpMap.put("PROFIL_WITHOUT_ROLE_QUERY","...");
//Removed code for readability
queries = Collections.unmodifiableMap(tmpMap);
}
И два массива String, как показано ниже:
String[] typeFilter может содержать комбинацию этих значений:
["WITHOUT_PROFIL", "WITHOUT_ROLE", "WITHOUT_USER"];String[] elementFilter может содержать комбинацию этих значений: ["PROFIL",
«РОЛЬ», «УТИЛИСАТОР»];Я хочу в зависимости от значений в typeFilter и elementFilter отфильтровать карту queries и объединить значения отфильтрованной карты с помощью " UNION ".
Например, если typeFilter содержит "WITHOUT_ROLE", а elementFilter содержит "PROFIL" и "USER", отфильтрованная карта будет содержать только записи PROFIL_WITHOUT_ROLE_QUERY и USER_WITHOUT_ROLE_QUERY, поэтому результат будет: queries.get("PROFIL_WITHOUT_ROLE_QUERY") + " UNION " + queries.get("USER_WITHOUT_ROLE_QUERY").
Вот что я пробовал:
// Filter queries map
List<String> queriesMapKeys = new ArrayList<>();
for (String element : elementFilter) {
for (String type : typeFilter) {
queriesMapKeys.add(queries.get(element + "_" + type + "_QUERY"));
}
}
String[] queriesToJoin = queries.entrySet().stream().filter(e -> queriesMapKeys.contains(e.getKey())).collect(// I'm stuck here :-/);
String sqlQuery = String.join(" UNION ", queriesToJoin);
Как я могу это решить? И есть ли лучший способ выполнить приведенный выше код?
вы ищете String [] queryToJoin = запросы .... .collect (Collectors.toList ()). toArray (new String [0]);
@lexicore да, действительно, и было бы неплохо, если бы была возможность объединить первый вложенный цикл с кодом, в котором я фильтрую карту.
Я думаю, что это нормально, что вы предварительно вычисляете имена запросов, которые хотите фильтровать. Но лучше использовать для этого Set как HashSet.
@ SEY_91, на самом деле есть только stream.toArray(String[]::new).
у тебя есть ответ @IchigoKurosaki?




Вы можете попробовать следующее.
List<String> queriesToJoin = queries.entrySet().stream().filter(e -> queriesMapKeys.contains(e.getKey())).collect(Collectors.toList());
String sqlQuery = String.join(" UNION ", queriesToJoin);
queriesToJoin в этом случае идентификатор типа List<Map.Entry<String,String>>, а не List<String>
Вам не обязательно использовать потоки. Вы можете просто использовать класс StringJoiner:
import java.util.StringJoiner;
<...>
StringJoiner builder = new StringJoiner(" UNION ");
for (String element : elementFilter) {
for (String type : typeFilter) {
String key = element + "_" + type + "_QUERY";
if (queries.containsKey(key)) {
builder.add(queries.get(key));
}
}
}
String sqlQuery = builder.toString();
Интересный факт: класс StringJoiner используется внутренне, когда вы выполняете String::join или собираете данные с Stream с помощью Collectors.joining.
Кажется, вы просто хотите получить значения для набора ключей из вашей карты. Это будет что-то вроде:
List<String> queriesToJoin = queries
.entrySet()
.stream()
.filter(e -> queriesMapKeys.contains(e.getKey()))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
Вы также просите лучше реализовать это.
Вы используете форматированную строку для моделирования определенных свойств ваших запросов и фильтров. Вместо этого вы можете попробовать использовать для этого классы или предикаты.
Например, вместо использования строк в качестве ключей / имен запросов рассмотрите возможность использования перечислений.
public enum QueryId {
USER_WITHOUT_ROLE_QUERY(USER, WITHOUT_ROLE),
PROFIL_WITHOUT_ROLE_QUERY(PROFIL, WITHOUT_ROLE);
QueryId(TargetElement element, QueryType type) {...}
public TargetElement getElement() {...}
public QueryType getQueryType() {...}
}
Затем вы можете фильтровать с помощью предикатов, которые используют QueryId.getElement() или QueryId.getQueryType().
Попробуйте это, если вы хотите объединить первый вложенный цикл с кодом, в котором вы фильтруете карту.
String[] queriesToJoin = Arrays.asList(elementFilter)
.stream()
.flatMap(f -> Arrays.asList(typeFilter)
.stream()
.map(s -> f + "_" + s + "_QUERY"))
.filter(t -> queries.containsKey(t))
.map(t -> queries.get(t))
.collect(Collectors.toList()).toArray(new String [0]);
В вашем коде
// Filter queries map
List<String> queriesMapKeys = new ArrayList<>();
for (String element : elementFilter) {
for (String type : typeFilter) {
queriesMapKeys.add(queries.get(element + "_" + type + "_QUERY"));
}
}
вы уже запрашиваете карту и добавляете результат get в список queriesMapKeys. Если ключа нет на карте, ссылки null появятся в списке. Ключи отсутствуют в этом списке. Таким образом, выполняя другую операцию потока, пытаясь сопоставить список с ключами карты, такими как
String[] queriesToJoin = queries.entrySet().stream()
.filter(e -> queriesMapKeys.contains(e.getKey())) …
вообще не может работать.
Но в любом случае в этом не было бы необходимости. Вам нужно только обработать потенциальные значения null. Либо:
queriesMapKeys.removeIf(Objects::isNull);
String sqlQuery = String.join(" UNION ", queriesMapKeys);
или же
String sqlQuery = queriesMapKeys.stream()
.filter(Objects::nonNull)
.collect(Collectors.joining(" UNION "));
Последний может быть объединен с предыдущей потоковой операцией, заменяя вложенные циклы, создавая queriesMapKeys:
String sqlQuery = Arrays.stream(elementFilter)
.flatMap(element -> Arrays.stream(typeFilter)
.map(type -> queries.get(element + "_" + type + "_QUERY")))
.filter(Objects::nonNull)
.collect(Collectors.joining(" UNION "));
Кажется, вы просто хотите получить значения для набора ключей, я правильно понимаю?