8

What would be the best way of handling null if we have senario like below

//mocking for demonstraton  
studentsByCourseRoster.setUsers(null);

studentsByCourseRoster.getUsers().stream().forEach(user -> {
    final UserDTOv2 userDTO = new UserDTOv2();
    userDTO.populateUserDataFromUserDTO(user, groupedUsers);
    users.add(userDTO);
});
Mureinik
  • 297,002
  • 52
  • 306
  • 350
Seth De
  • 417
  • 6
  • 18
  • where do you have to handle `null`? – Eran Dec 20 '18 at 07:11
  • 2
    How about `if(studentsByCourseRoster.getUsers() != null)`? – ernest_k Dec 20 '18 at 07:12
  • 5
    Just don’t set users to `null`. Allowing a `List` to become `null` (rather than empty), is a sign of a defective software design. Instead of adding workarounds at the reading side, fix the design. – Holger Dec 20 '18 at 07:36

5 Answers5

6

If you want to retain the single statement structure, you could use Optional.ofNullable and replace null with an empty list:

Optional.ofNullable(studentsByCourseRoster.getUsers())
        .orElse(Collections.emptyList())
        .forEach(user -> {
                     final UserDTOv2 userDTO = new UserDTOv2();
                     userDTO.populateUserDataFromUserDTO(user, groupedUsers);
                     users.add(userDTO);
         });
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • 2
    you do not need to `.stream()` btw, as a matter of fact, this violates the spec with that `.stream()` – Eugene Dec 20 '18 at 13:49
  • @Eugene good point thanks. I tried to have the minimal set of changes from the OP's code, but you're right, the `stream()` call is redundant. I removed it. – Mureinik Dec 21 '18 at 08:40
4

With a slight modification to Mureinik's answer I would instead use :

List<UserDTOv2> users = Optional.ofNullable(studentsByCourseRoster.getUsers())
        .orElse(Collections.emptyList())
        .stream()
        .map(user -> {
            UserDTOv2 userDTO = new UserDTOv2();
            userDTO.populateUserDataFromUserDTO(user, groupedUsers);
            return userDTO;
        }).collect(Collectors.toList());

Using Stream.ofNullable in Java 9

List<UserDTOv2> users = Stream.ofNullable(studentsByCourseRoster.getUsers())
        .map(user -> {
            UserDTOv2 userDTO = new UserDTOv2();
            userDTO.populateUserDataFromUserDTO(user, groupedUsers);
            return userDTO;
        }).collect(Collectors.toList());
Community
  • 1
  • 1
Naman
  • 27,789
  • 26
  • 218
  • 353
1

What would be the best way of handling null if we have senario like below

The simplest solution to that under your current design is to do so with an if statement.

That is not saying it's the best way to "handle" this problem but rather the best way to handle this is never to allow the list to be in a null state in the first place as also mentioned in the comments.

Have an empty list as the default value, this will save you quite a huge amount of if checks around your codebase depending on how many times getUsers() is being used and most importantly you wouldn't have to worry about NullPointerExeception's because they should never occur.

On another note, whenever you seem to see your self calling stream() on some collection and then immediately calling forEach you should realise it's wrong; 1) in the sense that you could easily call forEach directly on the list i.e. studentsByCourseRoster.getUsers().forEach(...) 2) streams and side-effect just don't work together well.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
0

You can also filter null objects by filter(Objects::nonNull):

studentsByCourseRoster.getUsers().stream().filter(Objects::nonNull).forEach(user -> {
    final UserDTOv2 userDTO = new UserDTOv2();
    userDTO.populateUserDataFromUserDTO(user, groupedUsers);
    users.add(userDTO);
});
pobu
  • 402
  • 1
  • 5
  • 13
  • Actually, the list is null first-hand, so you will get NPE right at `studentsByCourseRoster.getUsers()` – Toan Lu Dec 20 '18 at 07:27
  • If there were empty collection, i will not get NPE. Streams process all elements of a source, if there are no elements, no action will be taken. – pobu Dec 20 '18 at 07:32
  • 2
    Maybe you should try to run your code with `studentsByCourseRoster.setUsers(null);`, even the IDE can detect Null variable access – Toan Lu Dec 20 '18 at 07:44
0

One more way to write this with optional, in addition to correct @Murenik's answer. No need to create empty list, we can pass execution non null case only with:

    Optional.ofNullable(nullableUsers)
            .ifPresent(users -> users.forEach(user -> {
                // work with user
            }));

Nullable optional is also works very well with nested null references, e.g. we have some structure:

class User {
    @Getter
    Address address;
}

class Address {
    @Getter
    String street;
}

then instead of writing

if (user.getAddress() != null && user.getAddress().getStreet() != null) {
   // work with street
}

we can use Optional:

    Optional.ofNullable(user)
            .map(User::getAddress)
            .map(Address::getStreet)
            .ifPresent(street -> {
                // work with street
            });
udalmik
  • 7,838
  • 26
  • 40