9
import java.util.concurrent.Callable;

public class AdvancedLambda {

    static void invoke(Runnable r){
        r.run();
    }

    static Object invoke(Callable c) throws Exception {
        return c.call();
    }

    public static void main(String[] args) throws Exception {

        String s = (String) invoke(() -> true);
        System.out.println(s);
    }
}

Can anyone help me understand this? I was under the impression that we can only use lamba expressions in Java 8 only when we implement an interface and override its methods (replacing Anonymous classes by Lambda expressions).

Also in which situation will the method invoke(Runnable r) be called?

5 Answers 5

8

In the following line

String s = (String) invoke(() -> true);

It is actually invoke(Callable) that is getting called. The reason is:

  • () -> true is a lambda expression that has zero formal parameter and return a result.
  • Such a signature (zero parameter, single result) is compatible with the functional method call() of the Callable interface. Note that the interface does not need to have the @FunctionalInterface annotation, it just needs to have a single abstract method.

If you want to invoke invoke(Runnable) instead, you will need to create a lambda that is compatible with a functional method that takes zero parameter and returns no result (i.e. conforms with the signature of run()). Something like this:

invoke(() -> System.out.println("foo"));

Which just prints foo when ran.

Sign up to request clarification or add additional context in comments.

Comments

8

A lambda expression supplies an implementation for a functional interface. This is what your code snippet does.

Your call to invoke passes a lambda expression with no arguments that returns a value (a boolean in your case). Therefore it matches Object invoke(Callable c), and not void invoke(Runnable r) (since a Callable's call method has a return value while a Runnable's run method doesn't return anything).

invoke(() -> {System.out.println("something");});

will call void invoke(Runnable r), since in this case the lambda expression has no return type.

Comments

7

only when we Implement a interface and override its methods

That's, more or less, what you do here. Not methods, but just one method: call(). This () -> true part is your implementation of Callable#call().

In other words, this line:

String s = (String) invoke(() -> true);

would be totally equivalent with this one:

String s = (String) invoke(new Callable() {
        @Override
        public Object call() throws Exception {
            return true;
        }
    });    

Comments

2
LambdaParameters -> LambdaBody

The arrow operator (->) for defining lambda functions

  • Lambda :can only be used to execute background tasks (here compiler then figures out)
  • Expressions : are return a value of some kind

Lambda expression is another way of writing an instance of anonymous class, to make an instance of anonymous class easier to write. In JVM, it will not occupy much memory as comparing with normal java object creation with new(executing static variables, static blocks, loading classes from whole hierarchy ).

Lambda expression syntax:

(params) -> expression to implement a @FunctionalInterface

In your test case: String s = (String) invoke(() -> true); the expression has return type true with no argument. So the Runnable FunctionalInterface does not match with lambda expression because it has void run() attribute. It matches with Callable FuncationalInterface using
V call().

How lambda expressions work under the hood?
It might look like the lambda expressions are just the syntax sugar for anonymous inner classes, but there is much more elegant approach. The simplest explanation is: the lambda expression is represented by a new method, and it is invoked at run-time using invokedynamic.

Source Code:

class LambdaExample {

    public void abc() {
        Runnable r = () -> { 
            System.out.println("hello");
        }
        r.run();
    }
    
}

Bytecode equivalent:

class LambdaExample {

    public void abc() {
        Runnable r = <lambda$1 as Runnable instance>;
        r.run(); 
    }

    static void lambda$1() {
        System.out.println("hello");
    }
    
}

Inside the JVM, there is a lambda factory that creates an instance of the functional interface (e.g. Runnable) from the generated lambda method (e.g. lambda$1).

Lambda expressions are great, and there's even more great stuff in Java 8...

2 Comments

Getting your point here .. but didn't understand the byte code version much !
It's not quite another way of creating an anonymous class. It's more like a substitute for anonymous classes in specific cases.
0

Take a look at below example.

import javafx.beans.DefaultProperty;
import jdk.nashorn.internal.codegen.CompilerConstants;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Created by KUMAJYE on 13/09/2016.
 */
public class ThreadMonitor {

private static int noOfThreads = 0;


public static void main(String[] args) {
    ThreadModel threadModel;
    noOfThreads = Integer.parseInt(args[0]);
    if (noOfThreads > 0) {
        threadModel = getThreadingModelForCallsInCallingThread();
    } else {
        threadModel = getAsynchThreadingModel();
    }

}

public static ThreadModel getThreadingModelForCallsInCallingThread() {
    ExecutorService executor = Executors.newFixedThreadPool(noOfThreads);
    return (r) -> executor.submit(r);
}


public static ThreadModel getAsynchThreadingModel() {
    // do execution on same Thread or separate Thread.
    // or
    // r.run();
    return (r) -> new Thread(r).start();
}

interface ThreadModel {

    void invoke(Runnable r);
}

}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.