Wollo
Wollo

Reputation: 60

Reusing a chain of Stream Operations

I'm looking for a readable way to reuse a chain of stream operations.

The idea is that I have a certain sequence of actions that I want to apply to several streams in between other operations. The other operations are not identical between streams.

So, for example, for every stream, I want to change the case of a String, trim it, nullify empty Strings and then filter out nulls, and lastly, eliminate duplicates, like this:

In both cases, I do this sequence of actions:

.map( String::trim ).map( Strings::emptyToNull ).filter( Objects::nonNull ).distinct()

I currently duplicate that chain and put it between other actions for multiple streams:

myStream1.doSomeStuff().map( String::trim ).map( Strings::emptyToNull ).filter( Objects::nonNull ).distinct().doOtherStuff();

myStream2.doSomethingElse().map( String::trim ).map( Strings::emptyToNull ).filter( Objects::nonNull ).distinct().doSomethingElseStill();

Is there a good way to avoid rewriting that piece of code? Obviously, it's possible for the two map() actions, but is there a way for this combination of actions?

Upvotes: 2

Views: 549

Answers (1)

Yassin Hajaj
Yassin Hajaj

Reputation: 21965

You could wrap your Stream<String> in a function

public Stream<String> trimAndFilterOutEmptyStringsAndGetDistinctElements(Stream<String> stream) {
    return stream.map(String::trim)
                 .map(Strings::emptyToNull) // or use not(String::isEmpty) like suggested below
                 .filter(Objects::nonNull)
                 .distinct();
}

Which could be used like this

Stream<String> myStream1DownStream = trimAndFilterOutEmptyStringsAndGetDistinctElements(myStream1);
Stream<String> myStream2DownStream = trimAndFilterOutEmptyStringsAndGetDistinctElements(myStream2);

myStream1DownStream.doOtherStuff();
myStream2DownStream.doSomethingElseStill();

BTW I'd use

.filter(Predicate.not(String::isEmpty))  

instead of

.map(Strings::emptyToNull)
.filter(Objects::nonNull)

There is a more questionnable way, it is to use Lombok's @ExtensionMethod experimental feature. I would not use it in production

You'll then be able to extend the functionalities of the Stream class with custom methods

public class Extensions {
    public static Stream<String> trimAndFilterOutEmptyStringsAndGetDistinctElements(Stream<String> stream) {
        return stream.map(String::trim)
                     .map(Strings::emptyToNull) // or use not(String::isEmpty) like suggested
                     .filter(Objects::nonNull)
                     .distinct();    
    }
}

The usage is the following

myStream1.trimAndFilterOutEmptyStringsAndGetDistinctElements()
         .doOtherStuff();

More info

Upvotes: 5

Related Questions