Filter Array of cookies for a specific cookie and get value of a specific cookie in Java

Viewed 1458

I am fixing some issue in a legacy module and came across this code which get the array of cookies from request object which can return null. The code looks for a specific cookie, if present then returns cookie value otherwise it returns null. Below is the existing code

final Cookie[] cookies = request.getCookies();
if (cookies != null) {
    for (int i = 0; i < cookies.length; i++) {
        final Cookie cookie = cookies[i];
        if ("random cookie".equals(cookie.getName())) {
            return cookie.getValue();
        }
    }
    return null;
}

I refactored it to something like this

final Cookie[] cookies = request.getCookies();
if (cookies != null) {
    Optional<Cookie> cookie = Arrays.stream(cookies).
            filter(e -> "random cookie".equals(e.getName())).
            findAny();
    return cookie.isPresent() ? cookie.get().getValue() : null;
}
return null;

Can the above be refactored in a better way?

2 Answers

It would be best to make the method return Optional<String> - but if you can't then how about this:

final Cookie[] maybeCookies = request.getCookies();
return Optional.ofNullable(maybeCookies)
    .flatMap(cookies -> Arrays.stream(cookies)
         //Find the cookie if we can.
         .filter(e->"random cookie".equals(cookie.getName()))
         .findAny()
    )
    //If we have a matching cookie, return its value.
    .map(e->e.getValue())
    //otherwise return null to retain original behaviour
    .orElse(null);

I would refactor this into a method which returns Optional<String>:

public Optional<String> getCookieValue(String name) {
   final Cookie[] cookies = request.getCookies();
   if(cookies == null) return Optional.empty();
   return Arrays.stream(cookies)
                .filter(e -> name.equals(e.getName()))
                .findAny().map(Cookie::getValue);
} 

then the caller of this method would do any of these depending on how they intend to use the result:

getCookieValue("random cookie").ifPresent(e -> { ... });
getCookieValue("random cookie").orElse(null);
....
....

return Optional<String> to avoid dealing with nullity and let the user of this method decide what to do in the "no value case". This also reads better to the user of this API etc....

However, if you wish to persist with your current method signature then you can at least improve it to:

final Cookie[] cookies = request.getCookies();
if(cookies == null) return null; // avoids if blocks
return Arrays.stream(cookies)
             .filter(e -> "random cookie".equals(e.getName()))
             .findAny()
             .map(Cookie::getValue)
             .orElse(null);
Related