在Java

时间:2016-07-23 09:59:57

标签: java lambda runnable

直到现在我设法找到我需要的所有答案,但这个令我困惑。假设我们有示例代码:

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()

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

3 个答案:

答案 0 :(得分:11)

  

这是否意味着,在幕后,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

第一个submitRunnable所以Future.get()返回null

第二个submit默认为Callable,因此Future.get()会返回2

第三个submit只能是void返回值,因此必须为Runnable,以便Future.get()返回null

答案 1 :(得分:3)

是的,当只指定一个语句时,它的值会自动从lambda返回。

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

答案 2 :(得分:0)

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