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表达式

  • 相关阅读:
    HDU 2089 不要62
    HDU 5038 Grade(分级)
    FZU 2105 Digits Count(位数计算)
    FZU 2218 Simple String Problem(简单字符串问题)
    FZU 2221 RunningMan(跑男)
    FZU 2216 The Longest Straight(最长直道)
    FZU 2212 Super Mobile Charger(超级充电宝)
    FZU 2219 StarCraft(星际争霸)
    FZU 2213 Common Tangents(公切线)
    FZU 2215 Simple Polynomial Problem(简单多项式问题)
  • 原文地址:https://www.cnblogs.com/worthycoder/p/12932684.html
Copyright © 2011-2022 走看看