Is it a bad practice to append operations to a Stream in different methods?

Luis Miguel :

Suppose I have a method used by multiple classes in my application. This method takes a Stream as a parameter and applies a terminal operation forEach in order to write the data to a file, something like the following:

public File writeStreamToTempFile(Stream stream) {
    stream.forEach(item -> {
        //some code to write item to a file
    }
}

There are multiple callers of this method, and in some of those methods I need to transform the data, let's say using map function, like the following:

public void exportAnimalsData() {
    Stream<Animal> animalStream = //fetch data from a DB
    animals.filter(a -> a.type.equals("dog"))
           .map(a -> //Do something useful to transform the Dogs);

    writeStreamToTempFile(animalStream);
}

Not all the callers of the writeStreamToTempFile method need to perform additional operations on the stream.

So my question is:

Is it a bad practice to apply operations to a stream in different methods?

I read somewhere that Stream should never be the return type of a method (the caller does not know if that method already consumes the stream or not), does it also apply for parameters of a method?

Should I just apply all the operations needed in the same method or is it ok to append intermediate operations to the same stream in a different method?

jbx :

i read somewhere that Stream should never be the return type of a method

Not sure where you read that a Stream should never be the return type of a method. (Can you update your question with a link?).

On the contrary, Brian Goetz, one of the designers of the Stream API, clearly thinks otherwise:

https://stackoverflow.com/a/24679745/340088

(the caller does not know if that method already consume the stream or not)

If the caller is getting a Stream it is implicitly understood that the stream is usable. If you return a consumed Stream it is like returning a closed Socket or a closed InputStream. While possible syntactically, it is just bad coding. Doesn't mean you shouldn't return a Socket or an InputStream from a method just because some bad coder occasionally returns one in a bad state.

On the contrary, monadic style objects are intended to be returned. Stream, Optional, CompletableFuture, and all the functional interfaces (Function, Consumer, Operator, etc.) are intended to be returned so that more functional-style operations can be attached to them, without actually performing the function on the spot.

The example you posted, to me, is perfectly reasonable. You are sort of decorating your Stream with additional operations to the pipeline. You can have logic which decides which operations are added to the pipeline, and there is no reason why not to encapsulate them properly in small methods.

Furthermore, if the stream is very large carrying hundreds of thousands of elements, if you returned a collection, you would just be creating a huge collection in memory, incurring the cost to add them all, only to then stream them again to write them to the file. Doesn't make much sense does it?

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=86881&siteId=1