In which cases Stream operations should be stateful?

前端 未结 4 804
轮回少年
轮回少年 2021-01-01 03:30

In the javaodoc for the stream package, at the end of the section Parallelism, I read:

Most stream operations accept parameters that des

4条回答
  •  余生分开走
    2021-01-01 04:15

    A stateless function returns the same output for the same inputs, "no matter what".

    It's easy to create non-stateless functions in an imperative language like Java. e.g.

        func = input -> currentTime();
    

    If we do stream.map(func) with a stateful func, the resulting stream will depend on how func is invoked at runtime; the behavior of the application will be hard to understand (but not that hard).

    If func is stateless, stream.map(func) will always produce the same stream, no matter how map is implemented and executed. This is nice and desirable.

    Note that "no matter what" implies that a stateless function must be thread-safe.


    If a function returns void, isn't it always stateless? Well... there's another connotation of stateless - invoking a stateless function should not have side effects that are "important" to the application.

    If func has no "important" side effects, it's safe to invoke func arbitarily. For example, stream.map(func) can safely invoke func multiple times even on the same element. (But don't worry, Stream is never gonna do that).

    What is an "important" side effect? That is very subjective.

    At the very least, invoking fun will cost some CPU time, which is not exactly free. This might be concerning for performance critical applications; or on expensive platforms (cough AWS).

    If func logs something on hardisk, it may or may not be an "important" side effect. (It too costs $$)

    If func queries an external service that costs dearly, it is very concerning, it can bankrupt you.

    Now, forget about money. Purely from application logic point of view, func could cause mutation to some state that the application depends on; even if func returns the same output for the same inputs, it still cannot be considered "stateless". For example, if in stream.map(func), func adds each element to a list, and later the application uses the list, the resulting list will depend on how func is invoked at runtime. This is frawned upon by functional-programmers.

    If we do stream.forEach( e->log(e) ), is it stateless? We can consider it stateless if

    • we don't care about the cost of log
    • log() can be invoked concurrently
    • we don't care about the order of log entries
    • log entries have no impact on this application's logic

提交回复
热议问题