Home > Mobile >  Filter List to get specific object or else return default
Filter List to get specific object or else return default

Time:08-18

class Home {
    String homeName;
    String properties;
}
List<Home> list = new ArrayList<>();
list.add(new Home("DefaultHome","other"));
list.add(new Home("MyHome","other"));
list.add(new Home("BigHome","other"));

I want to stream this list to find valid home properties or return DefaultHome properties.

So if I do the following, it should return me DefaultHome properties.

list.stream().filter(a -> a.gethomeName().equals("HomeNotFound")).findFirst();

If "HomeNotFound" is not in the list, I should get Object of DefaultHome which is new Home("DefaultHome","other")

CodePudding user response:

Method findFirst() returns an Optional result.

You need to use Optional.orElse() as @Johannes Kuhn has pointed out in the comments:

Home home = list.stream()
    .filter(a -> a.getHomeName().equals("someName"))
    .findFirst()
    .orElse(new Home("DefaultHome","other"));

CodePudding user response:

Add with an OR a second condition to include your default value, sort by name equals DefaultHome so that it is allways at the end:

list.stream().filter(a -> a.getHomeName().equals("HomeNotFound") || a.getHomeName().equals("DefaultHome"))
    .sorted(Comparator.comparing(h -> "DefaultHome".equals(h.homeName)))
    .findFirst();

CodePudding user response:

I'd like to improve on @Alexander Ivanchenko's answer, but I don't have enough reputation to add comments yet.

Using orElse is fine for constant values and variables, but if you pass a constructor directly to orElse will call the constructor and instantiate a new object before the orElse method is called. This is because the arguments to methods are resolved before the methods are called.

Alternatively, one could use orElseGet, which takes a Supplier function. This function is only called if the Optional is empty. So, if we rewrite Alexander's answer as this:

Home home = list.stream()
    .filter(a -> a.getHomeName().equals("someName"))
    .findFirst()
    .orElseGet(() -> new Home("DefaultHome","other"));

, the constructor will only be executed when no match was found in the stream; in other words, only when it is needed.


I'd like to add that if you want to search through a list of Houses efficiently, you should not use a list, but a Map:

Map<Home> homeMap = new HashMap<>();

homeMap.put("DefaultHome", new Home("DefaultHome","other"));
homeMap.put("MyHome", new Home("MyHome","other"));
homeMap.put("BigHome", new Home("BigHome","other"));

homeMap.getOrDefault("HomeNotFound", new Home("DefaultHome","other"));

This code, however, has the same problem as the Optional.orElse method: the constructor is called every time, regardless the home is in the map or not. A simple solution for this is to store the default Home as a constant:

public static final String DEFAULT_HOME = new Home("DefaultHome","other")

Map<Home> homeMap = new HashMap<>();
homeMap.put(DEFAULT_HOME.getHomeName(), DEFAULT_HOME);
homeMap.put("MyHome", new Home("MyHome","other"));
homeMap.put("BigHome", new Home("BigHome","other"));

homeMap.getOrDefault("HomeNotFound", DEFAULT_HOME);
  • Related