2016-07-23 4 views
5

До сих пор мне удается найти все ответы, которые мне нужны, но это меня сбивает с толку. Скажем, у нас есть пример кода:Возвращаемое значение lambda в Java

public class Animal { 
    private String species; 
    private boolean canHop; 
    private boolean canSwim; 
    public Animal(String speciesName, boolean hopper, boolean swimmer) { 
    species = speciesName; 
    canHop = hopper; 
    canSwim = swimmer; 
    } 
    public boolean canHop() { return canHop; } 
    public boolean canSwim() { return canSwim; } 
    public String toString() { return species; } 
} 

public interface CheckAnimal { 
    public boolean test(Animal a); 
} 

public class FindSameAnimals { 
    private static void print(Animal animal, CheckAnimal trait) { 
     if(trait.test(animal)){ 
     System.out.println(animal); 
     } 

    public static void main(String[] args) { 
     print(new Animal("fish", false, true), a -> a.canHop()); 
    } 
} 

ОСА Учебное пособие (экзамен 1Z0-808) Книга говорит, что эти две строки эквивалентны:

a -> a.canHop() 
(Animal a) -> { return a.canHop(); } 

Означает ли это, что за кулисами, Java добавляет ключевое слово возвращение для кода в первом случае?

Если ответ ДА, то как следующий код компиляции (представьте, все остальное находится в надлежащем месте):

static int counter = 0; 
ExecutorService service = Executors.newSingleThreadExecutor(); 
service.execute(() -> counter++)); 

, если мы знаем, что подписи для выполнить и Runnable-х бег являются:

void execute(Runnable command) 
void run() 

Если ответ НЕТ, то как Java знает, когда ему нужно что-то возвращать, а когда нет? Может быть, в

a -> a.canHop() 

случае мы хотели игнорировать логический тип возврата метода.

+2

Он знает, что может игнорировать возвращаемый тип в Runnable case, потому что run() возвращает void. И он знает, что не должен игнорировать возвращаемый тип в случае CheckAnimal, потому что test() не возвращает void. –

+1

lambada делает то, что должен делать метод, если ваш метод содержит тип возвращаемого значения, тогда лямбда не укажет иначе, это ярлык для написания методов, поэтому не путайте себя – emotionlessbananas

ответ

9

Означает ли это, что за кулисами, Java добавляет возвращение ключевых слов к коду в первом случае?

Нет, компилятор генерирует байт-код, и он может генерировать один и тот же байт-код, но он не меняет синтаксис и затем скомпилирует его снова.

Мы хотели игнорировать логический тип возвращаемого метода.

Он имеет возможность игнорировать значение, основанное на том, какие функциональные интерфейсы он рассматривает.

a -> a.canHop() 

может быть

(Animal a) -> { return a.canHop(); } 

или

(Animal a) -> { a.canHop(); } 

на основе контекста, однако он отдает предпочтение первым, если это возможно.

Рассмотрим ExecutorService.submit(Callable<T>) и ExecutorService.submit(Runnable)

ExecutorService es = Executors.newSingleThreadExecutor(); 
es.execute(() -> counter++); // has to be Runnable 
es.submit(() -> counter++); // Callable<Integer> or Runnable? 

Сохранение тип возврата вы можете увидеть это в Callable<Integer>

final Future<Integer> submit = es.submit(() -> counter++); 

Чтобы попробовать себя, вот уже пример.

static int counter = 0; 

public static void main(String[] args) throws ExecutionException, InterruptedException { 
    ExecutorService es = Executors.newSingleThreadExecutor(); 

    // execute only takes Runnable 
    es.execute(() -> counter++); 

    // force the lambda to be Runnable 
    final Future<?> submit = es.submit((Runnable)() -> counter++); 
    System.out.println(submit.get()); 

    // returns a value so it's a Callable<Integer> 
    final Future<Integer> submit2 = es.submit(() -> counter++); 
    System.out.println(submit2.get()); 

    // returns nothing so it must be Runnable 
    final Future<?> submit3 = es.submit(() -> System.out.println("counter: " + counter)); 
    System.out.println(submit3.get()); 

    es.shutdown(); 
} 

печатает

null 
2 
counter: 3 
null 

Первый submit взять RunnableFuture.get() так возвращает null

Вторые submit по умолчанию, чтобы быть Callable таким образом Future.get() возвращает 2

третий submit может быть только void возвращаемое значение, так что должно быть RunnableFuture.get() так возвращает null

+0

И в случае, когда выполнение выполняется только Runnable: es.execute (() -> counter ++); это тогда считается побочным эффектом? – Freeman

+0

@Freeman любой метод, который не возвращает значение, может иметь только побочные эффекты. –

0

Вы смущены о сфере применения инструкции return. Оператор return (вставленный как байт-код компилятором или как исходный код программиста) возвращается из лямбда, а не из метода, который вызывает лямбда.

void foo() { 
    Supplier<String> s =() -> { return "bar" }; 
    String s = s.get(); // s is assigned to "bar" 
    // Execution continues as the return statement in the lambda only returns from the lambda and not the enclosing method 
    System.out.println("This will print"); 
} 
3

Да, при указании только одного оператора, то его значение автоматически возвращается из лямбда.

Тогда, поскольку Runnable является функциональным интерфейсом, его можно определить как лямбда. Тип возврата - void, поэтому любое возвращаемое значение внутри лямбда будет проигнорировано.

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