欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第三章(5)方法引用

程序员文章站 2022-05-22 21:19:27
...

1.方法引用初探   

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

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

第三章(5)方法引用

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

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

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

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

 第三章(5)方法引用

2.如何构建方法引用

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

第三章(5)方法引用

如果使用方法引用:

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);
    }
}

 

相关标签: java8 方法引用