Home > other >  Java optional stream collector to list from two sources else null?
Java optional stream collector to list from two sources else null?

Time:08-31

I apologize in advance if this question has been asked, but I have been struggling to figure this out for a few hours now (googling everything I can) and really hope someone could help.

I am trying to collect two String values, which I am trying to get from a source, in to a single String, and return null if these values do not exist (source.getA returns null).

So far, I have come up with this code:

if (source.getA() != null && source.getB() != null) {
    target.setAAndB(Stream.of(source.getA(), source.getB())
            .map(String::valueOf)
            .collect(Collectors.joining(" ")));
} else {
    target.setAandB(null);
}

How do I turn this in to a nice looking chain? I know there is a way, but I feel like I am missing a trick here.

EDIT:

target.setAandB(
        Optional.of(
                Stream.of(source.getA(), source.getB())
                        .map(String::valueOf)
                        .collect(Collectors.joining(" "))
        ).orElse(null)
);

Made a bit of progress, but here the orElse will not work, because the collector still returns a string with two null strings combined.

CodePudding user response:

Ternary operator can be used

target.setAandB(Objects.isNull(source.getA()) && Objects.isNull(source.getB()) ? null 
           : Stream.of(source.getA(), source.getB())
                  .map(String::valueOf).collect(Collectors.joining(" ")));

CodePudding user response:

There are no benefits in hiding conditional logic by using Optional.

See the answer by @StuartMarks, Java and OpenJDK developer.

The primary use of Optional is as follows:

Optional is intended to provide a limited mechanism for library method return types where there is a clear need to represent "no result," and where using null for that is overwhelmingly likely to cause errors.

A typical code smell is, instead of the code using method chaining to handle an Optional returned from some method, it creates an Optional from something that's nullable, in order to chain methods and avoid conditionals.

It is not justifiable to create Optional to avoid null-checks. It obscures the logic and makes your code harder to read.

And using Streams just in order to concatenate only two Strings is clearly an overkill. We have enough tools that, apart from streams.

That said, your code might be written like that:

if (source.getA() != null && source.getB() != null) {
    target.setAAndB(String.join(" ", source.getA().toString(), source.getB().toString());
} else {
    target.setAandB(null);
}

Alternatively, you can introduce a method responsible for generating this String:

public String getAB() {
    
    return source.getA() == null || source.getB() == null ? null :
        String.join(" ", source.getA().toString(), source.getB().toString();
}

Note: that if getA() and getB() are not plain getters, and source object does something behind the scenes to fetch the data, you need to store both into local variables instead of fetching twice.

  • Related