第三章(5)方法引用

1.方法引用初探   

  方法调用可以被看作仅仅调用特定方法的lambda表达式的一种快捷写法。如果一个Lambda代表的只是“直接调用这个方法”,那最好还是用名称来调用它,而不是去描述如何调用它。事实上,方法引用就是让你根据已有的方法实现来创建Lambda表达式。但是,显式地指明方法的名称,你的代码的可读性会更好。类如:

我们要在苹果列表中提取苹果的Name属性,形成另一个苹果名称列表:

      在这里,我们使用了lambda表达式,我们发现这个lambda表达式仅仅就是直接调用了Apple的getName方法而已,那么我们就可以使用方法引用来简化我们的lambda表达式:

List<String> apples = Test.getApplesName(list, Apple::getName);

      它是如何工作的呢?当你需要使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面。例如,Apple::getWeight就是引用了Apple类中定义的方法getWeight。请记住,不需要括号,因为你没有实际调用这个方法。方法引用就是Lambda表达式(Apple a) ->a.getWeight()的快捷写法。

下面的图片给出了一些方法引用的例子,你可以依据这些例子写出自己在实际工作中想要写的方法引用:

 

2.如何构建方法引用

(1)指向静态方法的方法引用(例如Integer的parseInt方法,写作Integer::parseInt)。代码案例:

如果使用方法引用:

List<Integer> list = Test.getInteger(strArr, Integer::parseInt);

(2)指向任意类型实例方法的方法引用(例如String的length方法,写作String::length)。

List<Integer> list = Test.getInteger(strArr, (String s)->s.length());

如果使用方法引用:

List<Integer> list = Test.getInteger(strArr, String::length);

     类似于String::length的第二种方法引用的思想就是你在引用一个对象的方法,而这个对象本身是Lambda的一个参数。例如,Lambda表达式(String s) -> s.toUppeCase()可以写作String::toUpperCase。也就是说只要被引用的方法是属于lambda表达式参数对象的,那么就可以使用参数对象所属类引用该方法。比如

public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Integer> list = new ArrayList<>();
		list.add(22);
		list.add(1);
		list.add(3);
		list.add(54);
        list.sort((Integer i1,Integer i2)->i1.compareTo(i2));
        for(Integer a:list) {
        	System.out.println(a);
        }
	}

 就可以改写为:

list.sort(Integer::compareTo);

(3)指向现有对象的实例方法的方法引用:那就是本篇一开始所举的Apple例子。

3.构造函数的引用

对于一个构造函数,我们可以使用classname::new来创建它的一个引用,例如,我们通过无参构造函数的lambda来获取一个Apple对象。

Supplier<Apple> s1= ()->new Apple();//Supplier为java8为我们提供
Apple apple = s1.get();

那么上面的lambda就可以直接改写为:

Supplier<Apple> s1= Apple::new;//Supplier为java8为我们提供
Apple apple = s1.get();

如果你调用一个有参数的构造函数:

Function<Integer, Apple> function = (weight)->new Apple(weight);
Apple apple = function.apply(100);
System.out.println(apple.getWeight());

同样,你也可以改写为构造函数的引用:

		Function<Integer, Apple> function = Apple::new;
		Apple apple = function.apply(100);
		System.out.println(apple.getWeight());

在下面的代码中,一个由Integer构成的List中的每个元素都通过我们前面定义的类似的map方法传递给了Apple的构造函数,得到了一个具有不同重量苹果的List:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Apple> list = Test.getApplesName(Arrays.asList(1,2,3,4,5,6,7), Apple::new);
		for(Apple apple:list) {
			System.out.println(apple.getWeight());
		}
	}
    public static <T,R>List<R> getApplesName (List<T> list,Function<T, R> f) {
    	List<R> list2 = new ArrayList<>();
    	for(T t : list) {
    		list2.add(f.apply(t));
    	}
    	return list2;
    }
}

如果我们的构造函数有两个参数:

BiFunction<String, Integer, Apple> b1 = Apple::new;
Apple apple =b1.apply("大狗", 100);
System.out.println(apple.getName()+apple.getWeight());

目前java8提供的函数式接口只能支持到两个参数的构造函数,如果你想支持两个以上的构造函数,那么你可以自己写一个函数式接口,如下:

public interface TriFunction<T, U, V, R>{ 
     R apply(T t, U u, V v);
}

不将构造函数实例化却能够引用它,这个功能有一些有趣的应用。例如,你可以使用Map来将构造函数映射到字符串值:

public class MyTest {

	static Map<String, Function<Integer, Fruit>> map = new HashMap<>();
	static {
		map.put("apple", Apple::new);
		map.put("orange", Orange::new);
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Fruit fruit = MyTest.giveMeFruit("apple", 100);
        System.out.println(fruit.getWeight());
	}
    public static Fruit giveMeFruit(String name,Integer weight) {
    	return map.get(name).apply(weight);
    }
}

猜你喜欢

转载自blog.csdn.net/qq564425/article/details/81448682