Java 8 Method References explained in 5 minutes

At IDR Solutions I spend alot of time on working on the development of our Java PDF Library. As I spend alot of time using Java 8 in our JavaFX PDF Viewer I thought that it might be useful to a series article of the new features in JDK8.

In my previous articles, we have looked at Lambda Expression, Streams API and Default Methods. In this latest article in the series, we will be looking at Method References.

What is Method References?

It is a feature which is related to Lambda Expression. It allows us to reference constructors or methods without executing them. Method references and Lambda are similar in that they both require a target type that consist of a compatible functional interface.

Types of Method Reference

There are four types of method reference, the table below summarizes this.

TypeExampleSyntax
1. Reference to a static methodContainingClass::staticMethodNameClass::staticMethodName
2. Reference to a constructorClassName::newClassName::new
3. Reference to an instance method of an arbitrary object of a particular typeContainingType::methodNameClass::instanceMethodName
4. Reference to an instance method of a particular objectcontainingObject::instanceMethodNameobject::instanceMethodName

 

I will explain further about the four types of method referenced in the table.

 

1 . Reference to a Static Method

 

public class ReferenceToStaticMethodExample {
     /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16);
        List primeNumbers = ReferenceToStaticMethodExample.findPrimeNumbers(numbers, 
                (number) -> ReferenceToStaticMethodExample.isPrime((int) number));
 
        System.out.println("Prime Numbers are " + primeNumbers);
    }
 
    public static boolean isPrime(int number) {
        if (number == 1) {
            return false;
        }
        for (int i = 2; i < number; i++) { if (number % i == 0) { return false; } } return true; } public static List findPrimeNumbers(List list, Predicate predicate) { List sortedNumbers = new ArrayList(); list.stream().filter((i) -> (predicate.test(i))).forEach((i) -> {
            sortedNumbers.add(i);
        });
        return sortedNumbers;
 
    }
}

As you can see in this code, we made reference to a static method in this class.

ContainingClass::staticMethodName

Containing class ReferenceToStaticMethod
staticMethodName isPrime

As I mentioned above, Method reference is very similar to Lambda.Lets look at the difference here

Lambda Form List primeNumbers = ReferenceToStaticMethod.testPredicate(numbers, a -> ReferenceToStaticMethod.isPrime(a));
Method Reference List primeNumbers = ReferenceToStaticMethod.testPredicate(numbers, ReferenceToStaticMethod::isPrime);

 

2. Reference To Constructor

 

public class ReferenceToConstructor {
 
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
         List  numbers = Arrays.asList(4,9,16,25,36);
         List squaredNumbers = ReferenceToConstructor.findSquareRoot(numbers,Integer::new);
         System.out.println("Square root of numbers = "+squaredNumbers);
    }
    
    private static List findSquareRoot(List list, Function<Integer,Integer> f){
        List result = new ArrayList();
        list.forEach(x -> result.add(Math.sqrt(f.apply((Integer) x))));
        return result;
    }
}

This is very similar to reference to to a static method.The difference between the two is, the constructor reference method name is new.

ClassName::new

ClassName Integer
new new
Lambda Form List squaredNumbers = ReferenceToConstructor.findSquareRoot(numbers, x -> new Integer(x));
Method Reference List squaredNumbers= ReferenceToConstructor.findSquareRoot(numbers,Integer::new);

 

3. Reference To an Instance Method Of An Arbitrary Object Of A Particular Type

 

public class ReferenceToInstanceMethodAOPT {
 
    /**
     * @param args the command line arguments
     */
 
     private static class Person {
 
            private final String name;
            private final int age;
 
 
            public Person(String name, int age) {
                this.name = name;
                this.age = age;
 
            }
 
            public String getName() {
                return name;
            }
 
            public int getAge() {
                return age;
            }
 
 
        }
    public static void main(String[] args) {
        // TODO code application logic here
        List persons = new ArrayList();
            persons.add(new Person("Albert", 80));
            persons.add(new Person("Ben", 15));
            persons.add(new Person("Charlote", 20));
            persons.add(new Person("Dean", 6));
            persons.add(new Person("Elaine", 17));
 
 
            List allAges = ReferenceToInstanceMethodAOPT.listAllAges(persons, Person::getAge);
            System.out.println("Printing out all ages \n"+allAges);
    }
 
 
    private static List listAllAges(List person, Function<Person, Integer> f){
        List result = new ArrayList();
        person.forEach(x -> result.add(f.apply((Person)x)));
        return result;
    }
}

This mean providing reference to any of the persons object in the List of a particular type which is the Person.So the containing type is persons and the method name is getAge();

ContainingType::methodName

ContainingType Person
methodName getAge
Lambda Form List allAges = ReferenceToInstanceMethodAOPT.listAllAges(persons, x -> x.getAge());
Method Reference List allAges = ReferenceToInstanceMethodAOPT.listAllAges(persons, Person::getAge);

 

4. Reference To An Instance Method Of A Particular Object

public class ReferenceToInstanceMethodOAPO {
 
    /**
     * @param args the command line arguments
     */
 
 
    public static void main(String[] args) {
        // TODO code application logic here
        List names = new ArrayList();
            names.add("David");
            names.add("Richard");
            names.add("Samuel");
            names.add("Rose");
            names.add("John");
 
 
           ReferenceToInstanceMethodOAPO.printNames(names,System.out::println);
 
    }
 
 
    private static void printNames(List list, Consumer c ){
        list.forEach(x -> c.accept(x));
    }
}

Since System.out is an instance of type PrintStream, we then call theprintln method of the instance.

containingObject::instanceMethodName
 

containingObject System.out
instanceMethodName println
Lambda Form ReferenceToInstanceMethodOAPO.printNames(names, x -> System.out.println(x));
Method Reference ReferenceToInstanceMethodOAPO.printNames(names,System.out::println);

 

So what can we Take Away?

  1. You can use replace Lambda Expressions with Method References where Lamdba is invoking already defined methods.
  2. You can’t pass arguments to methods Reference
  3. To use Lambda and Method Reference, make sure you have Java 8 installed. They do not work on Java 7 and earlier versions.

Hopefully you have found this quick guide useful, let us know what you think.

If you’re a first-time reader, or simply want to be notified when we post new articles and updates, you can keep up to date by social media (Twitter, Facebook and Google+) or the Blog RSS.

Related Posts:

The following two tabs change content below.

Ernest Duodu

Developer at IDRSolutions
Ernest is a developer at IDRSolutions. He focuses mainly on our JavaFX PDF Viewer implementation. He was a speaker at JavaOne 2014, where he did a joint session titled "Lessons learnt developing a NetBeans PDF viewer plugin in JavaFX". Aside programming, he also enjoys a wide variety of hobbies which includes sky-diving, photography, exercising and listening to music.
Ernest

About Ernest Duodu

Ernest is a developer at IDRSolutions. He focuses mainly on our JavaFX PDF Viewer implementation. He was a speaker at JavaOne 2014, where he did a joint session titled "Lessons learnt developing a NetBeans PDF viewer plugin in JavaFX". Aside programming, he also enjoys a wide variety of hobbies which includes sky-diving, photography, exercising and listening to music.

13 thoughts on “Java 8 Method References explained in 5 minutes

  1. For the first example 1 . Reference to a Static Method
    specifying Generic type like `List` would make IDE happier, and then stream usage maybe simplified

    public static List findPrimeNumbers(List list, Predicate predicate) {
    List sortedNumbers = new ArrayList();
    list.stream().filter(predicate).forEach( sortedNumbers::add );
    return sortedNumbers;
    }

    • OK, the formated code is


      public static List findPrimeNumbers(List list, Predicate predicate) {
      List sortedNumbers = new ArrayList();
      list.stream().filter(predicate).forEach( sortedNumbers::add );
      return sortedNumbers;
      }

  2. P_think

    Hi,
    I make some error when make the first example 1 . Reference to a Static Method
    Exception in thread “main” java.lang.Error: Unresolved compilation problems:
    The method findPrimeNumbers(List, Predicate) in the type ReferenceToStaticMethod is not applicable for the arguments (List, ReferenceToStaticMethod::isPrime)
    The type ReferenceToStaticMethod does not define isPrime(Object) that is applicable here

    at jv8.ReferenceToStaticMethod.main(ReferenceToStaticMethod.java:17)
    Please help me check it.
    Thank

    • Hi,

      Thank you for pointing this out to us, I have taken a look at the example and have now altered it so that it should now work. I hope this helps.

  3. umar

    public class ReferenceToStaticMethodExample {
    /**
    * @param args
    * the command line arguments
    */
    public static void main(String[] args) {
    List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
    11, 12, 13, 15, 16);
    List primeNumbers = ReferenceToStaticMethodExample
    .findPrimeNumbers(numbers,
    ReferenceToStaticMethodExample::isPrime);

    System.out.println(“Prime Numbers are ” + primeNumbers);
    }

    public static boolean isPrime(int number) {
    if (number == 1) {
    return false;
    }
    for (int i = 2; i < number; i++) {
    if (number % i == 0) {
    return false;
    }
    }
    return true;
    }

    public static List findPrimeNumbers(List list,
    Predicate predicate) {
    List sortedNumbers = new ArrayList();
    list.stream().filter(predicate).forEach(sortedNumbers::add);
    return sortedNumbers;

    }
    }

  4. A

    Thank you so much for this awesome post!

  5. King

    Example 1 is not valid since amended to *Work but can’t use method reference because
    the list carry Object not int

    • Ravi

      This is correct and the example 1 given above is not valid and should be updated.

  6. King

    Working code for example 2

    private static List findSquareRoot(List list, Function f){
    List result = new ArrayList();
    list.forEach(x -> result.add(Math.sqrt(f.apply((Integer) x))));
    return result;
    }

  7. Prasath M

    “Function f ” can u explain this in detail. Do we need to separate ‘Functionf’. what it tells.

    • Hi Prasath,
      Function is a functional interface. It can be used as the assignment target for a lambda expression or method reference. E.g. in our second example it is used to create a new Integer object. I hope that helps.

  8. bender

    Hi in the 3rd example the function listAllAges has the following parameter Function f)
    is the integer=””- a typo ? if not can you explain what it means.
    thanks !

    • Hi, yes it was a typo, thanks for pointing it out. I’ve edited the code now so it should work

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>