Batterie
Batterie

Reputation: 19

How to fix "Intermediate Stream methods should not be left unused" on Sonarqube

I found this bug on Sonarqube:

private String getMacAdressByPorts(Set<Integer> ports) {
    ports.stream().sorted(); // sonar list show "Refactor the code so this stream pipeline is used"
    return ports.toString();
} //getMacAdressByPorts

I have been searching for a long time on the Internet, but it was no use. Please help or try to give some ideas how to achieve this.

Upvotes: 0

Views: 2017

Answers (3)

Batterie
Batterie

Reputation: 19

I finally solved the problem used the code below.

private String getMacAdressByPorts(Set<Integer> ports) {
        return ports.stream().sorted().collect(Collectors.toList()).toString();

Upvotes: 0

Yassine Badache
Yassine Badache

Reputation: 1851

From the Sonar Source documentation about this warning (emphasis of mine):

Stream operations are divided into intermediate and terminal operations, and are combined to form stream pipelines. After the terminal operation is performed, the stream pipeline is considered consumed, and cannot be used again. Such a reuse will yield unexpected results.

Official JavaDoc for stream() gives more details on sorted() (emphasis of mine):

Returns a stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed. [...] This is a stateful intermediate operation.

This implies that only using sorted() will yield no result. From the Oracle Stream package documentation (still emphasis of mine):

Stream operations are divided into intermediate and terminal operations, and are combined to form stream pipelines. A stream pipeline consists of a source (such as a Collection, an array, a generator function, or an I/O channel); followed by zero or more intermediate operations such as Stream.filter or Stream.map; and a terminal operation such as Stream.forEach or Stream.reduce.

Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.

sorted() returns another stream(), and not a sorted list. To solve your Sonar issue (and maybe your code issue, in that manner), you have to call a terminal operation in order to run all the intermediate operations. You can find a list (non-exhausive, I think) of terminal operations on CodeJava for instance.


In your case, the solution might look like:

private String getMacAdressByPorts(Set<Integer> ports) {
    /* Ports > Stream > Sort (intermediate operation) > 
    / Collector (final operation) > List > String
    / Note that you need to import the static method toList()
    / from the Collector API, otherwise it won't compile
    */

    return ports.stream().sorted().collect(toList()).toString();
}

Upvotes: 2

daniu
daniu

Reputation: 14999

The sorted() method has no effect on the Set you pass in; actually, it's a non-terminal operation, so it isn't even executed. If you want to sort your ports, you need something like

return ports.stream().sorted().collect(Collectors.joining(","));

EDIT: as @Slaw correctly points out, to get the same format you had before (ie [item1, item2, item3], you also need to add the square brackets to the joining collector, ie Collectors.joining(", ", "[", "]"). I left those out for simplicity.

Upvotes: 5

Related Questions