Java中的lambda返回值

Posted

技术标签:

【中文标题】Java中的lambda返回值【英文标题】:Return value by lambda in Java 【发布时间】:2016-11-27 04:27:41 【问题描述】:

到目前为止,我设法找到了我需要的所有答案,但这一个让我感到困惑。假设我们有示例代码:

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 Study Guide (Exam 1Z0-808) 书说这两行是等价的:

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

这是否意味着,Java 在幕后为第一种情况的代码添加了关键字 return

如果答案是肯定的,那么接下来的代码将如何编译(想象其他一切都在适当的位置):

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

如果我们知道 execute 和 Runnable 的 run 的签名是:

void execute(Runnable command)
void run()

如果答案是否定的,那么 Java 怎么知道什么时候需要返回,什么时候不需要呢?也许在

a -> a.canHop()

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

【问题讨论】:

它知道它可以忽略 Runnable 情况下的返回类型,因为 run() 返回 void。它知道它不能忽略 CheckAnimal 案例中的返回类型,因为 test() 不会返回 void。 lambada 做了一个方法应该做的事情,如果你的方法包含返回类型,那么 lambda 将提供否则不提供,这是编写方法的捷径所以不要混淆自己 【参考方案1】:

这是否意味着,在幕后,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&lt;Integer&gt;

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:es.execute(() -> counter++);然后被认为是副作用? @Freeman 任何不返回值的方法都只会有副作用。【参考方案2】:

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

那么,既然Runnable是一个Functional Interface,那么它可以定义为一个lambda。返回类型为void,因此lambda内的任何返回值都将被忽略。

【讨论】:

【参考方案3】:

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

【讨论】:

以上是关于Java中的lambda返回值的主要内容,如果未能解决你的问题,请参考以下文章

Java Lambda表达式的箭头理解总结

java8 lambda方法引用

java 多线程-lambda带返回值

如何使用 Java lambda 遍历列表映射并返回单个值? [复制]

lambda 返回 initializer_list 中的奇怪值

我奶奶都能懂java8特性-lambda表达试