user7865286
user7865286

Reputation: 354

Understading Java types for stream operations

When using stream, very similar two pieces of code behave differently.

I cannot understand what the compiler's error is trying to convey.

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static java.util.stream.Collectors.toList;

public class Main {

    public static void main(String[] args) {

        // Pythangorian stream
        List<List<Integer>> ret = IntStream.range(1, 10).boxed()
                .flatMap(a -> IntStream.range(a, 10)
//                                       This works fine...
//                                       .mapToObj(b -> Arrays.asList(a, b, a*a + b*b))
                                       .mapToObj(b -> Arrays.asList(a, b, Math.sqrt(a*a + b*b)))
//                                       .filter(t -> Math.sqrt(t.get(2)) % 1 == 0))
                                       .filter(t -> t.get(2) % 1 == 0))
                .collect(toList());

        System.out.println(ret);
    }
}

If Math.sqrt is used in mapToObj, it gets compiler error. If not, it works fine. The error message is like so:

Error:(21, 62) java: bad operand types for binary operator '%'
  first type:  java.lang.Number&java.lang.Comparable<? extends java.lang.Number&java.lang.Comparable<?>>
  second type: int
Error:(22, 25) java: incompatible types: inference variable T has incompatible bounds
    equality constraints: java.util.List<java.lang.Integer>
    lower bounds: java.util.List<java.lang.Number&java.lang.Comparable<? extends java.lang.Number&java.lang.Comparable<?>>>

Can someone please tell me what this error message is saying? I am aware of my little knowledge in Java is the main concern. Can you please guide me where to look to understand this?

Upvotes: 1

Views: 79

Answers (1)

k13i
k13i

Reputation: 4331

The reason is you are trying to collect to List<Integer> but you should use List<? extends Number> instead. Moreover your filter method can be removed because this condition is always true, i.e. any integer can be divided by one without remainder.

Working code can look like this:

List<List<? extends Number>> ret = IntStream.range(1, 10)
        .boxed()
        .flatMap(a -> IntStream.range(a, 10)
                .mapToObj(b -> Arrays.asList(a, b, Math.sqrt(a * a + b * b))))
        .collect(toList());

The reason is Math.sqrt() returns double and a and b are integers so you cannot collect all of these three to List<Integer>. The second approach is to collect to List<Double> and use explicit cast from integer to double:

List<List<Double>> ret = IntStream.range(1, 10)
        .boxed()
        .flatMap(a -> IntStream.range(a, 10)
                .mapToObj(b -> Arrays.asList((double) a, (double) b, Math.sqrt(a * a + b * b))))
        .collect(toList());

Upvotes: 4

Related Questions