Are the Streams in Java 8 monads?

Yes, java.util.stream.Stream satisfies Monad laws.

Following prerequisites are:

  1. Stream should be Functor, i.e. to provide following function fmap :: (a -> b) -> M a -> M b. If we will look into sources, we will see that it already has function Stream<R> map(Function<T, R> mapper)

  2. It should have unit (a.k.a return) operation: unit :: a -> M a. This one is obvious: Stream<T> of(T t).

  3. It should have bind or join operation:

    1. bind :: M a -> (a -> M b) -> M b : Stream<R> flatMap(Function<T, Stream<R>> mapper)
    2. join :: M (M a) -> M a: this one is not present in Stream but we can infer it from bind.

Now we have required functions. But it's not enough yet to call it monad! We need to prove that monad laws are valid. Let's look at them:

Left identity: (return a) bind f <=> f a

        Function<String, Stream<Integer>> f = str -> str.chars().boxed();
        String a = "abc";
        Stream<Integer> left = Stream.of(a).flatMap(f);
        Stream<Integer> right = f.apply(a);
        //left should be same as right

Right identity: m bind unit <=> m

        Stream<String> stream = Stream.of("abc", "def");
        Stream<String> left = stream.flatMap(str -> Stream.of(str));
        // left should be same as Stream.of("abc", "def")

Associativity: (m bind f) bind g <=> m bind (\x -> f x bind g)


        Function<Integer, Stream<String>> f = integer -> Arrays.stream(Integer.toHexString(integer).split(""));
        Function<String, Stream<BigInteger>> g = string -> Stream.of(string).map(str -> new BigInteger(str, 16));

        Stream<Integer> mLeft = Stream.of(47789, 61453);
        Stream<BigInteger> left = mLeft.flatMap(f).flatMap(g);

        Stream<Integer> mRight = Stream.of(47789, 61453);
        Stream<BigInteger> right = mRight.flatMap(integer -> f.apply(integer).flatMap(g));
        //left should be same as right        

So it looks like Streams are really monads! But be wary, same situation might happen as with Optional which sometimes violates Monadic laws. I have a gut feeling that it might be violated in some cases if you will use parallel() because it can change execution order. If you know where it could happen please comment below.


EDIT The answer below is incorrect (retained here for history).

Yes, in each case the functor consists of the class and its map method, and the two natural transformations are of and flatMap(identity).

The correct answer seems to be here.


If you know Haskell: Java's Stream is nothing else then Haskell's list monad [] and Java's Optional is nothing else the Haskell's Maybe monad.