目录
一、简介
二、引用静态方法
1.格式
2.示例
编辑
3.条件解析
三、引用成员方法
1.格式
2.示例
四、引用构造方法
1.格式
2.示例
五、类名引用成员方法
1.格式
2.略微不同的方法引用规则
3.示例
六、引用数组的构造方法
1.格式
2.示例
一、简介
方法引用就是,把已有的方法拿过来,当作函数式中抽象方法的方法体。
为什么要使用方法引用?
在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿参数做操作
那么考虑一种情况:如果我们在Lambda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再写重复逻辑呢?答案肯定是没有必要
那我们又是如何使用已经存在的方案的呢?
这就是方法引用的用处了,我们通过方法引用来使用已经存在的方案。
下面示例更能明白方法引用的好处:
上面示例 ,使用匿名内部类和lambda表达式的方法必须重新实现方法,但是方法引用可以用类实现好的方法拿来使用。
但是这些方法能被拿来方法引用是有条件的(适用二、三、四、六):
1.引用处需要是函数式接口
2.被引用的方法需要已经存在
3.被引用方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
4.被引用方法的功能需要满足当前的要求
刚才的示例代码用到方法引用的地方就是函数式接口的地方,即Arrays类的sort方法的第二个参数comparator,这个参数是一个函数式接口,底层代码如下:
什么是函数式接口?函数式接口就是一个接口,而且这个接口只有一个抽象方法 。
可以被隐式地转换为一个 lambda 表达式或方法引用。这样的接口使得函数式编程在 Java 中成为可能,尤其是在使用 Java 8 引入的流(Stream)和 lambda 表达式时。
在 Java 中,可以通过
@FunctionalInterface
注解来明确标识一个接口为函数式接口。尽管这个注解是可选的,但使用它可以帮助编译器检查该接口是否符合函数式接口的规范。
二、引用静态方法
1.格式
类名::方法名
范例:Integer::parseInt
注意 :: 该符号为引用运算符,而它所在的表达式被称为方法引用
2.示例
将集合里面的字符串转化为数字
3.条件解析
下面是Stream接口的抽象方法map,参数是一个Function接口
Function接口这个参数是函数式接口,底层如下。满足第一个条件,方法引入的地方为函数式接口FunctionalInterface
下面是Integer类的静态方法parseInt,返回类型和参数值满足,方法有内容实现,刚好满足字符串转数字的功能需求。到这里就满足方法引用的后面三个条件。
三、引用成员方法
1.格式
对象::成员方法名
注意在静态方法里面比 (如main) 不能用this、super
2.示例
注意:main方法里面是禁止使用this、super的
四、引用构造方法
1.格式
类名::new
范例:Student::new
作用:创建一个对象
2.示例
准备好一个Student类
用引用构造方法的方式将字符串转换出对象
五、类名引用成员方法
1.格式
类名::方法名
范例:String::toUpperCase()
2.略微不同的方法引用规则
前面只有静态方法才能使用类名::方法名,普通方法也要这样用就必须遵守下面的规则。与原规则不同的地方在于形参。
新规则:
上面的规则说到了抽象方法的第二个形参到最后一个,被引用的方法必须一样。那么抽象方法的第一个参数呢?
抽象方法的第一个参数其实就是我们要用的方法引用的方法所在的类,就是::前面的类名,用官方的话来说就是--被引用方法的调用者。一般是流中的每一个数据的数据类型。
还有一个问题就是,如果抽象方法的第二个参数是空的呢?
抽象方法的第二个参数是空的,表示被引用方法是无参的。
局限性:因为有抽象方法的形参限制,并不是所有的普通方法都能引用。
3.示例
需求:将集合中的字符串小写转大写
下面是map的形参即函数式接口,它的抽象方法只有一个参数,所以只能引用无参的方法,流的数据类型是String,所以选用String的无参方法。
下面左边是匿名内部类的写法,右边是String类的无参方法toUpperCase将小写字母转大写,满足功能需求。返回值由被引用的方法决定。
六、引用数组的构造方法
1.格式
数据类型[ ]::new
范例:int[ ]::new
注意:数组中的数据必须跟流中的数据一样
2.示例
函数式接口的抽象方法