Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return value by lambda in Java

Till now I manage to find all answers I need but this one confusing me. Let's say we have example code:

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) book says that these two lines are equivalent:

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

Does this mean that, behind the scenes, Java adds keyword return to code in the first case?

If answer is YES then how next code compile (imagine everything else is in proper place):

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

if we know that signatures for execute and Runnable's run are:

void execute(Runnable command)
void run()

If answer is NO then how Java know when it need to return something and when not to? Maybe in

a -> a.canHop()

case we wanted to ignore boolean return type of method.

like image 580
Freeman Avatar asked Jul 23 '16 09:07

Freeman


People also ask

How do you return a value from lambda in Java?

A return statement is not an expression in a lambda expression. We must enclose statements in braces ({}). However, we do not have to enclose a void method invocation in braces. The return type of a method in which lambda expression used in a return statement must be a functional interface.

Can lambda expressions return value?

A lambda expression can't directly capture an in, ref, or out parameter from the enclosing method. A return statement in a lambda expression doesn't cause the enclosing method to return.

What does lambda return in Java?

Lambda Expressions were added in Java 8. A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.


2 Answers

Does this mean that, behind the scenes, Java adds keyword return to code in the first case?

No, The compiler generates byte code, and it might generate the same byte code but it doesn't change the syntax and then compile it again.

we wanted to ignore boolean return type of method.

It has the option of ignoring a value based on what functional interfaces it is considering.

a -> a.canHop()

could be

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

or

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

based on context, however it favours the first if possible.

Consider ExecutorService.submit(Callable<T>) and ExecutorService.submit(Runnable)

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

Saving the return type you can see it's a Callable<Integer>

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

To try yourself, here is a longer example.

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

prints

null
2
counter: 3
null

The first submit take a Runnable so Future.get() returns null

The second submit defaults to being a Callable so Future.get() returns 2

The third submit can only be a void return value so it must be a Runnable so Future.get() returns null

like image 164
Peter Lawrey Avatar answered Oct 12 '22 01:10

Peter Lawrey


Yes, when specifying only a single statement, its value is automatically returned from the lambda.

Then, since Runnable is a Functional Interface, it can be defined as a lambda. The return type is void, so any return value inside the lambda will be ignored.

like image 42
Guillaume Poussel Avatar answered Oct 12 '22 01:10

Guillaume Poussel