zoukankan      html  css  js  c++  java
  • JDK1.8新特性之(二)--方法引用

    在上一篇文章中我们介绍了JDK1.8的新特性有以下几项。

    1.Lambda表达式

    2.方法引用

    3.函数式接口

    4.默认方法

    5.Stream

    6.Optional类

    7.Nashorm javascript引擎

    8.新的日期时间API

    9.Base64

    并且学习了JDK1.8最重要的特性--Lambda表达式这一篇学习方法引用。

    首先介绍方法引用是啥?

          方法引用单从“引用”二字不难理解,我们经常拿毛主席的”不管黑猫白猫能抓住老鼠的猫就是好猫“这句话来说事情,这里就是引用了毛主席的话。那么方法引用就是拿过其他地方已经存在的方法,我们拿过来使用,在这里可以理解成Lambda表达式的一种特殊用法。只是我们得按照一定的规则来用。也就是我们接下来要重点要学习的内容:方法引用的方式

    接下来先列出方法引用的方式。

          总体来说方法引用有三种方式,分别如下。

      1.普通方法引用
    1.1 实例方法引用(通过实例对象)
    对象::实例方法名;
    1.2 静态方法引用
    类名::静态方法名;
    1.3 实例方法引用(通过类名)
    类名::实例方法名;
    注:上面两种实例方法引用的不同之处,通过下面代码详细说明。
      2.构造器引用
    类名::new;
      3.数组引用
    类型::new;

    下面重点通过实例来学习上面的集中形式。
    1.1 实例方法引用(通过实例对象)
    下面通过最简单的打印输出语句来理解实例方法引用。
     1 public class MethodReferenceTest {
     2 
     3     /**
     4      * 为了更容易理解方法引用
     5      * 我通过正常的Lambda表达式和方法引用两种方式来实现代码部分
     6      */
     7     //*****************************
     8     // 方法引用的形式一  对象::实例方法名
     9     //*****************************
    10     @Test
    11     public void test1(){
    12         //Lambda表达式
    13         PrintStream ps1 = System.out;
    14         Consumer con1 = x -> ps1.println(x);
    15         con1.accept("Hello Lambda表达式!");
    16 
    17         //方法引用
    18         PrintStream ps2 = System.out;
    19         Consumer con2 = ps2::println;
    20         con2.accept("Hello 方法引用!");
    21     }
    22 
    23 }

    执行结果

    ...
    com.dream.test.JDK8speciality.MethodReferenceTest,test1 Hello Lambda表达式! Hello 方法引用! Process finished with exit code
    0

     通过上面实例14行和19行的对比可以看出,使用方法引用的方式比直接Lambda表达式更简洁,再次也可以看做方法引用是Lambda表达式的一种特殊写法,学习了Lambda表达式,方法引用的写法也就不难理解了。

    注:Consumer是JDK1.8的java.util.function包下提供的一个函数式接口,accept方法接收一个泛型<T>类型,返回值为void的抽象方法。具体实现是Lambda表达式的部分去实现的,也就是 x -> ps1.println(x);ps2::println; 关于JDK1.8提供的函数式接口会在后面函数式接口章节进行学习。

    1.2 静态方法引用
    下面通过比较两个整数的大小来理解静态方法的引用。
     1 public class MethodReferenceTest {
     2 
     3     //*****************************
     4     // 方法引用的形式二  类名::静态方法名
     5     //*****************************
     6     @Test
     7     public void test2(){
     8         //Lambda表达式
     9         //x > y:返回1;
    10         //x = y:返回0;
    11         //x < y:返回-1;
    12         Comparator<Integer> com1 = (x,y)->Integer.compare(x,y);
    13         Integer i1=com1.compare(2,1);
    14         System.out.println("Lambda表达式结果:" + i1);
    15 
    16         //方法引用
    17         Comparator<Integer> com2 = Integer::compare;
    18         Integer i2=com2.compare(2,1);
    19         System.out.println("方法引用结果:" + i2);
    20     }
    21 
    22 }

    执行结果

    com.dream.test.JDK8speciality.MethodReferenceTest,test2
    Lambda表达式结果:1
    方法引用结果:1
     
    Process finished with exit code 0

    正常通过Lam表达式我们 (x,y)->Integer.compare(x,y);这样写,由于Integer类下有静态方法已经实现了两个整数的比较,所有我们通过静态方法引用的方式直接引用就好了。由此变成了Integer::compare;

    1.3 实例方法引用(通过类名)
    通过比较两个字符串的内容来说明。
     1 public class MethodReferenceTest {
     2 
     3     //*****************************
     4     // 方法引用的形式三 类名::实例方法
     5     //*****************************
     6     @Test
     7     public void test3(){
     8         //比较两个字符串的内容
     9         //Lambda表达式
    10         BiPredicate<String,String> bp1 = (s1,s2) -> s1.equals(s2);
    11         boolean b1 = bp1.test("abc","abc");
    12         System.out.println("Lambda结果:" + b1);
    13 
    14         //方法引用
    15         BiPredicate<String,String> bp2 = String::equals;
    16         boolean b2 = bp2.test("abc","abc");
    17         System.out.println("方法结果:" + b2);
    18     }
    19 
    20 }
    
    

    执行结果

    ...
    com.dream.test.JDK8speciality.MethodReferenceTest,test3 Lambda结果:
    true 方法结果:true Process finished with exit code 0

    通过对象的方式引用和通过类名的方式引用不同之处是:当函数式参数列表的第一个参数是方法的调用者,而且第二个参数是被调用方法的参数的时候,我们就需要用【类名::方法名】的方式来书写代码。

    这里的BiPredicate也是JDK1.8的java.util.function包下的函数是接口,关于函数式接口会在后面函数式接口章节进行学习,在这里知道它是函数接口接口即可。

    2.构造器引用

    由于构造器是创建对象的时候使用的所以这里也是要用new关键字的。也就是【类名::new】的形式。

     1 public class MethodReferenceTest {
     2 //*****************************
     3     // 构造器引用  类名::实例方法
     4     //*****************************
     5     @Test
     6     public void test4(){
     7         //通过无参数的构造器创建对象
     8         System.out.println("无参构造器");
     9         //Lambda表达式
    10         System.out.println("Lambda表达式:");
    11         Supplier<User> su1 =() -> new User();//Lambda表达式没有参数的时候圆括号不可省略
    12         User user1 = su1.get();
    13         System.out.println("userName:" + user1.getUserName() + " pwd:" + user1.getPwd());
    14 
    15         //构造器引用
    16         System.out.println("构造器引用:");
    17         Supplier<User> su2 = User::new;
    18         User user2 = su2.get();
    19         System.out.println("userName:" + user2.getUserName() + " pwd:" + user2.getPwd());
    20 
    21         //通过有参数的构造器创建对象
    22         System.out.println("有参数构造器");
    23         //Lambda表达式
    24         System.out.println("Lambda表达式:");
    25         BiFunction<String,String,User> bf1 = (userName,pwd) -> new User(userName,pwd);
    26         User user3 = bf1.apply("12345@163.com","987654321");
    27         System.out.println("userName:" + user3.getUserName() + " pwd:" + user3.getPwd());
    28 
    29         //构造器引用
    30         System.out.println("构造器引用:");
    31         BiFunction<String,String,User> bf2 = User::new;
    32         User user4 = bf2.apply("12345@163.com","987654321");
    33         System.out.println("userName:" + user4.getUserName() + " pwd:" + user4.getPwd());
    34 
    35         /**
    36          * 通过对以上有参数,无参数的构造器引用的实例可以看出:
    37          * 无论构造器参数有几个,引用部分的代码都是ClassName::new,不同的是函数式接口。
    38          */
    39     }
    40 
    41 }

    执行结果

    ...
    com.dream.test.JDK8speciality.MethodReferenceTest,test4 无参构造器 Lambda表达式: userName:
    null pwd:null 构造器引用: userName:null pwd:null 有参数构造器 Lambda表达式: userName:12345@163.com pwd:987654321 构造器引用: userName:12345@163.com pwd:987654321 Process finished with exit code 0

    有了前面几个方法引用的了解这里也就不难理解,只要记住构造方法引用的形式即可。需要注意的是:当Lambda表达式的没有参数的时候必须写上【() -> 】不能省略,否则报错。

    还有一个需要注意的点就是,无论构造器有几个参数,构造器引用的形式都是【类名::构造器名】。变化的使用的函数式接口不同而已。关于函数式接口详细会在后面函数式接口章节进行学习。

    3.数组引用

    数组引用的形式和构造器引用的形式类似只是变成了【类名[]::构造器名】而已。也不用做过多解释。直接看例子即可。

     1 public class MethodReferenceTest {
     2 
     3     //*****************************
     4     // 数组引用  类型::new
     5     //*****************************
     6     @Test
     7     public void test5(){
     8         //Lambda表达式
     9         Function<Integer,Integer[]> f1 =i -> new Integer[i];
    10         Integer[] iArray1 = f1.apply(10);
    11         System.out.println("Lambda表达式:Array长度为" + iArray1.length);
    12 
    13         //数组引用
    14         Function<Integer,Integer[]> f2 =Integer[]::new;
    15         Integer[] iArray2 = f2.apply(10);
    16         System.out.println("数组引用:Array长度为" + iArray2.length);
    17     }
    18 
    19 }

    执行结果

    ...
    com.dream.test.JDK8speciality.MethodReferenceTest,test5 Lambda表达式:Array长度为10 数组引用:Array长度为10 Process finished with exit code
    0

    这里使用了Function函数式接口,也会在接下来的文章中解释。

    以上就是我对于方法引用的理解,如果有理解错误或者写的不好的地方还请各位大神不吝赐教呀。欢迎指正。

     

    上一篇文章

    JDK1.8新特性之(一)--Lambda表达式

  • 相关阅读:
    15天学会jquery
    js常用方法
    js兼容注意事项--仅供参考
    Javascript面向对象特性实现封装、继承、接口详细案例
    关于sql用<>不等于查询数据不对问题
    解决document.onclick在IE下用不了或无效的问题
    解决Button设置disabled后无法执行后台代码问题
    利用Wireshark截取数据包,并对数据包进行解析
    导入本地文本中的数据到MySQL数据库中
    删除数据库中重复项
  • 原文地址:https://www.cnblogs.com/worthycoder/p/12932684.html
Copyright © 2011-2022 走看看