文章目录

  • Pre
  • 方法引用
    • 如何构建方法引用
      • 指向静态方法的方法引用
      • 指向任意类型实例方法的方法引用
      • 指向现有对象的实例方法的方法引用
    • 构造函数引用
    • 自定义构造函数引用

Pre

先来看段代码

  Comparator<Enginner> enginnerComparator = new Comparator<Enginner>() {@Overridepublic int compare(Enginner o1, Enginner o2) {return o1.getJob().compareTo(o2.getJob());}};enginnerComparator.compare(new Enginner("Java",18),new Enginner("Go",10));List<Enginner> enginnerList = Arrays.asList(new Enginner("Java",18),new Enginner("Go",10));System.out.println("0enginnerList:" + enginnerList);enginnerList.sort(enginnerComparator);System.out.println("1enginnerList:" + enginnerList);

排序嘛 ,是不是很长

使用方法引用,一行代码搞定,如下:

 enginnerList.sort(Comparator.comparing(Enginner::getJob));System.out.println("2enginnerList:" + enginnerList);

方法引用让你可以重复使用现有的方法定义,并像Lambda一样传递它们。在一些情况下比起使用Lambda表达式, 更易读 。上面的栗子就是借助了Java 8 API ,用方法引用写的一个排序的例子。


方法引用

方法引用可以被看作仅仅调用特定方法的Lambda的一种快捷写法。它的基本思想是,如果一个Lambda代表的只是“直接调用这个方法”,那最好还是用名称来调用它,而不是去描述如何调用它。

实际上,方法引用就是让你根据已有的方法实现来创建Lambda表达式。 显式地指明方法的名称,代码的可读性会更好 。

当你需要使用方法引用时,目标引用放在分隔符 :: 前,方法的名称放在后面

Enginner::getJob

就是引用了 Enginner类中定义的方法 getJob 。 请记住,不需要括号,因为你没有实际调用这个方法。

方法引用就是Lambda表达式 (Enginnera) -> a.getJob() 的快捷写法

再来看几个等效的例子 加深下印象

(Enginner a) -> a.getJob()    等价于  Enginner ::getJob

做下实验


public class MethodReferrenceDemo {public static <T, R> R doSomething(T t, Function<T, R> f) {return f.apply(t);}public static void main(String[] args) {Function<Enginner, String> ef = (Enginner e) -> e.getJob();System.out.println(doSomething(new Enginner("Java", 18), ef));Function<Enginner, String> ef2 = Enginner::getJob;System.out.println(doSomething(new Enginner("Java", 18), ef2));}
}

还比如

() -> Thread.currentThread().dumpStack()  等价于 Thread.currentThread()::dumpStack
(str, i) -> str.substring(i)  等价于  String::substring
(String s) -> System.out.println(s)  等价于  System.out::println

我们可以把方法引用看作针对仅仅涉及单一方法的Lambda的语法糖,因为你表达同样的事情
时要写的代码更少了。


如何构建方法引用

方法引用主要有三类。

指向静态方法的方法引用

举个例子 : Integer 的 parseInt 方法,写作 Integer::parseInt

        Function<String, Integer> stringIntegerFunction2 = (String s) -> Integer.parseInt(s);Function<String, Integer> stringIntegerFunction3 = Integer::parseInt;System.out.println(stringIntegerFunction2.apply("18"));System.out.println(stringIntegerFunction3.apply("18"));

指向任意类型实例方法的方法引用

举个例子 : String 的 length 方 法 , 写 作 String::length

  Function<String, Integer> stringIntegerFunction = (String s) -> s.length();Function<String, Integer> stringIntegerFunction1 = String::length;System.out.println(stringIntegerFunction.apply("abc"));System.out.println(stringIntegerFunction1.apply("abc"));

类似于 String::length 方法引用的思想就是你在引用一个对象的方法,而这个对象本身是Lambda的一个参数。

例如,Lambda表达式 (String s) -> s.toUppeCase() 可以写作 String::toUpperCase


指向现有对象的实例方法的方法引用

假设你有一个局部变量 eng用于存放 Enginner 类型的对象,它支持实例方法 getValue ,那么你就可以写 eng::getValue

这种写法是我们在Lambda中调用一个已经存在的外部对象中的方法。 例如,Lambda表达式()->eng.getValue() 可以写作 eng::getValue


再来看几个例子, 将Lambda表达式重构为等价的方法引用

lambda :   args -> ClassName.staticMethod(args)等价于  (1)方法引用:  className::staticMethod
lambda :   (arg0 ,rest)-> argo.instanceMethod(rest)   (arg0是ClassName类型的)等价于   (2)方法引用:  ClassName::instanceMethod
lambda :   (args)-> expr.instanceMethod(args)    等价于方法引用:  expr::instanceMethod

请注意,还有针对构造函数、数组构造函数和父类调用(super-call)的一些特殊形式的方法引用。

比方说你想要对一个字符串的 List 排序,忽略大小写。 List 的 sort 方法需要一个 Comparator 作为参数 。 我们知道 Comparator 描述了 一个具有 (T, T) -> int 签名的函数描述符。你可以利用 String 类中的 compareToIgnoreCase方法来定义一个Lambda表达式。

 List<String> list = Arrays.asList("apple","pear","banana");list.sort((s1,s2)-> s1.compareToIgnoreCase(s2));

Lambda表达式的签名与 Comparator 的函数描述符兼容。利用前面所述的方法,这个例子可以使用方法引用改成下面的样子

 list.sort(String::compareToIgnoreCase);

请注意,编译器会进行一种与Lambda表达式类似的类型检查过程,来确定对于给定的函数式接口,这个方法引用是否有效:方法引用的签名必须和上下文类型匹配

来个小测验吧

测验:方法引用
下列Lambda表达式的等效方法引用是什么?(1) Function<String, Integer> stringToInteger =
(String s) -> Integer.parseInt(s);
(2) BiPredicate<List<String>, String> contains =
(list, element) -> list.contains(element);答案如下。
(1) 这个Lambda表达式将其参数传给了 Integer 的静态方法 parseInt 。这种方法接受一
个需要解析的 String ,并返回一个 Integer 。因此,可以使用 Lambda表达式调用静态方法来重写Lambda表达式,如下所示:
Function<String, Integer> stringToInteger = Integer::parseInt;(2) 这个Lambda使用其第一个参数,调用其 contains 方法。由于第一个参数是 List 类型
的,你可以使用刚才的(2) 如下:
BiPredicate<List<String>, String> contains = List::contains;这是因为,目标类型描述的函数描述符是  (List<String>,String) -> boolean ,而
List::contains 可以被解包成这个函数描述符。

构造函数引用

对于一个现有构造函数,我们可以利用它的名称和关键字 new 来创建它的一个引用:ClassName::new 。它的功能与指向静态方法的引用类似。

例如,假设有一个构造函数没有参数。它适合 Supplier 的签名 () -> Enginner。

Enginner的构造函数

我们可以这样做:

  // 构造函数引用指向默认Enginner的构造函数Supplier<Enginner> supplier = Enginner::new;// 调用 Supplier 的 get 方法 将产生一个新的 enginner Enginner enginner = supplier.get();

等价于

    Supplier<Enginner> s = () -> new Enginner();// 利用默认构造函数创建 Enginner的Lambda表达式Enginner supplier2 = s.get();// 调用 Supplier 的 get 方法 将产生一个新的 Enginner

如果Enginner构造函数的签名是 Enginner(String job) ,那么它就适合 Function 接口的签
名,我们可以这样写:

// 指向 Enginner(String job) 的构造函数引用Function<String ,Enginner> f2 =  Enginner::new; // 调用该 Function 函数的 apply 方法,并给出职位,将产生一个 Enginner Enginner e2 =f2.apply("Java");System.out.println(e2.getJob());

如果你有一个具有两个参数的构造函数 Enginner(String job, Integer age) ,那么
它就适合 BiFunction 接口的签名 . 两个参数的 使用BiFunction 即可 (Bi = Binary )

  BiFunction<String ,Integer,Enginner> f3 = Enginner::new;Enginner e4 = f3.apply("Java",18);System.out.println(e4 .getJob() + " - " +  e4.getAge());

上面是使用方法引用,如果直接用lambda呢? 如下

     BiFunction<String,Integer,Enginner> f4 = (str , age)-> new Enginner(str, age);Enginner ee =f4.apply("Go", 10);System.out.println(ee .getJob() + " - " +  ee.getAge());


自定义构造函数引用

上面的栗子我们将有零个、一个、两个参数的构造函数转变为构造函数引用。那要怎么样才能对具有三个参数的构造函数,比如 Color(int, int, int), 使用构造函数引用呢?

构造函数引用的语法是 ClassName::new ,那么在这个例子里面就是Color::new 。但是你需要与构造函数引用的签名匹配的函数式接口。但是语言本身并没有提供这样的函数式接口,你可以自己创建一个:

public interface TriFunction<T, U, V, R>{R apply(T t, U u, V v);
}

现在你可以像下面这样使用构造函数引用了:

TriFunction<Integer, Integer, Integer, Color> colorFactory = Color::new;

Java 8 - 05 方法引用相关推荐

  1. 你知道Java 8 的方法引用吗

    1. 前言 Java中的方法引用,很多同学都见过但却叫不出名字甚至不太会用,在这篇文章中,我们将看到什么是方法引用以及如何使用它. 2. 方法引用的使用场景 我们先来看看方法引用的使用: new Ra ...

  2. Java SE 05 方法

    Java SE 05(方法) 方法可以用于定义可重用的代码以及组织和简化编码. 1.方法概述 为了解决代码重复编写的问题,可以将重复的代码提取出来放在一个{}中,并为这段代码起个名字.这样每次在调用该 ...

  3. java中的方法引用

    目录 简介 一,类::静态方法 二,对象::实例方法 三,类::实例方法 四,构造器引用,Class::new 五,数组引用,数组::new 简介 从JDK1.8开始,可以使用方法引用. 方法引用的操 ...

  4. 【java笔记】方法引用介绍和使用

    以一个例子说明 public interface FunInterface {void prints(String s); }public class Demo {public static void ...

  5. java一个引用多大_为什么Java 8为方法引用引入了一个新的“::”运算符?

    在Java 8中,使用::运算符完成引用. 例如 // Class that provides the functionality via it's static method public clas ...

  6. Java 8 中的方法引用,轻松减少代码量,提升可读性!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 1. 引言 Java8中最受广大开发中喜欢的变化之一是因为 ...

  7. java 方法引用_JAVA 8 方法引用 - Method References

    什么是方法引用 简单地说,就是一个Lambda表达式.在Java 8中,我们会使用Lambda表达式创建匿名方法,但是有时候,我们的Lambda表达式可能仅仅调用一个已存在的方法,而不做任何其它事,对 ...

  8. 十三、Java高级特性 Lambda表达式 | 接口组成更新 | 方法引用 | 函数式接口

    文章目录 十三.Java高级特性 1.Lambda表达式 1.1体验Lambda表达式[理解] 1.2Lambda表达式的标准格式[理解] 1.3Lambda表达式练习1[应用] 1.4Lambda表 ...

  9. Jdk1.8新特性(三)——方法引用::

    Lambda表达式可以用来创建匿名方法,有时候使用lambda表达式仅仅是调用一个已存在的方法: Arrays.sort(stringsArray,(s1,s2)->s1.compareToIg ...

最新文章

  1. Unity3D 材料
  2. 2021 年不可错过的 40 篇 AI 论文,你都读过吗?
  3. TestNg依赖详解(三)------灵活的文件配置依赖
  4. 安装hive出现的各种问题(这些问题出现在spark连接mysql的时候)
  5. 单片机C语言编程:.H文件与.C文件的关系!
  6. SQL Server系统存储过程
  7. 计算机图形学多边形填充代码_计算机图形学 Computer Graphics (第一周笔记及课件翻译)...
  8. Citespace、vosviewer 文献信息可视化分析
  9. 介绍几个能下载中英文双语字幕电影的网站
  10. 如何在windows xp下实现声音内录
  11. 分布式数据库TiDB在携程的实践
  12. Anchor-Free系列之CornerNet: Detecting Objects as Paired Keypoints
  13. 定期360评估系统优于年度绩效考核
  14. STM32智能门锁学习二,RFID刷卡解锁
  15. 各种艺术字、图片在线制作
  16. java 控制面板,Java9 控制面板
  17. “云原生”、“大数据”、“云计算”的结合——阿里云的云原生大数据计算服务MaxCompute
  18. Thinkpad t450s 加装ssd 记录
  19. centos7上安装kerberos附java使用kerberos案例
  20. Urbannav数据集/novatel_data/inspvax订阅

热门文章

  1. 全球变暖java_全球变暖 蓝桥杯
  2. ubuntu mysql自动备份_Ubuntu下mysql数据库自动备份脚本
  3. 项目当中套一个自己的小库的方式问题记录
  4. TRMF 辅助论文:最小二乘法复现TRMF
  5. Tableau实战系列浏览 Tableau 环境(二) -工作区域
  6. 实用的才是最好的,教你如何以MATLAB的方式实现高等应用数学问题(二)
  7. django权限系统实现步骤_Django权限机制的实现
  8. 4000+系统,10w+服务的立体式监控是如何炼成的?
  9. 水平分库分表的关键步骤以及可能遇到的问题
  10. 用最少的机器支撑万亿级访问,微博6年Redis优化历程