Возвращаемое значение лямбда в 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());
}
}
учебное пособие OCA (экзамен 1Z0-808) книга говорит, что эти две строки эквивалентны:
a -> a.canHop()
(Animal a) -> { return a.canHop(); }
означает ли это, что за кулисами Java добавляет ключевое слово возвращение кодировать в первом случае?
если ответ да, то как следующий код компилируется (представьте, что все остальное в порядке место):
static int counter = 0;
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(() -> counter++));
если мы знаем, что подписи выполнить и выполнимых по run являются:
void execute(Runnable command)
void run()
если ответ нет, то как Java знает, когда ему нужно что-то вернуть, а когда нет? Может быть, в
a -> a.canHop()
случай, который мы хотели игнорировать boolean возвращаемый тип метода.
3 ответов
означает ли это, что за кулисами Java добавляет ключевое слово return в код в первом случае?
нет, компилятор генерирует байтовый код, и он может генерировать тот же байтовый код, но он не изменяет синтаксис, а затем компилирует его снова.
мы хотели игнорировать логический тип возвращаемого метода.
он имеет возможность игнорировать значение, основанное на том, какие функциональные интерфейсы это принимая во внимание.
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
взять Runnable
так Future.get()
возвращает null
второй submit
по умолчанию являясь Callable
так Future.get()
возвращает 2
третий submit
может быть только void
возвращаемое значение, поэтому оно должно быть Runnable
так Future.get()
возвращает null
да, при указании только одного оператора, то его значение автоматически возвращается от лямбды.
С Runnable
функциональный интерфейс, его можно определить как лямбда. Тип возврата -void
, поэтому любое возвращаемое значение внутри лямбды будет проигнорировано.
вы запутались в рамки return
заявление. The (вставляется ли как байт-код компилятором или как исходный код программистом) возвращается из лямбда-кода, а не из метода, вызывающего лямбда-код.
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");
}