java8 :: 方法引用 method references


简单来说, 方法引用是针对接口来使用的。语法的一般形式为 xx::yy,jre会自动推断实现的方法、参数列表以及返回值。这也就要求了接口必须带有 @FunctionalInterface注解,或者符合 @FunctionalInterface规范。

方法引用一共包含4中形式

kind
Example
Reference to a static methodContainingClass::staticMethodName
Reference to an instance method of a particular objectcontainingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular typeContainingType::methodName
Reference to a constructorClassName::new

Reference to a static method && Reference to an instance method of a particular object

这两个用法相似,放在一起写。

public class MethodRef {

	public static void main(String[] args) {
		IMethod iMethod1 = MethodRef::staticMethod;
		IMethod iMethod2 = new MethodRef()::particularMethod;
	}
	
	public static void staticMethod(MethodRefTest test) {
		
	}
	
	public void particularMethod(MethodRefTest test) {
		
	}

}
//Consumer
//@FunctionalInterface
interface IMethod{
	void method(MethodRefTest test);
}

这两种写法分别相当于以staticMethod、particularMethod作为实现方法去生成一个匿名实现类。与下方代码等效

public class MethodRef {

	public static void main(String[] args) {
		IMethod iMethod1 = MethodRef::staticMethod;
		IMethod iMethod2 = new MethodRef()::particularMethod;
		
		IMethod iMethod3 = new IMethod() {
			
			@Override
			public void method(MethodRefTest test) {
				// TODO Auto-generated method stub
				MethodRef.staticMethod(test);
			}
		};
		
		IMethod iMethod4 = new IMethod() {
			
			@Override
			public void method(MethodRefTest test) {
				// TODO Auto-generated method stub
				new MethodRef().particularMethod(test);
			}
		};
	}
	
	public static void staticMethod(MethodRefTest test) {
		
	}
	
	public void particularMethod(MethodRefTest test) {
		
	}

}
//Consumer
//@FunctionalInterface
interface IMethod{
	void method(MethodRefTest test);
}

可以看出,这个语法的关键点只在于实现方法的参数列表与返回值,只要这两点一致,那么,不管方法写在了哪个类中,都可以使用。

Reference to an instance method of an arbitrary object of a particular type

关于这种写法,我一直没有找到什么太好的解释。只是从形式上看,它与第二种写法的主要区别就是,允许参数列表不同,jre会自动的向下寻找合适的方法来执行。由于推断的规则的原因,所使用的接口必须使用泛型
见下例中method5

public class MethodRef {

	public static void main(String[] args) {
		IMethod iMethod1 = MethodRef::staticMethod;
		IMethod iMethod2 = new MethodRef()::particularMethod;
		
		IMethod iMethod3 = new IMethod() {
			
			@Override
			public void method(MethodRefTest test) {
				// TODO Auto-generated method stub
				MethodRef.staticMethod(test);
			}
		};
		
		IMethod iMethod4 = new IMethod() {
			
			@Override
			public void method(MethodRefTest test) {
				// TODO Auto-generated method stub
				new MethodRef().particularMethod(test);
			}
		};
		
		IMethod2<MethodRef> iMethod5 = MethodRef::noVar;
	}
	
	public static void staticMethod(MethodRefTest test) {
		
	}
	
	public void particularMethod(MethodRefTest test) {
		
	}
	
	public IMethod noVar() {
		return (p) -> {};
	}

}
//Consumer
//@FunctionalInterface
interface IMethod{
	void method(MethodRefTest test);
}

interface IMethod2<T>{
	void method(T test);
}

jre会自动推断出合适的方法来执行,但是,到底什么是合适,我目前还没有找到像样的解释。

Reference to a constructor

与上一种相似,也是必须要使用泛型。但是我目前只找到了适用于类似Supplier 接口的例子,感觉用处不是很大。
(见下方代码iMethod6,iMethod7)

import java.util.function.Supplier;

public class MethodRef {

	public static void main(String[] args) {
		IMethod iMethod1 = MethodRef::staticMethod;
		IMethod iMethod2 = new MethodRef()::particularMethod;
		
		IMethod iMethod3 = new IMethod() {
			
			@Override
			public void method(MethodRefTest test) {
				// TODO Auto-generated method stub
				MethodRef.staticMethod(test);
			}
		};
		
		IMethod iMethod4 = new IMethod() {
			
			@Override
			public void method(MethodRefTest test) {
				// TODO Auto-generated method stub
				new MethodRef().particularMethod(test);
			}
		};
		
		IMethod2<MethodRef> iMethod5 = MethodRef::noVar;
		
		IMethod3<MethodRef> iMethod6 = MethodRef::new;
		Supplier<MethodRef> iMethod7 = MethodRef::new;
	}
	
	public static void staticMethod(MethodRefTest test) {
		
	}
	
	public void particularMethod(MethodRefTest test) {
		
	}
	
	public IMethod noVar() {
		return (p) -> {};
	}

}
//Consumer
//@FunctionalInterface
interface IMethod{
	void method(MethodRefTest test);
}

interface IMethod2<T>{
	void method(T test);
}
//形式与Supplier相似
interface IMethod3<T>{
	T method();
}

参考文档

官方文档地址
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
参考帖子
Java 8 constructor method references
Reference to an instance method of an arbitrary object of a particular type… not working with custom classes?
官方例子

/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
  
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Collection;
import java.util.function.Supplier;
import java.util.Set;
import java.util.HashSet;
import java.time.LocalDate;
import java.time.chrono.IsoChronology;
 
public class MethodReferencesTest {
     
    // The method transferElements copies elements from one collection to
    // another
   
    public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>
        DEST transferElements(
            SOURCE sourceCollection,
            Supplier<DEST> collectionFactory) {
         
            DEST result = collectionFactory.get();
            for (T t : sourceCollection) {
                result.add(t);
            }
            return result;
    }  
       
    public static void main(String... args) {
 
        List<Person> roster = Person.createRoster();        
 
        for (Person p : roster) {
            p.printPerson();
        }
      
         
        Person[] rosterAsArray = 
            roster.toArray(new Person[roster.size()]);
         
        class PersonAgeComparator
            implements Comparator<Person> {
            public int compare(Person a, Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        }
         
        // Without method reference
        Arrays.sort(rosterAsArray, new PersonAgeComparator());
         
        // With lambda expression
        Arrays.sort(rosterAsArray,
            (Person a, Person b) -> {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        );
        
        // With method reference
        Arrays.sort(rosterAsArray, Person::compareByAge);
         
        // Reference to an instance method of a particular object
        class ComparisonProvider {
            public int compareByName(Person a,
                Person b) {
                return a.getName().compareTo(b.getName());
            }
         
            public int compareByAge(Person a,
                Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        }
        ComparisonProvider myComparisonProvider = new ComparisonProvider();
        Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
         
        // Reference to an instance method
        // of an arbitrary object of a particular type
         
        String[] stringArray = { "Barbara", "James", "Mary", "John",
            "Patricia", "Robert", "Michael", "Linda" };
        Arrays.sort(stringArray, String::compareToIgnoreCase);
 
        Set<Person> rosterSetLambda =
            transferElements(roster, () -> { return new HashSet<>(); });
         
        Set<Person> rosterSet = transferElements(
            roster, HashSet::new);
        System.out.println("Printing rosterSet:");
        rosterSet.stream().forEach(p -> p.printPerson());
    }
}

class Person {
	   
    public enum Sex {
        MALE, FEMALE
    }
   
    String name; 
    LocalDate birthday;
    Sex gender;
    String emailAddress;
   
    Person(String nameArg, LocalDate birthdayArg,
        Sex genderArg, String emailArg) {
        name = nameArg;
        birthday = birthdayArg;
        gender = genderArg;
        emailAddress = emailArg;
    }  
 
    public int getAge() {
        return birthday
            .until(IsoChronology.INSTANCE.dateNow())
            .getYears();
    }
 
    public void printPerson() {
      System.out.println(name + ", " + this.getAge());
    }
     
    public Sex getGender() {
        return gender;
    }
     
    public String getName() {
        return name;
    }
     
    public String getEmailAddress() {
        return emailAddress;
    }
     
    public LocalDate getBirthday() {
        return birthday;
    }
     
    public static int compareByAge(Person a, Person b) {
        return a.birthday.compareTo(b.birthday);
    }
 
    public static List<Person> createRoster() {
         
        List<Person> roster = new ArrayList<>();
        roster.add(
            new Person(
            "Fred",
            IsoChronology.INSTANCE.date(1980, 6, 20),
            Person.Sex.MALE,
            "fred@example.com"));
        roster.add(
            new Person(
            "Jane",
            IsoChronology.INSTANCE.date(1990, 7, 15),
            Person.Sex.FEMALE, "jane@example.com"));
        roster.add(
            new Person(
            "George",
            IsoChronology.INSTANCE.date(1991, 8, 13),
            Person.Sex.MALE, "george@example.com"));
        roster.add(
            new Person(
            "Bob",
            IsoChronology.INSTANCE.date(2000, 9, 12),
            Person.Sex.MALE, "bob@example.com"));
         
        return roster;
    }
     
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值