Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I convert lambda parameters to usable objects?

I'm trying to stream a list of Doubles into a Map<Double, Double>, where the keys are the Doubles in the original list, and the values are some computed value.

This is what my code looks like:

// "values" is a List<Double> that was passed in
ImmutableMap<Double, Double> valueMap = values.parallelStream()
    .collect(Collectors.toMap(p -> p, p -> doThing(values, p)));

private Double doThing(List<Double>, Double p) {
    Double computedValue = 0.0;
    // Do math here with p
    return computedValue;
}

However, IntelliJ is complaining that p -> p is not a valid lambda expression - it's complaining about a cyclic inference. I'm also getting an error when I call doThing, because p is a lambda parameter and not a Double.

When I try to cast p to a Double in the call to doThing, that fails to cast.

Am I missing something really obvious? It seems like there's no way to actually do anything with my lambda parameters...

like image 909
sichinumi Avatar asked Oct 28 '15 20:10

sichinumi


People also ask

How do you accept a lambda function as a parameter in Java?

Basically to pass a lamda expression as a parameter, we need a type in which we can hold it. Just as an integer value we hold in primitive int or Integer class. Java doesn't have a separate type for lamda expression instead it uses an interface as the type to hold the argument.

Does lambda expression create object?

Yes, any lambda expression is an object in Java.

What are the two conditions required for using a lambda function in a stream?

In order to match a lambda to a single method interface, also called a "functional interface", several conditions need to be met: The functional interface has to have exactly one unimplemented method, and that method (naturally) has to be abstract.


2 Answers

I think the problem here is simply that your collecting operation returns a Map<Double, Double> but the type of valueMap is ImmutableMap<Double, Double>.

You also forgot to give a name for the List<Double> parameter in doThing but I assume it was only a typo when writing the question.

like image 73
Bubletan Avatar answered Oct 14 '22 22:10

Bubletan


As stated, the problem is that Collectors.toMap accumulates the element into Map<K,U> (the current implementation returns an HashMap but it's an internal detail).

If you want to collect into an ImmutableMap, you can use the collectingAndThen collector.

Use Collectors.toMap as the downstream collector and provide the function map -> ImmutableMap.copyOf(map) as a finisher.

ImmutableMap<Double, Double> valueMap = values.stream()
                .collect(collectingAndThen(toMap(p -> p, p -> doThing(values, p)), ImmutableMap::copyOf));
like image 22
Alexis C. Avatar answered Oct 14 '22 22:10

Alexis C.