//LambdaFunctionVariations.java
//Designed to illustrate some of the many variations possible when
//defining a lambda function, and also the way to supply a lambda
//function as the parameter when a method has a "functional interface"
//(an interface with a single abstract method) as a parameter.
//Note the "extra" classes that are created when the file is compiled.

public class LambdaFunctionVariations
{
    public static void main(String args[])
    {
        LambdaFunctionVariations tester = new LambdaFunctionVariations();

        //Define and then use some lambda functions:
        //With parameter type declaration
        MathOperation addition = (int a, int b) -> a + b;

        //Without parameter type declaration
        MathOperation subtraction = (a, b) -> a - b;

        //With parameter type declaration plus return statement
        //and curly braces
        MathOperation multiplication = (int a, int b) ->
        {
            return a * b;
        };

        //With parameter type declaration but without return statement
        //and without curly braces
        MathOperation division = (int a, int b) -> a / b;

        System.out.println();
        System.out.println
        (
            "10 + 5 = "
            + tester.operate(10, 5, addition)
        );
        System.out.println
        (
            "10 - 5 = "
            + tester.operate(10, 5, subtraction)
        );
        System.out.println
        (
            "10 x 5 = "
            + tester.operate(10, 5, multiplication)
        );
        System.out.println
        (
            "10 / 5 = "
            + tester.operate(10, 5, division)
        );

        //With parentheses and parameter type
        GreetingService greetService1 =
            (String message) -> System.out.println("Hello " + message);

        //With just parentheses
        GreetingService greetService2 =
            (message) -> System.out.println("Hello " + message);

        //Without parentheses or parameter type
        GreetingService greetService3 =
            message -> System.out.println("Hello " + message);

        greetService1.sayMessage("Sam");
        greetService2.sayMessage("Mary");
        greetService3.sayMessage("John");
    }

    private interface MathOperation
    {
        int operation
        (
            int a,
            int b
        );
    }

    private interface GreetingService
    {
        void sayMessage(String message);
    }

    private int operate
    (
        int a,
        int b,
        MathOperation mathOperation
    )
    {
        return mathOperation.operation(a, b);
    }
}
/*  Output:

    10 + 5 = 15
    10 - 5 = 5
    10 x 5 = 50
    10 / 5 = 2
    Hello Sam
    Hello Mary
    Hello John
*/
