Java中lambda的返回值

问题描述:

到目前为止,我设法找到了我需要的所有答案,但是这个答案令我困惑。比方说,我们有示例代码:Java中lambda的返回值

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

如果我们知道,签名执行和Runnable接口的运行是:

void execute(Runnable command) 
void run() 

如果答案是否定的,那么Java如何知道它何时需要返回什么以及何时不需要返回?也许在

a -> a.canHop() 

情况下,我们想忽略方法布尔返回类型。

+2

它知道它可以忽略Runnable情况下的返回类型,因为run()返回void。它知道它不能忽略CheckAnimal情况下的返回类型,因为test()不会返回void。 –

+1

lambada做了一个方法应该做的事情,如果你的方法包含返回类型,那么lambda将提供其他方式,否则它是写方法的快捷方式,所以不要混淆你自己 – emotionlessbananas

这是否意味着,在幕后,Java的增加在第一种情况下的关键字返回代码?

不,编译器生成字节码,它可能会生成相同的字节码,但它不会更改语法,然后再次编译。

我们想忽略boolean返回类型的方法。

它可以根据它正在考虑的功能接口忽略一个值。

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

+0

而且只在执行时需要Runnable:es.execute (() - > counter ++);那么它会被视为副作用? – Freeman

+0

@Freeman任何不返回值的方法只能有副作用。 –

您对return声明的范围感到困惑。 return语句(不管是由编译器作为字节码还是由程序员作为源代码插入)都从lambda返回,而不是从调用lambda的方法返回。

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"); 
} 

是,仅指定单个语句的时候,它的价值会自动从拉姆达返回。

然后,由于Runnable是一个功能接口,它可以定义为lambda。返回类型为void,因此lambda内的任何返回值都将被忽略。