Анонимный класс заменен лямбда-выражениями
у меня есть пример кода, который использует Java 8 новая функции потока (получить диапазон значений int 1 .. 20, пропустите первые 9, Затем возьмите оставшиеся 10, каждое значение int: уменьшите на один и умножьте на 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()));
вывод выглядит следующим образом:
[18, 20, 22, 24, 26, 28, 30, 32, 34, 36]
теперь я хочу заменить анонимные классы с лямбда-выражения. Следующее преобразование работает нормально (второй анонимный класс заменен на i -> i * 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(i -> i * 2)).toArray()));
однако, когда я заменяю первый анонимный класс лямбда-выражением:
System.out.println(
Arrays.toString(
IntStream.rangeClosed(1, 20).skip(9).limit(10)
.map((v -> v - 1).andThen(i -> i * 2)).toArray()));
Я не могу скомпилировать свой код. Ошибка говорит Operator '-' cannot be applied to '<lambda parameter>', 'int'
знаете ли вы, как объединить два лямбда-выражения с IntUnaryOperator.andThen
?
Я знаю, что мог бы использовать ... .limit(10).map(v -> v - 1).map(i -> i * 2).toArray() ...
который отлично работает, но я хотел бы узнать, как использовать IntUnaryOperator.andThen
с лямбдами (если это возможно).
3 ответов
вы должны явно передать первое лямбда-выражение IntUnaryOperator. Работает следующий код:
System.out.println(
Arrays.toString(
IntStream.rangeClosed(1, 20).skip(9).limit(10)
.map(((IntUnaryOperator) v -> v - 1).andThen(i -> i * 2)).toArray()));
мне удалось скомпилировать код следующим образом (хотя и с использованием экспериментальных версий eclipse):
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()));
Я понимаю ваш интерес, чтобы иметь возможность писать код без объявления first
и second
, однако, IntUnaryOperator
- это FunctionalInterface
и на основе того, как работает Java-компилятор, a FunctionalInterface
должен иметь "контекст", чтобы иметь возможность быть составленным так, как вы хотите. Вот почему с вашим исходным фрагментом кода Java-компилятор не имеет способа сопоставить выражение lamda с точно пример IntUnaryOperator
.
более подробно взглянуть на эту тему: http://mail.openjdk.java.net/pipermail/jdk8-dev/2013-June/002668.html
другое решение-использовать static IntUnaryOperator.identity()
как точка отсчета:
IntUnaryOperator.identity().andThen(v -> v - 1).andThen(i -> i * 2)
со статическим импортом вы можете использовать только identity()
слишком!
если IntUnaryOperator
имеет статический метод, как...
static IntUnaryOperator first(IntUnaryOperator op) { return op; }
... мы могли бы просто написать:
IntUnaryOperator.first(v -> v - 1).andThen(i -> i * 2)