简体   繁体   中英

Filter map by its value using Java Stream API

I am new to Java streams and want to run the below code using streams.

 List<String> roles = new ArrayList<>();
    if (stats.containsKey("roles")) {
            roles = stats.get("roles");
    } else {
            Map<String, String> roleMap = stats.containsKey("attributes") ? 
                       stats.get("attributes") : new HashMap<>();
            for (Map.Entry<String, String> e : roleMap.entrySet()) {
                    if (e.getValue().equals("true")) {
                            roles.add(e.getKey());
                    }
            }
    }

In the above code I am doing the following steps :

  1. I have a stats hashmap in which first I am checking if the roles key is present, if it is present I am returning the corresponding value.

  2. if the stats hashmap does not contain the roles key, I am checking if stats hashmap contains key attributes .

  3. If the attribute key present then its value is Hashmap and then I am traversing the hashmap and checking wherever its value is equal to "true", I am adding the corresponding key to my roles list.

Input:

{
    "attributes":{
        "id":false
        "name":true
    }
       
}

Output:

["name"]

Can this whole code be reduced by streams?

Not sure how much this will help. Using streams in your use case according to me is not simplifying the solution, but if you want to use then you can do something like this in your code.

 Map<String,Object> stats=new HashMap<>();
       List<String> roles = new ArrayList<>();
        stats.entrySet().stream()
                .forEach(i -> {
                    if (i.getKey().contains("roles")) {
                        roles.add((String)i.getValue());
                    } else if(i.getKey().contains("attributes")){
                        Map<String, String> roleMap=  (Map<String, String>)i.getValue();
                        roleMap.entrySet().stream().forEach(j-> {
                            if (j.getValue()
                                .equalsIgnoreCase("true"))
                                roles.add(j.getKey());
                    });
                    }
                });
 stats.keySet().stream().filter(s->s.equals("roles")).findFirst().map(s->stats.get("roles")).orElseGet(()->{
        List list=  Lists.newArrayList();
        stats.get("attributes").foreach((k,v)->{
             if v;list.add(k)
         })
       return list;
    })

If the values of the keys roles and attributes were of same type ( List<String> ) you could easily do something like

List<String> roles = stats.getOrDefault("roles",
                          stats.getOrDefault("attributes", new ArrayList<>()));

You could still use this approach, but since the assosiated values are of different types you need to make some casting which makes your code maybe a little bit unintuitive:

Map<String, Object> stats = new HashMap<>();
stats.put("roles", Arrays.asList("role1", "role2"));
stats.put("attributes", Map.of("id", "false", "name", "true"));

List<String> roles = (List<String>) stats.getOrDefault("roles",
                     ((Map<String, String>) stats.getOrDefault("attributes", new HashMap<>()))
                                        .entrySet()
                                        .stream()
                                        .filter(i -> i.getValue().equalsIgnoreCase("true"))
                                        .map(Map.Entry::getKey)
                                        .collect(Collectors.toList()));
System.out.println(roles);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM