【java8新特性】方法引用

欢迎交流java8新特性系列文章:https://www.jianshu.com/nb/27231419 . [1][2][3][4][5]

一、简介

     方法引用是java8的新特性之一, 可以直接引用已有Java类或对象的方法或构造器。方法引用与lambda表达式结合使用,可以进一步简化代码。
     来看一段简单代码:

    public static void main(String[] args) {
        List<String> strList = Arrays.asList(new String[] { "a", "c", "b" });

        strList.stream().sorted((s1, s2) -> s1.compareToIgnoreCase(s2)).forEach(s -> System.out.println(s));
    }

上述程序生成一个Stream流,对流中的字符串进行排序并遍历打印。程序中采用lambda表达式的方式代替匿名类简化了代码,然而代码中两处lambda表达式都仅仅调用的是一个已存在的方法:String.compareToIgnoreCase、System.out.println,这种情况可以用方法引用来简化:

    public static void main(String[] args) {

        List<String> strList = Arrays.asList(new String[] { "a", "c", "b" });

        strList.stream().sorted(String::compareToIgnoreCase).forEach(System.out::println);
    }

对比一下可以看到,上述程序分别采用了类的任意对象的实例方法引用特定对象的实例方法引用两种方法引用形式(下一章会讲述),采用方法引用的方式可以简化lambda表达式的写法。

二、方法引用的具体使用

java8方法引用有四种形式:

  • 静态方法引用       :   ClassName :: staticMethodName
  • 构造器引用        :   ClassName :: new
  • 类的任意对象的实例方法引用:   ClassName :: instanceMethodName
  • 特定对象的实例方法引用  :   object :: instanceMethodName

lambda表达式可用方法引用代替的场景可以简要概括为:lambda表达式的主体仅包含一个表达式,且该表达式仅调用了一个已经存在的方法。方法引用的通用特性方法引用所使用方法的入参和返回值与lambda表达式实现的函数式接口的入参和返回值一致

2.1  静态方法引用

    静态方法引用的语法格式为: 类名::静态方法名 ,如
System.out::println 等价于lambda表达式 s -> System.out.println(s) ,代码示例:

public class Test
{
    public static void main(String[] args)
    {
        //lambda表达式使用:
        Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(s -> Test.println(s));
        //静态方法引用:
        Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(Test::println);
    }
    
    public static void println(String s)
    {
        System.out.println(s);
    }
}

静态方法引用适用于lambda表达式主体中仅仅调用了某个类的静态方法的情形

2.2  构造器引用

   &nbsp构造器引用的语法格式为: 类名::new ,如() -> new ArrayList<String>() 等价于 ArrayList<String>::new,代码示例:

Supplier<List<String>> supplier1= () -> new  ArrayList<String>();

等价于


Supplier<List<String>> supplier = ArrayList<String>::new;

构造器引用适用于lambda表达式主体中仅仅调用了某个类的构造函数返回实例的场景

2.3  类的任意对象的实例方法引用

   &nbsp类的任意对象的实例方法引用的语法格式为: 类名::实例方法名 , 这种方法引用相对比较复杂,我们来看示例:

一、示例1

  Arrays.sort(strs,(s1,s2)->s1.compareToIgnoreCase(s2));

等价于

  Arrays.sort(strs, String::compareToIgnoreCase);

上述示例中,strs为一个String数组,lambda表达式(s1,s2)->s1.compareToIgnoreCase(s2)实现函数式接口的是Comparator接口, 我们看下jdk8中Comparator接口的源码(截取部分):

  @FunctionalInterface
  public interface Comparator<T> {
      int compare(T o1, T o2);
  }

而String类的compareToIgnoreCase方法源码为:

    public int compareToIgnoreCase(String str) {
        return CASE_INSENSITIVE_ORDER.compare(this, str);
    }

可以发现函数式接口Comparator<String>的compare方法比String类的compareToIgnoreCase方法多了一个String类型的入参。看到这里对类的任意对象的实例方法引用的使用可能似懂非懂,下面我们看一个自己实现一个类的任意对象的实例方法引用的示例(示例2)。

二、示例2

public class Student
{
    
    private String name;
    
    private Integer score;
    
    public void setNameAndScore(String name, Integer score)
    {
        this.name = name;
        this.score = score;
        System.out.println("Student "+  name +"'s score is " + score);
    }
     
    public static void main(String[] args)
    {
        /*lambda表达式的用法:
        TestInterface testInterface = (student, name, score) -> student.setNameAndScore(name, score);*/
        //类的任意对象的实例方法引用的用法:
        TestInterface testInterface = Student::setNameAndScore;
        testInterface.set(new Student(), "DoubleBin", 100);
    }
    
    @FunctionalInterface
    interface TestInterface
    {
        // 注意:入参比Student类的setNameAndScore方法多1个Student对象,除第一个外其它入参类型一致
        public void set(Student d, String name, Integer score);
    }
}

看完上述代码,我们可以总结出类的任意对象的实例方法引用的特性为:

  • 1、方法引用的通用特性:方法引用所使用方法的入参和返回值与lambda表达式实现的函数式接口的入参和返回值一致;
  • 2、lambda表达式的第一个入参为实例方法的调用者,后面的入参与实例方法的入参一致
2.4  特定对象的实例方法引用

   &nbsp特定对象的实例方法引用的语法格式为: 对象::实例方法名 , 示例代码:

public class Test
{
    public static void main(String[] args)
    {
        Test test = new Test();
        // lambda表达式使用:
        Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(s -> test.println(s));
        // 特定对象的实例方法引用:
        Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(test::println);
    }
    
    public void println(String s)
    {
        System.out.println(s);
    }
}

特定对象的实例方法引用适用于lambda表达式的主体中仅仅调用了某个对象的某个实例方法的场景

三、总结

     方法引用使用运算符::连接类(或对象)与方法名称(或new)实现在特定场景下lambda表达式的简化表示,使用时要注意方法引用的使用场景及各种方法引用的特性。使用方法引用的好处是能够更进一步简化代码编写,使代码更简洁。
     然而作者认为,方法引用代替lambda表达式对代码的简化程度远远没有lambda表达式代替匿名类的简化程度大, 有时反而增加了代码的理解难度(如2.3节:类的任意对象的实例方法引用),且使用场景的局限性不利于增加或修改代码,个人认为有时没有必要刻意使用方法引用~


  1. 【java8新特性】lambda表达式与函数式接口详解

  2. 【java8新特性】Stream API详解

  3. 【java8新特性】Optional详解

  4. 【java8新特性】方法引用

  5. 【java8新特性】默认方法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容