Skip to content

Example code to demonstrate how Java maps method references to FunctionalInterfaces

License

Notifications You must be signed in to change notification settings

adashrod/MethodReferenceCheatSheet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Java Lambda and Method Reference Cheat Sheet

This repo and the example code demonstrate how Java maps method references to FunctionalInterfaces, and given the signature of a function, which FunctionalInterfaces it can be used for as a method reference.

Suppose you have a class with some instance functions:

public class MyObject {
    // no arguments, no return (0:0)
    public void niladicVoid() {
        ...
    }
    // 1 argument, no return (1:0)
    public void monadicVoid(final Object o) {
        ...
    }
    // 1 argument, has return (1:1)
    public Object monadicWithReturn(final Object o) {
        ...
    }
    // 2 arguments, no return (2:0)
    public void dyadicVoid(final Object a, final Object b) {
        ...
    }
    ...
}

a class with some static functions:

public class MyStatics {
    public static String niladicWithReturn() {
        ...
    }
    public static void niladicVoid() {
        ...
    }
    ...
}

and an API that takes some FunctionalInterface types as arguments (Consumer, Function, etc):

public class MyApi {
    // takes a Consumer, or a method reference that can be cast to a Consumer
    private static <T> void consumerCall(final Consumer<T> c, final T t) {
        ...
        c.accept(t);
    }
    // takes a BiConsumer, or a method reference that can be cast to a BiConsumer
    private static <T, U> void biConsumerCall(final BiConsumer<T, U> bc, final T t, final U u) {
        ...
        bc.accept(t, u);
    }
}    

Here is how you can use the functions in MyObject and MyStatics as method references when calling an API that requires FunctionalInterface types.

final MyObject obj = new MyObject();

// 1a: === as method references ===
MyApi::consumerCall(obj::monadicVoid, "a"); // if the method reference takes 1
// argument, then the object on the left side of :: becomes the LHS of the call
// to the method reference, and the argument passed to the Consumer is
// forwarded to that method. See equivalent lambda example in the next section.
MyApi::consumerCall(MyObject::niladicVoid, obj); // if the method reference
// takes 1 less argument than the FunctionalInterface type, a class method
// reference can be used, and 1st the argument to the FunctionalInterface type
// (here: Consumer) becomes the LHS of the call

// 1b: === as lambdas === These are exactly the same as 1a
MyApi::consumerCall(arg -> obj.monadicVoid(arg), "a"); // LHS is a variable in
// the scope
MyApi::consumerCall(arg -> arg.niladicVoid(), obj); // LHS is the argument to
// the Consumer


// BiConsumers demonstrate how the arity (number of arguments) of the method
// reference must be the same as the FunctionalInterface type when using an
// instance, or 1 less when using a class method reference as method references
// 2a: === as method references ===
MyApi::biConsumerCall(obj::dyadicVoid, "a", "b"); // instance method reference:
// instance is LHS and arity of method reference and FunctionalInterface type
// are the same (2)
MyApi::biConsumerCall(MyObject::monadicVoid, obj, "a"); // class method
// reference: 1st argument to BiConsumer is the LHS of the call, method
// reference only takes 1 argument 
biConsumerCall(MyStatics::dyadicVoid, "a", "b"); // static method reference:
// similar to instance method reference, the arity of the reference matches
// that of the FunctionalInterface type (2 here)

// 2b: === as lambdas === These are exactly the same as 2a
MyApi::biConsumerCall((a, b) -> obj.dyadicVoid(a, b), "a", "b");
MyApi::biConsumerCall((myObject, i) -> myObject.monadicVoid(i), obj, "a");
MyApi::biConsumerCall((a, b) -> MyStatics.dyadicVoid(a, b), "a", "b");


// if an API expects a FunctionalInterface type that doesn't expect a return
// type, and you provide one that returns something, the result is ignored and
// the pattern is the same as the above with Consumers
// 3a: === as method references ===
MyApi::consumerCall(obj::monadicWithReturn, "a");
MyApi::consumerCall(MyObject::niladicWithReturn, obj);
MyApi::consumerCall(MyStatics::monadicWithReturn, "b");

// 3b: === as lambdas === These are exactly the same as 3a
MyApi::consumerCall(arg -> obj.monadicWithReturn(arg), "a");
MyApi::consumerCall(myObject -> myObject.niladicWithReturn(), obj);
MyApi::consumerCall(arg -> MyStatics.monadicWithReturn(arg), "b");


// and some examples with FunctionalInterface types that expect return values:
// 4a: === as method references ===
functionCall(obj::monadicWithReturn, obj);
functionCall(MyObject::niladicWithReturn, obj);
functionCall(MyStatics::monadicWithReturn, "a");
biFunctionCall(obj::dyadicWithReturn, "a", "b");
biFunctionCall(MyObject::monadicWithReturn, obj, "a");
biFunctionCall(MyStatics::dyadicWithReturn, "a", "b");

// 4b: === as lambdas === These are exactly the same as 4a
functionCall(arg -> obj.monadicWithReturn(arg), obj);
functionCall(myObject -> myObject.niladicWithReturn(), obj);
functionCall(arg -> MyStatics.monadicWithReturn(arg), "a");
biFunctionCall((a, b) -> obj.dyadicWithReturn(a, b), "a", "b");
biFunctionCall((myObject, arg) -> myObject.monadicWithReturn(arg), obj, "a");
biFunctionCall((a, b) -> MyStatics.dyadicWithReturn(a, b), "a", "b");

Contained in the source code are samples of how different signatures of functions map to different FunctionalInterface types, and how they can be used.

In MyObject and MyStatics, there are a handful of functions, and each one is documented with the types of FunctionalInterfaces that they can be cast to. All functions in MyObject are instance functions and all in MyStatics are static. In the documentation, a function's arity is described by the notation (x:y), where x is the number of arguments to the function, and y is the number of return values (either 0 or 1). E.g. a function that takes 2 arguments and returns void is (2:0).

Application has example method references of everything defined in the other classes.

from MyObject:

/**
 * Method references to this function (0 arguments:1 return) can be cast to the following FunctionalInterface types:
 * <ul>
 * <li>Supplier(0:1) as instance::func</li>
 * <li>Function(1:1) as ClassName::func (1st arg is instance)</li>
 * </ul>
 *
 * Method references to this function can be cast to the following FunctionalInterface types, but the return value
 * will be ignored
 * <ul>
 * <li>Runnable(0:0) as instance::func (ignores return value, not useful for getters)</li>
 * <li>Consumer(1:0) as ClassName::func  (1st arg is instance, ignores return value, not useful for getters)</li>
 * </ul>
 */
public String niladicWithReturn() {
    ...

from MyStatics:

/**
 * Method references to this function (1:0) can be cast to the following FunctionalInterface type:
 * Consumer(1:0) as ClassName::func
 * <br/><br/>
 * Method references to this function cannot be cast to FunctionalInterface types with return values such as
 * Function because Function requires a return value
 */
public static void monadicVoid(final Object i) {
    ...

About

Example code to demonstrate how Java maps method references to FunctionalInterfaces

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages