Question

I have sample code which uses Java 8 new stream functionality (get a range of int values 1 .. 20, skip the first 9, then take remaining 10, each int value: reduce by one and multiply by 2).

System.out.println(Arrays.toString(
    IntStream.rangeClosed(1, 20).skip(9).limit(10).map((new IntUnaryOperator() {
        @Override
        public int applyAsInt(int operand) {
            return operand - 1;
        }
    }).andThen(new IntUnaryOperator() {
        @Override
        public int applyAsInt(int operand) {
            return operand * 2;
        }
    })).toArray()));

The output is as follows:

[18, 20, 22, 24, 26, 28, 30, 32, 34, 36]

Now I want to replace anonymous classes with Lambda expressions. The following conversion works fine (the second anonymous class replaced with i -> i * 2 lambda expression) and I get the same output:

System.out.println(Arrays.toString(
    IntStream.rangeClosed(1, 20).skip(9).limit(10).map((new IntUnaryOperator() {
        @Override
        public int applyAsInt(int operand) {
            return operand - 1;
        }
    }).andThen(i -> i * 2)).toArray()));

However, when I replace the first anonymous class with lambda expression:

System.out.println(
    Arrays.toString(
        IntStream.rangeClosed(1, 20).skip(9).limit(10)
            .map((v -> v - 1).andThen(i -> i * 2)).toArray()));

I am not able to compile my code. The error says Operator '-' cannot be applied to '<lambda parameter>', 'int'

Compilation error

Do you know how to combine two lambda expressions with IntUnaryOperator.andThen?

I know I could use ... .limit(10).map(v -> v - 1).map(i -> i * 2).toArray() ... which works fine but I would like to find out how to use IntUnaryOperator.andThen with lambdas (if that possible).

Was it helpful?

Solution

You have to explicitly cast the first lambda expression to IntUnaryOperator. The following code works:

System.out.println(
        Arrays.toString(
                IntStream.rangeClosed(1, 20).skip(9).limit(10)
                        .map(((IntUnaryOperator) v -> v - 1).andThen(i -> i * 2)).toArray()));

OTHER TIPS

I managed to compile the code as the following (although using eclipse experimental versions):

IntUnaryOperator first = v -> v - 1;
IntUnaryOperator second = i -> i * 2;
System.out.println(Arrays.toString(IntStream.rangeClosed(1, 20).skip(9)
                .limit(10).map(first.andThen(second)).toArray()));

I understand your interest to be able to write the code without declaring first and second; however, IntUnaryOperator is a FunctionalInterface and based on how Java compiler works, a FunctionalInterface needs to have a "context" to be able to be composed the way you want it. This is why with your original code snippet Java compiler does not have a way to map your lamda expression to exactly an instance of IntUnaryOperator.

For a longer discussion take a look at this thread: http://mail.openjdk.java.net/pipermail/jdk8-dev/2013-June/002668.html

Another solution is to use the static IntUnaryOperator.identity() as a startpoint:

IntUnaryOperator.identity().andThen(v -> v - 1).andThen(i -> i * 2)

With static imports you can use just identity() too!

If IntUnaryOperator had a static method like...

static IntUnaryOperator first(IntUnaryOperator op) { return op; }

... we could simply write:

IntUnaryOperator.first(v -> v - 1).andThen(i -> i * 2)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top