函数式编程--方法和构造器引用
来源:互联网 发布:东莞厂货aj哪淘宝店好 编辑:程序博客网 时间:2024/06/06 01:03
前面已经说过了,如果lambda表达式的代码块只有一行代码,可以省略lambda表达式中代码块的花括号,语句后面的逗号也要省去的。不仅如此,如果lambda表达式的代码块只有一行代码,还可以在代码中使用方法引用和构造器引用。
上面的Lambda表达式的代码块(注释掉的代码)只有一行代码,所以程序可以省略该代码块的花括号,而且由于该函数式接口里面的convert()方法需要返回值,所以Lambda表达式会把这条代码的值作为返回值。现在我们用方法引用来代替Lambda表达式,将Converter接口中被实现方法的全部参数传给该类方法作为参数。比如上面我们自己写的这行代码Converter converter = Integer::parseInt;当我们调用该接口中的唯一的抽象方法时,调用参数将会传给Integer类的parseInt方法。
super::方法名字
上面的lambda表达式只有一行代码,而且是调用了某一个类的构造器,所以我们可以使用构造器引用来替换。new就代表使用该类的构造器,这里有一个问题,我们直接使用某一个类的new来表示调用这个类的构造器,那么如果说这个类很多个构造器的时候,应该要使用哪一个构造器呢?这里取决于调用函数式接口里面的抽象方法时传入的参数类型,比如上面代码我们调用Converter类的convert方法,实际传入一个String类型的参数,那么这个参数将会传入到String的使用String类型作为参数的构造器中,上面的构造器引用将调用String类的,带一个String参数的构造器。
上面写的一些例子只是显示了使用方法引用的机制,并没有展现他的真正优势。方法引用能够一展拳脚的一处地方是在与集合一起时候的时候,比如说现在我们要使用Collections类定义的max()方法来确定集合中最大的元素,以前我们传入一个集合,还要传入一个实现了Comparator<T>接口的对象的实例,匿名内部类,比较麻烦的。现在我们只需要自己实现一个与Comparator接口中定义的compare()方法兼容的方法就可以。比如下面代码:
方法引用和构造器引用可以让lambda表达式编码更加简洁,具体语法就是使用2个英文冒号,然后加上方法名字,注意没有括号的。一共有4种情况,类引用类方法,对象引用实例方法,类引用构造器都很好理解,注意的是这里还有一个类引用实例方法。
- 1,引用类方法
public class Test{public static void main(String[] args){//原始的方法//Converter converter = str -> Integer.parseInt(str);//使用类方法引用Converter converter = Integer::parseInt;System.out.println(converter.convert("25"));}}@FunctionalInterfaceinterface {//定义一个将字符串串成integer的方法Integer convert(String str);}
上面的Lambda表达式的代码块(注释掉的代码)只有一行代码,所以程序可以省略该代码块的花括号,而且由于该函数式接口里面的convert()方法需要返回值,所以Lambda表达式会把这条代码的值作为返回值。现在我们用方法引用来代替Lambda表达式,将Converter接口中被实现方法的全部参数传给该类方法作为参数。比如上面我们自己写的这行代码Converter converter = Integer::parseInt;当我们调用该接口中的唯一的抽象方法时,调用参数将会传给Integer类的parseInt方法。
- 2,引用特定对象的实例方法
public class Test{public static void main(String[] args){//原始的lambda表达式//Converter converter = str -> "LinkinPark".indexOf(str);//使用类方法引用Converter converter = "LinkinPark"::indexOf;System.out.println(converter.convert("kin"));}}@FunctionalInterfaceinterface Converter{//定义一个将获取字符串下表的方法Integer convert(String str);}上面我们的注释掉的lambda表达式只有一行调用"LinkinPark"的indexOf()实例方法的代码,所以我们使用方法引用来代替。对于上面的实例方法引用,也就是调用字符串对象"LinkinPark"的indexOf()实例方法时,调用参数将会传给"LinkinPark"对象的indexOf()的实例方法。
- 3,引用类的实例方法
public class Test{public static void main(String[] args){//原始的lambda表达式//Converter converter = (str, index, end) -> str.substring(index, end);//使用方法引用Converter converter = String::substring;System.out.println(converter.convert("LinkinPark", 0, 6));}}@FunctionalInterfaceinterface Converter{/** * @param str 原始的字符串 * @param index 开始截图的下标 * @param end 终止截图的下标 * @return 截取后的字符串 * @Description: 定义一个截取字符串的方法 */String convert(String str, int index, int end);}这个语法我们在第一次使用的时候觉得有点别扭,记住就好了。针对上面的代码,当我们调用Converter接口中的唯一的抽象方法时,第一个调用参数将作为substring方法的调用者,剩下的调用参数将会作为substring()实例方法的调用参数。另外一点,通过使用super,可以引用方法的父类版本,语法如下:
super::方法名字
- 4,构造器引用
public class Test{public static void main(String[] args){//原始的lambda表达式//Converter converter = str -> new String(str);//使用构造器引用Converter converter = String::new;System.out.println(converter.convert("LinkinPark"));}}@FunctionalInterfaceinterface Converter{//定义一个方法,处理一个字符串然后在返回一个字符串String convert(String str);}
上面的lambda表达式只有一行代码,而且是调用了某一个类的构造器,所以我们可以使用构造器引用来替换。new就代表使用该类的构造器,这里有一个问题,我们直接使用某一个类的new来表示调用这个类的构造器,那么如果说这个类很多个构造器的时候,应该要使用哪一个构造器呢?这里取决于调用函数式接口里面的抽象方法时传入的参数类型,比如上面代码我们调用Converter类的convert方法,实际传入一个String类型的参数,那么这个参数将会传入到String的使用String类型作为参数的构造器中,上面的构造器引用将调用String类的,带一个String参数的构造器。
- 总结一下:
public class Test{//这其实就是命令者模式public String test(String str, StringFunc func){return func.convert(str);}public String test1(StringFuncImpl stringFuncImpl, String str, StringFunc1 func){return func.convert(stringFuncImpl, str);}public StringFuncImpl test2(String str, StringFunc2 func){return func.getStringFuncImpl(str);}public static void main(String[] args){Test test = new Test();StringFuncImpl stringFuncImpl = new StringFuncImpl();//下面的代码输出LinkinPark...System.out.println(test.test("LinkinPark", StringFuncImpl::convert));System.out.println(test.test("LinkinPark", stringFuncImpl::convert1));System.out.println(test.test1(stringFuncImpl, "LinkinPark", StringFuncImpl::convert1));System.out.println(test.test2("LinkinPark", StringFuncImpl::new).getName());}}@FunctionalInterfaceinterface StringFunc{//定义一个接口,一个方法来处理字符串String convert(String str);}@FunctionalInterfaceinterface StringFunc1{//定义一个接口,一个方法来处理字符串String convert(StringFuncImpl stringFuncImpl, String str);}@FunctionalInterfaceinterface StringFunc2{//得到一个StringFuncImpl实例StringFuncImpl getStringFuncImpl(String str);}class StringFuncImpl{private String name;public StringFuncImpl(){}public StringFuncImpl(String name){this.name = name;}public String getName(){return name;}//注意,这里要和上面的函数式接口兼容static String convert(String str){return str + "...";}String convert1(String str){return str + "...";}}
- 泛型中的方法引用
public class Test{public static <T> int test(T[] vals, T value, LinkinFunc<T> func){return func.func(vals, value);}public static void main(String[] args){Integer[] vals = { 1, 2, 3 };System.out.println(test(vals, 1, LinkinImpl::<Integer> countMatch));String[] valss = {"1","2","3"};System.out.println(test(valss, "1", LinkinImpl::<String> countMatch));}}@FunctionalInterfaceinterface LinkinFunc<T>{//一个处理泛型数组的算法int func(T[] vals, T value);}class LinkinImpl{//上面函数式接口的具体实现static <T> int countMatch(T[] vals, T value){int count = 0;for (T t : vals){if (t == value){count++;}}return count;}}阅读上面的代码没什么难度的,参数的传递发送在::的后面。当把泛型方法指定为方法引用时,参数类型出现在::之后,方法名称之前。需要指出的是在一般情况下,并非必须显示指定类型参数,类型参数会被自动推断得出。
上面写的一些例子只是显示了使用方法引用的机制,并没有展现他的真正优势。方法引用能够一展拳脚的一处地方是在与集合一起时候的时候,比如说现在我们要使用Collections类定义的max()方法来确定集合中最大的元素,以前我们传入一个集合,还要传入一个实现了Comparator<T>接口的对象的实例,匿名内部类,比较麻烦的。现在我们只需要自己实现一个与Comparator接口中定义的compare()方法兼容的方法就可以。比如下面代码:
static int linkinCompare(MyClass a,MyClass b){retutn a.getId()-b.getId();}在调用时候直接用类名::linkinCompare就可以了。
0 0
- 函数式编程--方法和构造器引用
- Java8 方法引用和构造器引用
- 【书摘】C++编程思想:引用和拷贝构造函数
- 引用和拷贝构造函数 --C++编程思想
- C#构造函数的继承和引用方法
- Java8新特性——方法和构造函数引用
- Java8方法引用和构造器引用示例
- 引用和拷贝构造函数
- 引用和拷贝构造函数
- 引用和拷贝构造函数
- java8新特性之函数式接口、lambda表达式、接口的默认方法、方法和构造函数的引用
- JAVA8之方法引用和构造引用
- Java 8 函数式接口、lambda表达式、方法以及构造器引用
- java8 方法或构造函数的引用
- 方法引用与构造器引用
- 关于常引用和拷贝构造函数
- c++中的引用和拷贝构造函数
- C++编程思想(2nd卷一):引用和拷贝构造函数
- Oracle EBS 11i BOM模块常用表结构
- 091.Block And Var 块与局部变量
- 那些年使用的测试工具
- Unity3D中使用easyroad3d插件 删除道路
- 090.Block 定义块的三种方式
- 函数式编程--方法和构造器引用
- 中文分词测试
- CvArr、Mat、CvMat、IplImage、BYTE转换(总结而来)
- MySQL replication 主从配置
- Hello,Algorithm!(你好,算法!)
- 学习MyBatis与Spring,Maven报错整理!
- 在uboot中加入cmd_run命令,运行环境变量
- java计算百分比,取小数点后两位
- Python偏函数