2013-11-29 1 views
21

У меня есть пример кода, который использует Java 8 new stream functionality (получите диапазон значений 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] 

Теперь я хочу, чтобы заменить анонимные классы с Lambda expressions. Следующее преобразование работает отлично (второй анонимный класс заменяется выражением 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'

Compilation error

Вы знаете, как объединить два лямбда-выражения с IntUnaryOperator.andThen?

Я знаю, что могу использовать ... .limit(10).map(v -> v - 1).map(i -> i * 2).toArray() ..., который отлично работает, но я хотел бы узнать, как использовать IntUnaryOperator.andThen с lambdas (если это возможно).

+1

Интересный вопрос! Также более формальный '((int v) -> v - 1).andThen ((int i) -> i * 2) 'не работает:" ошибка: выражение lambda не ожидается здесь ". – isnot2bad

+0

компилятор не может вывести тип '(v -> v - 1) .andThen (i -> i * 2)', поскольку на самом деле он должен сделать 2 вывода, а затем третий из этих двух. это, скорее всего, выходит за рамки системы типов. – aepurniet

ответ

16

Вы должны явно бросить первый лямбда-выражение в IntUnaryOperator. Следующий код работает:

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

Я думаю, было бы полезно указать, что причина, по которой требуется бросок, заключается в том, что сама лямбда не имеет типа. Он получает только тип через назначение/литье. Например, выражение 's -> s.isEmpty()' может быть присвоено 'java.util.function.Predicate ', 'java.util.function.Function ', 'com.google. common.base.Predicate 'и т. д. –

11

мне удалось скомпилировать код, как показано ниже (хотя с помощью затмений экспериментальных версий):

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-компилятор, FunctionalInterface должен иметь «контекст», чтобы быть выполненным так, как вы хотите. Вот почему с вашим исходным фрагментом кода Java-компилятор не имеет способа отобразить ваше выражение lamda точно в качестве экземпляра IntUnaryOperator.

Для более длительного обсуждения, посмотрите на эту тему: http://mail.openjdk.java.net/pipermail/jdk8-dev/2013-June/002668.html

11

Другим решением является использование статического IntUnaryOperator.identity() как StartPoint:

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) 
+0

Легко написать собственный статический метод' first'. –

Смежные вопросы