[Java]“语法糖”系列(一)之方法引用(Method References)
2017-11-23 22:44
351 查看
>前言
首先,JAVA的方法引用需要在JDK8以上才能运作,因为它是JDK8引入的新特性。
JAVA经过这么多版本的迭代,已经跟几十年前的C++之流完全不同了;在JAVA中,引入了很多更抽象的语言特性,比如Lambda、迭代器、方法引用之类的,有人视之为语法糖,因为这些新的高级语言特性确实精简了编写代码时的工作量、也使得整体代码更加易读(前提是你学习了这些语言特性)。Anders Hejlsberg就提到过编程语言在未来会逐渐分化并融合各自的特性,在传统的声明式语言上更加抽象化地加入函数式编程方法。
>方法引用
方法引用的用处就是在Lambda表达式中进一步精简代码和突出代码行为,是函数式编程思想的另一体现。
主要有四类:
下面我们将给出一个例子,来对这四种方法引用做介绍。
>一个实例
>实例解析
首先,我们要先了解Arrays.forEach方法:
也就是,上文实例代码中的这一行:
同样的道理,可以去对比2.2和3、2.1和2.2,很容易就能看懂什么时候要用静态引用、什么时候可以带参。
还需要注意的是:必须给出一个无参构造函数才能使用‘构造引用’。
我在实例代码中还给出了一个静态的create方法,该方法中的Supplier接口是一个函数式接口:
首先,JAVA的方法引用需要在JDK8以上才能运作,因为它是JDK8引入的新特性。
JAVA经过这么多版本的迭代,已经跟几十年前的C++之流完全不同了;在JAVA中,引入了很多更抽象的语言特性,比如Lambda、迭代器、方法引用之类的,有人视之为语法糖,因为这些新的高级语言特性确实精简了编写代码时的工作量、也使得整体代码更加易读(前提是你学习了这些语言特性)。Anders Hejlsberg就提到过编程语言在未来会逐渐分化并融合各自的特性,在传统的声明式语言上更加抽象化地加入函数式编程方法。
>方法引用
方法引用的用处就是在Lambda表达式中进一步精简代码和突出代码行为,是函数式编程思想的另一体现。
主要有四类:
引用类型 | 引用示例 |
构造方法 | $ClassName::new |
实例方法 | $instance::$methodName |
类任意对象实例 | $ClassName::$methodName |
类静态方法 | $ClassName::$staticMethodName |
>一个实例
public class Sugar { public static void main(String[] args){ Person p0 = new Person("Teacher"); Person p1 = new Person("Tom"); Person p2 = new Person("Jam"); List<Person> list = Arrays.asList(p1,p2); list.forEach(Person::sayHello);//(x)->Person.sayHello(x) list.forEach(Person::total);//(x)->x.total() list.forEach(Person::sayGoodbye);//(x)->x.sayGoodbye() list.forEach(p0::sayGoodbyeTo);//(x)->p0.sayGoodbyeTo(x) Person p3 = Person.create("Baby",Person::new); p3.sayGoodbye(); } } class Person{ private static int sum = 0; private String name; public Person(){}//必须给出一个无参构造函数才能使用‘构造引用’ public Person(String name){ this.name = name; Person.sum++; } //针对list.forEach(Consumer)做1~3,已知forEach的动作是每次向Consumer传递一个list中的对象 //1 静态 带参 Person::sayHello public static void sayHello(Person p){ System.out.println(p.name + " Say Hello!"); } //2.1 非静态 不带参 Person::total public void total(){ System.out.println("Sum:"+Person.sum); } //2.2 实例方法(非静态) 不带参 Person::sayGoodbye public void sayGoodbye(){ System.out.println(this.name + " Say Goodbye!"); } //3 实例方法(非静态) 带参 p0::sayGoodbyeTo public void sayGoodbyeTo(Person p){ System.out.println(this.name + " Say Goodbye To "+p.name); } //4.引用构造方法 public static Person create(String name,Supplier< Person > supplier){ Person p = supplier.get(); p.name = name; return p; } }输出:
>实例解析
首先,我们要先了解Arrays.forEach方法:
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { //依次给出本list中的每一个listItem action.accept(t); } }注意到,forEach对给定的动作(Consumer action),依次给出本list中的每一个listItem,调用该方法,并传入该listItem作为唯一的参数,去执行这个动作。这个动作(行为),就是一个函数,是函数式编程思想的体现。
也就是,上文实例代码中的这一行:
list.forEach(Person::sayHello);实际上静态方法sayHello收到了一个Person实例作为输出,并执行了sayHello方法。如果我们把原本的静态带参(一个)函数sayHello方法改成:
public void sayHello(Person p){ System.out.println(p.name + " Say Hello!"); }也就是非静态带参函数,那么编译器就会报错。结合实例代码中的3,可以很容易理解其报错的原因:forEach传入了一个作为参数的Person却找不到一个作为执行实例的Person(因为此时不是静态方法了)。
同样的道理,可以去对比2.2和3、2.1和2.2,很容易就能看懂什么时候要用静态引用、什么时候可以带参。
还需要注意的是:必须给出一个无参构造函数才能使用‘构造引用’。
我在实例代码中还给出了一个静态的create方法,该方法中的Supplier接口是一个函数式接口:
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }可以近似认为是一个专供函数式编程(此处暂时缩小范围为:方法引用中的“构造引用”)使用的工厂方法。
相关文章推荐
- javaSE_8系列博客——Java语言的特性(三)--类和对象(20)--嵌套类(Lambda 表达式--VS--方法引用)
- 读书笔记——《Java 8实战》系列之方法引用
- 在java中实现C#语法里的按引用传递参数的方法
- Java 8新特性:新语法方法引用和Lambda表达式及全新的Stream API
- 08/31号,Java基础语法部分==》方法的创建及引用
- Java 8新特性:新语法方法引用和Lambda表达式及全新的Stream API
- Java8中Lamda表达式和方法引用的基本语法
- JAVA面试题解惑系列(五)——传了值还是传了引用?
- Java常见笔试面试题目深度剖析系列之:Java方法参数传递详解
- JAVA面试题解惑系列(五)——传了值还是传了引用?
- java方法参数传值传引用的一点看法
- JAVA面试题解惑系列(五)——传了值还是传了引用?
- vs2008中使用母版页关于引用*.js的[智能语法提示]和[设置路径]的方法和问题
- Java语法总结 - 方法
- 在java bean中对一个java文件进行语法分析 的方法
- 从JVM内存管理的角度谈谈静态方法和静态属性 和 java对象引用与JVM自动内存管理
- JAVA WebService注册中心JUDDI使用方法(引用)
- JAVA面试题解惑系列(五)——传了值还是传了引用?
- java 命令行引用jar包的方法
- 总结java方法(函数)传值和传引用的问题