New in JDK8 – method references

What is a method reference?

In fact, I’ve written about this in previous articles, but I just wrote about it, and I didn’t elaborate on it. Now let’s look at an example

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class FunctionRefTest1 {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student("Zhang".20));
        list.add(new Student("Bill".19));
        list.add(new Student("Fifty".23));
        list.add(new Student("Liu six".22));
        // Sort the list using the Comparator
        // short form of lambda
        // list.sort((o1,o2)-> o1.getAge()-o2.getAge());
        // lambda is the simplest form of lambda
        list.sort( Comparator.comparingInt(Student::getAge));
        for (Student student : list) {
            System.out.println(student.getName()+""+student.getAge()); }}}Copy the code

Sort ((o1,o2)-> o1.getage () -o2.getage ()); list.sort((o1, O2)-> o1.getage ()); And list. Sort (Comparator.com paringInt Student: : getAge ()); Both codes have the same effect, while list.sort(Comparator.comparingInt(Student::getAge)); So this is using a method reference, what’s the effect? Method references make lambda expressions less redundant, thus simplifying the way lambda expressions are written.

Preliminary experience

  • Method references can be understood to eliminate the redundancy of lambda expressions and simplify writing.
  • Format:AA::BBWhat is AA, what is BB, depends on the situation, and I’ll elaborate on that. Okay

Maybe you are still foggy, ok, come again an example, let you digest once

public class FunctionRefTest2 {
    public static void main(String[] args) {
        getSum((a)->{
            int ans = 0;
            for (int i : a) {
                ans += i;
            }
            System.out.println("sum = "+ans);
        });
    }
    public static void getSum(Consumer<int[]> consumer){
        int[] a = {1.2.3.4.5.6.7.8.9}; consumer.accept(a); }}Copy the code

Here we’re going to implement array summation, which is fine for us to do, but we’ll see that there’s a lot of stuff in lambda{}, and if there’s a method out there that can also implement array summation, like this

public class FunctionRefTest2 {
    public static void main(String[] args) {
        getSum((a)->{
            int ans = 0;
            for (int i : a) {
                ans += i;
            }
            System.out.println("sum = "+ans);
        });
    }
    public static void sum(int[] a){
        int ans = 0;
        for (int i : a) {
            ans += i;
        }
        System.out.println("sum = "+ans);
    }
    public static void getSum(Consumer<int[]> consumer){
        int[] a = {1.2.3.4.5.6.7.8.9}; consumer.accept(a); }}Copy the code

The outer sum method repeats the code inside the {} of the lambda expression, resulting in a redundant lambda expression, in which case the method reference comes into play

public class FunctionRefTest2 {
    public static void main(String[] args) {
        getSum(FunctionRefTest2::sum);
    }
    public static void sum(int[] a){
        int ans = 0;
        for (int i : a) {
            ans += i;
        }
        System.out.println("sum = "+ans);
    }
    public static void getSum(Consumer<int[]> consumer){
        int[] a = {1.2.3.4.5.6.7.8.9}; consumer.accept(a); }}Copy the code

So, lambda expressions are a little bit cleaner, a little bit higher? Now that you know something about method references, let’s take a look at the rest of it

The way a method is referenced

  1. Object name :: Method name
  2. Class name :: Static method name
  3. Class name :: References instance methods
  4. Class name :: constructor
  5. Array :: constructor

Precautions for method references:

  • The parameters of the referenced method must be the same as those of the abstract method in the interface
  • When an interface abstract method has a return value, the referenced method must also have a return value
  • Method references can only refer to existing methods

How can we do this without examples? Let’s take a look at a couple of examples, just to get to the bottom of it

Object name :: Method name

This is the most common usage. If a member method already exists in a class, it can be referenced by object name

package com.features.functionReference;

import java.util.Date;
import java.util.function.Supplier;

public class FunctionRefTest3 {
    public static void main(String[] args) {
        Date now = new Date();
        Supplier<Long> s1 = () -> now.getTime();
        System.out.println("Current time obtained without using method references:"+s1.get());
        Supplier<Long> s2 = now::getTime;
        System.out.println("Current time obtained using method reference:"+s2.get()); }}Copy the code

Now is an object of type Date

Class name :: Static method name

One of the common forms

package com.features.functionReference;

import java.util.function.Supplier;

// Class name :: static method name
public class FunctionRefTest4 {
    public static void main(String[] args) {
        Supplier<Long> s1 = ()-> System.currentTimeMillis();
        System.out.println("Current time obtained without using method references:"+s1.get());
        Supplier<Long> s2 = System::currentTimeMillis;
        System.out.println("Current time obtained without using method references:"+s2.get()); }}Copy the code

System is a class

Class name :: References instance methods

In Java object-oriented, class names can only call static methods, and class names refer to instance methods with the premise that they actually take the first argument as the caller of the method

package com.features.functionReference;

import java.util.function.BiFunction;
import java.util.function.Function;

// Class name :: references instance methods
public class FunctionRefTest5 {
    public static void main(String[] args) {
        Function<String,Integer> f1 = s -> s.length();
        System.out.println("The length of hello from unused method references is:"+f1.apply("hello"));
        Function<String,Integer> f2 = String::length;
        System.out.println("The length of hello obtained using method references is:"+f2.apply("hello"));

        BiFunction<String,Integer,String> f3 = String::substring;
        System.out.println("The length of hello obtained using method references is:"+f3.apply("hello".2)); }}Copy the code

S is an instance of String, and length is an instance method of S

Class name :: constructor

Because the constructor name is exactly the same as the class name, constructor references are used in the format :: new,

package com.features.functionReference;

import com.features.lambda.demo02.Student;

import java.util.function.BiFunction;
import java.util.function.Supplier;

// Class name :: constructor
public class FunctionRefTest6 {
    public static void main(String[] args) {
        Supplier<Student> s1 = () -> new Student();
        System.out.println("Result before method reference is used:"+s1.get());

        Supplier<Student> s2 = Student::new;
        System.out.println("Result after using method reference:"+s2.get());

        BiFunction<String,Integer,Student> function = Student::new;
        System.out.println("Result after using method reference:"+function.apply("Zhang".20)); }}Copy the code

Student is a concrete class

Array :: constructor

package com.features.functionReference;

import java.util.function.Function;

// Array :: constructor
public class FunctionRefTest7 {
    public static void main(String[] args) {
        Function<Integer,String[]> f1 = len->new String[len];
        System.out.println("Length of array obtained before method reference is used:"+f1.apply(5).length);

        Function<Integer,String[]> f2 = String[]::new;
        System.out.println("Length of array after using method reference:"+f2.apply(5).length); }}Copy the code