Search code examples
javareactive-programmingproject-reactorflux

Why Flux.zip accept predefined Function but not an anonymous function?


when learning Flux (reactive-core) in java, I meet following questions about Function.

This is Flux.zip() method signature:

 public static <I, O> Flux<O> zip(
      final Function<? super Object[], ? extends O> combinator, 
                    Publisher<?extends I>... sources) {
   return zip(combinator, Queues.XS_BUFFER_SIZE, sources);
}

And when I try to invoke this method:



Flux<User> userFluxFromStringFlux(Flux<String> usernameFlux, Flux<String> firstnameFlux, Flux<String> lastnameFlux) {
        // predefined function taking object[] and returns User
        Function<Object[], User> function = array -> new User(array[0].toString(),array[1].toString(), array[2].toString());
        // it is working without error 
        Flux.zip(function, usernameFlux, firstnameFlux, lastnameFlux);


        // this is also working without error
        Flux.zip(array -> {
            return new User(array[0].toString(),array[1].toString(), array[2].toString());
            }, usernameFlux, firstnameFlux, lastnameFlux);


        // but this has error with array[0] "Array type expected; found: 'org.reactivestreams.subscriber<capture<? super java.lang.object>>'"
        Flux.zip(array ->  new User(array[0].toString(),array[1].toString(), array[2].toString()), usernameFlux, firstnameFlux, lastnameFlux);
        return null;
    }

The third way which using anonymous function, but IDEA reports that there is a error :

Array type expected; found: 'org.reactivestreams.subscriber>.

I wonder why predefined Function and anonymous function with explict return is working but anonymous function?

I appreciate your help.


Solution

  • Not a compiler expert, but I think it has to do with the java compiler seeing an ambiguity with the short form lambda: is what you are passing an inline Publisher (since it is a functional interface) or a Function?

    This confusion is made possible because the short form doesn't have an explicit return statement: in the case of the Publisher option it would mean you create a User to immediately be garbaged collected, but that's not the sort of things the compiler will forbid you to do.

    So the target type of the lambda is assumed to be Publisher, and thus array is inferred to be a Subscriber. But then the array index operator is used on it, which surely must be wrong.

    On the other hand, putting in the brackets { } removes that ambiguity by having an explicit return type that seem to be used in the inference. To the compiler you can no longer be representing a Publisher, so the next candidate (Function) is used.

    Another way of removing the ambiguity is to show the compiler that the array is... an array:

    Flux.zip((Object[] array) -> new User(array[0].toString(),array[1].toString(), array[2].toString())
                    , usernameFlux, firstnameFlux, lastnameFlux);