15R6
15R6

Reputation: 307

Handling nested if/else statements using Java 8 streams

I have a condition where there are some checks to be made in order to create an object. I am using Streams for this, and I'm having a tough time in getting this done.

The input is a HashMap object with key/value pairs and output should be below.

| userrole   | userid | username | output   |
|------------|--------|----------|----------|
| "" (blank) | 111    | amathews | 111      |
| ""         |        | amathews | amathews |
| Admin      | 111    | amathews | 111      |
| Admin      | 111    | ""       | 111      |
| Admin      |        | amathews | Admin    |

This is how the precedence is: userid>userrole>username.

Each HashMap object will contain userrole/username/userid as key and its values along with other key/value pairs. We will have a bunch of nested if/else statements to accomplish this task in prior versions of Java.

Here is my code:

map.entrySet().stream()
        .filter(e -> e.getValue() instanceof String || e.getValue() instanceof Integer)
        .filter(e -> e.getKey().contains("userrole") || e.getKey().contains("userid") || e.getKey().contains("username") )
        .map(e -> e.getValue())
        .collect(Collectors.toList());

I know that the way I have written map function in the Stream is not correct too. How to accomplish this in java 8? I do not know how to add the nested if/else part here.

Edit : Sorry If I hadn't stated the problem precisely. Here is the code snippet:

public List<UserAction> getUserActionList(Map<String, String> map)
    {
        String userRole = map.get("userrole");
        String userName = map.get("username");
        String userId = map.get("userid");

        String output = null;
        // if userrole, userid and username are not null/empty, then output is userid 
        if(!checkForNullEmpty(userRole) && !checkForNullEmpty(userId) && !checkForNullEmpty(userName))
            output = userId;
        // if userrole and userid are null/empty and username is not empty/null, then output is username
        else if(checkForNullEmpty(userRole) && checkForNullEmpty(userId) && !checkForNullEmpty(userName))
            output = userName;
        // if userid and username are null/empty and userrole is not empty/null, then output is userrole
        else if(!checkForNullEmpty(userRole) && checkForNullEmpty(userId) && checkForNullEmpty(userName))
            output = userRole;

        List<UserAction> udList = new ArrayList<>();
        // Add the map and output into a UserAction object
        udList.add(new UserAction(map, output));

        return udList;

    }

I had handled only 3 conditions here as per the table. So this has to refactored to use java 8 Streams. I hope it makes sense now.

Upvotes: 4

Views: 14817

Answers (2)

Bohemian
Bohemian

Reputation: 424993

If at least one of the values is guaranteed, you could refactor it like this:

public List<UserAction> getUserActionList(Map<String, String> map) {
    return Stream.of("userid", "username", "userrole")
        .map(map::get)
        .filter(s -> !checkForNullEmpty(s))
        .limit(1)
        .map(output -> new UserAction(map, output))
        .collect(Collectors.toList());
}

If it is not guaranteed that at least one value will be non-null, it's a little uglier, but not too bad:

public List<UserAction> getUserActionList(Map<String, String> map) {
    return Stream.of("userid", "username", "userrole")
        .map(map::get)
        .filter(s -> !checkForNullEmpty(s))
        .limit(1)
        .map(output -> new UserAction(map, output))
        .map(Collections::singletonList)
        .findFirst()
        .orElseGet(() -> Arrays.asList(new UserAction(map, null)));
}

Upvotes: 3

yyunikov
yyunikov

Reputation: 5897

It's not really clear about the task you need to accomplish, but in general, everything that you need to write in your if statements you can do with filter() method from Stream API. Then, in map() method you'd have the exact logic which is needed to be done with the data (e.g. transforming it to some other type or getting values which are needed). collect() method is used to create a result from the Stream, e.g. list, set, map, single object or anything else. For example:

map.entrySet().stream()
                .filter(e -> {
                    // filter the data here, so if isStrOrInt or containsUserData is false - we will not have it in map() method
                    boolean isStrOrInt = e.getValue() instanceof String || e.getValue() instanceof Integer;
                    boolean containsUserData = e.getKey().contains("userrole") || e.getKey().contains("userid") || e.getKey().contains("username");
                    return isStrOrInt && containsUserData;
                })
                .map(e -> {
                    if (e.getKey().contains("userrole")) {
                        // do something
                    }
                    // some more logic here
                    return e.getValue();
                })
                .collect(Collectors.toList());
                // or e.g. .reduce((value1, value2) -> value1 + value2);

If you need to create a single object in the end, you would probably need reduce() method. I recommend you to check reduction operations, general information about Stream API to understand how they work.

Upvotes: 2

Related Questions