I have following code where I want to get value for multiple keys which starts with same name: for example contents_of_a1, contents_of_ab2, contents_of_abc3
Optional.ofNullable(((Map<?, ?>) fieldValue))
.filter(Objects::nonNull)
.map(coverages -> coverages.get("contents_of_%"))
.filter(Objects::nonNull)
.filter(LinkedHashMap.class::isInstance)
.map(LinkedHashMap.class::cast)
.map(contents -> contents.get("limit"))
.map(limit -> new BigDecimal(String.valueOf(limit)))
.orElse(new BigDecimal(number));
How can I pass contents_of%
CodePudding user response:
I don't know the reasons behind the data structure and what you want to achieve.
However, it is not important as this can be easily reproduced.
Using of Optional is a good start, however, for iterating and processing multiple inputs, you need to use java-stream instead and then Optional inside of collecting (I assume you want Map<String, BigDecimal
output, but it can be adjusted easily).
Also, note .filter(Objects::nonNull)
is meaningless as Optional handles null
internally and is never passed to the next method.
final Map<String, Map<?, ?>> fieldValue = Map.of(
"contents_of_a", new LinkedHashMap<>(Map.of("limit", "10")),
"contents_of_b", new HashMap<>(Map.of("limit", "11")), // Different
"contents_of_c", new LinkedHashMap<>(Map.of("amount", "12")), // No amount
"contents_of_d", new LinkedHashMap<>(Map.of("limit", "13")));
final List<String> contents = List.of(
"contents_of_a",
"contents_of_b",
"contents_of_c",
// d is missing, e is requested instead
"contents_of_e");
final int number = -1;
final Map<String, BigDecimal> resultMap = contents.stream()
.collect(Collectors.toMap(
Function.identity(), // key
content -> Optional.of(fieldValue) // value
.map(coverages -> fieldValue.get(content))
.filter(LinkedHashMap.class::isInstance)
// casting here to LinkedHashMap is not required
// unless its specific methods are to be used
// but we only get a value using Map#get
.map(map -> map.get("limit"))
.map(String::valueOf)
.map(BigDecimal::new)
// prefer this over orElse as Optional#orElseGet
// does not create an object if not required
.orElseGet(() -> new BigDecimal(number))));
// check out the output below the code
resultMap.forEach((k, v) -> System.out.println(k " -> " v));
Only the content for a
is used as the remaining were either not an instance of LinkedHashMap
, didn't contain a key limit
or were not among requested contents.
contents_of_a -> 10 contents_of_b -> -1 contents_of_e -> -1 contents_of_c -> -1
CodePudding user response:
If you want to filter a map for which key starting with "contents_of_", you can do this for Java 8:
Map<String, Object> filteredFieldValue = fieldValue.entrySet().stream().filter(c -> {
String k = c.getKey();
return Stream.of("contents_of_").anyMatch(k::startsWith);
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));