Do Lamda expressions have to be inside a method? Can they exist outside a method as a member of a class

Viewed 115

I am trying to see, the difference in passing functions as parameters between Scala and Java. I have moved to Scala a few years ago, not in touch with Java much. Can I have a Lambda expression outside of a method, like below?. It compiles and works fine, but Is there anything wrong with it. So far all the examples I have seen have Lamdas inside a method. The below code is just an example, I am aware you can achieve the same thing with Supplier Interface.

@FunctionalInterface
public interface IFunc {

    String printMessage();
}


public class JavaFunc {

    public String message() {

        return functionA(functionB);
    }

    IFunc functionB = () ->  "Hi, I am functionB from Java, I am passed to functionA as a parameter.";

    public String functionA(IFunc funcB) {
        return funcB.printMessage();
    }

}
3 Answers

You can declare lambda expression any where in class

If you declare inside a method (which is similar to local variables, scope inside of method)

public String message() {

  IFunc functionB = () ->  "Hi, I am functionB from Java, I am passed to functionA as a parameter.";

    return functionA(functionB);
}

If you declare in the class (Which is similar to instance variables that can be accessed in all instance methods directly and with object reference in static area )

public class JavaFunc {

 IFunc functionB = () ->  "Hi, I am functionB from Java, I am passed to functionA as a parameter.";

public String message() {

    // use here functionB
    return functionA(functionB);
}

Example : lambda expression for Predicate and anonymous inner class

p1,p2 are at instance level and p3,p4 are local

public class DemoMain {

Predicate<Integer> p1 = i -> i > 5;

Predicate<Integer> p2 = new Predicate<Integer>() {

    @Override
    public boolean test(Integer t) {
        // TODO Auto-generated method stub
        return false;
    }
};

public static void main(String args[]) {

    DemoMain m = new DemoMain();
    System.out.println(m.p1.test(10));
    System.out.println(m.p2.test(10));
}

public void m1() {

    System.out.println(p1.test(10));
    System.out.println(p2.test(10));

    Predicate<Integer> p3 = i -> i > 5;

    Predicate<Integer> p4 = new Predicate<Integer>() {

        @Override
        public boolean test(Integer t) {
            // TODO Auto-generated method stub
            return false;
            }
        };

    }

 }

To put it in another way, lambda expressions are also known as function objects, so wherever you can use a normal objects, you can also use lambdas: you can define them as attributes, you can pass them as method parameters, etc.

public ExampleClass {
    //Initializing the consumer with our method reference (subset of lambdas)
    static Consumer<Integer> printer = System.out::println;

    public static void useLambda(Consumer<Integer> myIntegerPrinter, Integer value) {
         myIntegerPrinter.accept(value);
    }

    public static void main(String[] args) {
         // passing the lambda as parameter to useLambda
         useLambda(printer, 100);
    }
}

Remember what Lambda is short for. It's simply used for method definitions, particularly for functional interfaces. Pretty much wherever you can use an object where you define some function (with simple logic), you could also easily use Lambda. A good example to use would be ActionListener.

Without lambda, we could say:

ActionListener al = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(e.getActionCommand());
    }
};

With lambda, we can shorten this to the simple expression:

ActionListener al = e -> System.out.println(e.getActionCommand());

It's clear to see that these are directly related to each other; 'ActionEvent e', from the original, is simply declared as 'e' in the secondary, as the compiler already knows what type it's of, and similarly, we can define the body of the method by declaring what it does in a singular line.

Now, these can also be passed as parameters, because they're just like any other object. For instance, let's say we had a JButton object, which frequently is given an ActionListener. Note that JButton has a method JButton#addActionListener(ActionListener al). Now, we can pass our ActionListener in any of the following ways:

JButton b = new JButton();
//Option One
ActionListener al = e -> System.out.println(e.getActionCommand());
b.addActionListener(al);
//Option Two
b.addActionListener(e -> System.out.println(e.getActionCommand()));
//Option Three
b.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(e.getActionCommand());
    }
});
//Option Four
ActionListener al = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(e.getActionCommand());
    }
};
b.addActionListener(al);

All of these are logically equivalent!

Related