dma_k
dma_k

Reputation: 10639

How to force lambda type to a specific one?

Suppose I have a function with such signature:

public static <T> List<Future<T>> invokeAll(Stream<Callable<T>> tasks) {
   ... submit given tasks using executor ...
}

and I have a stream of data, which should be "wrapped" into callable and passed to this function. Naive mapping like below does not work:

Stream<String> ids = Stream.of("1", "2", "3");

invokeAll(ids.map((id) -> {
    // Do a long computation with given ID...
    return Boolean.TRUE; // Compilation error: Type mismatch: cannot convert from Boolean to Callable<Object>
}));

One solution would be to return lambda that returns lambda:

invokeAll(ids.map((id) -> {
    return () -> {
        // Do a long computation with given ID...
        return Boolean.TRUE;
    };
}));

another (in some way equivalent) is to use helper function:

public static <T> Callable<T> createCallable(T id) {
    return () -> {
        return id;
    };
}

invokeAll(ids.map(ThisClass::createCallable));

but maybe there is better / shorter way of doing the same? E.g. somehow tell the compiler that it needs to create a Callable that returns a given value:

invokeAll(ids.map((Function<String, Callable<Boolean>>) (id) -> {
    // Do a long computation with given ID
    return Boolean.TRUE;
}));

Thanks for any suggestion.

Upvotes: 1

Views: 383

Answers (1)

Michael
Michael

Reputation: 44140

Let's ignore lambdas for a moment, because I think they're the source of the confusion. Let's use good old anonymous classes:

invokeAll(
    ids.map(
        new Function<String, Callable<Boolean>>()
        {
            @Override
            public Callable<Boolean> apply(String str)
            {
                return new Callable<Boolean>()
                {
                    @Override
                    public Boolean call() throws Exception
                    {
                        return Boolean.TRUE;
                    }
                };
            }
        }
    )
);

What you're effectively asking is "how I can automatically do this:"

invokeAll(
    ids.map(
        new Function<String, Callable<Boolean>>()
        {
            @Override
            public Callable<Boolean> apply(String str)
            {
                return Boolean.TRUE;
            }
        }
    )
);

Of course, you can't. A Boolean is not a Callable<Boolean>. So the solutions are limited to what you've already identified:

1) to use a lambda to create the Callable:

() -> Boolean.TRUE 
() -> { return Boolean.TRUE; }

2) to create a method which does this for you. Such as method is likely to more verbose than option #1 so it doesn't gain you anything.

Sorry, there's no way other to automagically make this any better.

Upvotes: 5

Related Questions