Perfoming null-checks while collecting with Collectors.groupingBy

241 Views Asked by At

I have the following piece of code which groups the given entries (activities, which is Iterable<activity>) based on IDs.

For the final result, I want it to return a Map of ID to Iterables of the entries grouped by that ID.

For example: Map<String, Iterables<activity>>.

Right now, it returns a Map<String, List<activity>>.

        stream(activities)
            .collect(
                groupingBy(
                    activity -> {
                      if (activity.getID()) {
                        return activity.getID();
                      } else {
                        return activity.getName();
                      }
                    }));

I am unable to figure out a way to do this.

1

There are 1 best solutions below

0
On

There's no such notion in Java as truthy values, which exists in languages like javascript. I.e. String can't be resolved into boolean automatically (what your code attempts to do).

There are multiple ways of how you can check whether the given value is null and provide an alternative value.

If name attribute is guaranteed to be non-null you can use static method requireNonNullElse() of the Objects utility class:

.collect(Collectors.groupingBy(act -> Objects.requireNonNullElse(act.getID(), act.getName()));

If name attribute is nullable, then you have to provide a default value that will be used in case if both id and name equal to null. Because null key is not allowed with Collectors.groupingBy() and will result in NullPointerException at runtime.

For the case when both field could be null I suggest extracting the logic for obtaining the key into a separate method.

public static String getKey(Action action) {
    return action.getID() != null ? action.getID() :
         action.getName() != null ? action.getName() : "defaultKey";
}

Which can be used inside the collector like that:

.collect(Collectors.groupingBy(act -> getKey(act)); // or as a method reference MyClass::getKey

Sidenote: by convention, names of classes in Java should start with a capital letter: Student, Employee, Activity.