15

I'm looking for a succinct way to rewrite a piece of Java code so that it uses streams to convert an array to a list in a null-safe fashion. Here's the original code:

public MailObject toMailObject(final String[] ccAddresses) {
    final MailObject mailObject = new MailObject();

    // line of code to be altered
    mailObject.setCcAddresses(ccAddresses == null 
        ? Collections.emptyList() : Arrays.asList(ccAddresses));

    // other necessary code

    return mailObject;
}

I've thought of doing something like this:

// psuedocode that obviously doesn't compile
Optional.ofNullable(ccAddresses).SOMETHING.orElse(Collections.emptyList());

where SOMETHING would be along the lines of:

Arrays.stream(ints).collect(Collectors.toList());

but I can't seem to get the syntax quite right.

This question was helpful but didn't exactly address my issue. Could anyone point me in the right direction? I feel like I'm close...

Thank you very much for your time.

risingTide
  • 1,754
  • 7
  • 31
  • 60

3 Answers3

13

You might use the map :

List<String> ccAddrs = Optional.ofNullable(ccAddress)
                               .map(Arrays::asList)
                               .orElse(Collections.emptyList())
Mạnh Quyết Nguyễn
  • 17,677
  • 1
  • 23
  • 51
10

In my opinion, the code that you have so far is perfectly readable. I think using a Stream for something like this will just complicate things. If you still want to use a Stream, then something like the following would work:

mailObject.setCcAddresses(Stream.ofNullable(ccAddresses)
          .flatMap(Arrays::stream)
          .collect(Collectors.toUnmodifiableList()));

As you can see, this is a more unreadable, and I wouldn't recommend it over your simple ternary expression.


Your Optional solution is slightly more readable and would look like the following:

mailObject.setCcAddresses(Optional.ofNullable(ccAddresses)
          .map(Arrays::asList)
          .orElse(Collections.emptyList()));
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • 6
    `Stream.ofNullable` requires Java 9 and `Collectors.toUnmodifiableList()` even requires Java 10. And when you’re using Java 9 or newer, you can likewise change the original code to `mailObject.setCcAddresses(ccAddresses == null? List.of(): List.of(ccAddresses));`, whose simplicity will highlight the silliness of using `Optional` or `Stream` here even more. – Holger Mar 21 '19 at 09:16
  • 1
    Good insight onto the Java versions that the first solution uses...and also into the `List.of()` possibility! Between this and the full answer by @Jacob G. there are a lot of options here; thanks! – risingTide Mar 21 '19 at 18:18
0

You can try with my strong tested code:

Fixed type method:

public static List<String> nullSafeConversion(final String[] names) {
     // Initialize all to a list
     List<String> namesList = Arrays.asList(names);
     // Create a null safe Stream
     Stream<String> nameStream = namesList.stream().flatMap(Stream::ofNullable);

     // return collected list from stream
     return nameStream.collect(Collectors.toList());
}

Generic type method:

public static <E> List<E> nullSafeConversion(final E[] e) {
    // Initialize all to a list
    List<E> eList = Arrays.asList(e);
    // Create a null safe Stream
    Stream<E> eStream = eList.stream().flatMap(Stream::ofNullable);
    // return collected list from stream
    return eStream.collect(Collectors.toList());
}

How to call:

String[] names = {"Subarata", "Talukder", null, "Software Engineer"};
Integer[] marks = {100, 55, null, 25, 66, null, 88};
    
// Print all null safe items
for (String name : nullSafeConversion(names)) {
    // Show null safe data
    System.out.println(name);
}

Outputs:

Subarata
Taluker
Software Engineer
Subarata Talukder
  • 5,407
  • 2
  • 34
  • 50