资讯专栏INFORMATION COLUMN

Java 8方法引用使用指南

terro / 3439人阅读

摘要:方法引用众所周知,在中我们可以使用方法引用。为什么呢这是因为方法引用并非表达式或者函数接口。有关方法引用的使用方式,我们又向前迈进了一步。我们有一个工具类,可以让每个方法引用都转换为标准包中任意匹配的函数接口。

【编者按】本文作者为拥有15年 Java 开发经验的资深程序员 Per-Åke Minborg,主要介绍如何灵活地解析 Java 中的方法引用。文章系国内 ITOM 管理平台 OneAPM 编译呈现。

方法引用

众所周知,在Java 8中我们可以使用方法引用。譬如,在我们需要遍历流元素时,可以使用 String::isEmpty 来引用isEmpty方法。试看下面这段代码:

</>复制代码

  1. Stream.of("A", "", "B").filter(Stream::isEmpty).count();

运行的结果为1(因为在这个流中只有一个空元素)。但是,如果我们要过滤出非空字符串,我们得写成.filter(s -> !s.isEmpty())。这是一个Lambda表达式。显然,这儿有个讨厌的不对称想象。我们可以使用方法引用,但却不能用它的反式。我们可以写predicate.negate()却不能写Stream::isEmpty.negate()!Stream::isEmpty

为什么呢?这是因为方法引用并非Lambda表达式或者函数接口。不过,使用Java的类型推导可以将方法引用解析为一个或多个函数接口。上例中的String::isEmpty至少可以解析为:

</>复制代码

  1. Predicate
  2. Function

所以,我们要排除其他可能性,确定到底将方法引用转换为哪个函数接口。本文在一定程度上解决了该问题。文中的代码来自开源项目Speedment,它让数据库看起来像Java 8的流。

解析方法引用

其实,以静态方法为“管道”,可以部分地解决这个问题——该静态方法以一个方法引用为输入,以特定的函数接口为其返回。试考虑下面这个简短的静态方法:

</>复制代码

  1. public static Predicate as(Predicate predicate) {
  2. return predicate;
  3. }

现在,如果静态地导入这个方法,事实上,我们就能更简单地使用方法引用。如下例所示:

</>复制代码

  1. Stream.of("A", "", "B").filter(as(String::isEmpty).negate()).count();

这段代码返回的结果为2,即流中非空元素的数量。有关方法引用的使用方式,我们又向前迈进了一步。另一个好处是,这个解决方案让我们更轻松地编写predicates接口,例如:

</>复制代码

  1. .filter(as(String::isEmpty).negate().and("A"::equals))
解析所有方法引用

但是,现在仍有一个问题亟待解决。我们不能随随便便地创建一大堆静态as()函数,因为一个方法引用可能解析为多种as()方法,正如本文开头提到的那样。所以,一个更妙的解决方案,是把函数接口类型名添加至每个静态方法,这样我们就可以程序化地为每个函数接口转换方法选择一个特定的方法引用。我们有一个工具类,可以让每个方法引用都转换为Java标准包 `java.util.function中任意匹配的函数接口。

直接在GitHub下载最新版本

</>复制代码

  1. import java.util.function.*;
  2. /**
  3. *

@author Per Minborg
*/

class FunctionCastUtil {

</>复制代码

  1. public static BiConsumer asBiConsumer(BiConsumer biConsumer) {
  2. return biConsumer;
  3. }
  4. public static BiFunction asBiFunction(BiFunction biFunction) {
  5. return biFunction;
  6. }
  7. public static BinaryOperator asBinaryOperator(BinaryOperator binaryOperator) {
  8. return binaryOperator;
  9. }
  10. public static BiPredicate asBiPredicate(BiPredicate biPredicate) {
  11. return biPredicate;
  12. }
  13. public static BooleanSupplier asBooleanSupplier(BooleanSupplier booleanSupplier) {
  14. return booleanSupplier;
  15. }
  16. public static Consumer asConsumer(Consumer consumer) {
  17. return consumer;
  18. }
  19. public static DoubleBinaryOperator asDoubleBinaryOperator(DoubleBinaryOperator doubleBinaryOperator) {
  20. return doubleBinaryOperator;
  21. }
  22. public static DoubleConsumer asDoubleConsumer(DoubleConsumer doubleConsumer) {
  23. return doubleConsumer;
  24. }
  25. public static DoubleFunction asDoubleFunction(DoubleFunction doubleFunction) {
  26. return doubleFunction;
  27. }
  28. public static DoublePredicate asDoublePredicate(DoublePredicate doublePredicate) {
  29. return doublePredicate;
  30. }
  31. public static DoubleToIntFunction asDoubleToIntFunction(DoubleToIntFunction doubleToIntFunctiontem) {
  32. return doubleToIntFunctiontem;
  33. }
  34. public static DoubleToLongFunction asDoubleToLongFunction(DoubleToLongFunction doubleToLongFunction) {
  35. return doubleToLongFunction;
  36. }
  37. public static DoubleUnaryOperator asDoubleUnaryOperator(DoubleUnaryOperator doubleUnaryOperator) {
  38. return doubleUnaryOperator;
  39. }
  40. public static Function asFunction(Function function) {
  41. return function;
  42. }
  43. public static IntBinaryOperator asIntBinaryOperator(IntBinaryOperator intBinaryOperator) {
  44. return intBinaryOperator;
  45. }
  46. public static IntConsumer asIntConsumer(IntConsumer intConsumer) {
  47. return intConsumer;
  48. }
  49. public static IntFunction asIntFunction(IntFunction intFunction) {
  50. return intFunction;
  51. }
  52. public static IntPredicate asIntPredicate(IntPredicate intPredicate) {
  53. return intPredicate;
  54. }
  55. public static IntSupplier asIntSupplier(IntSupplier intSupplier) {
  56. return intSupplier;
  57. }
  58. public static IntToDoubleFunction asIntToDoubleFunction(IntToDoubleFunction intToDoubleFunction) {
  59. return intToDoubleFunction;
  60. }
  61. public static IntToLongFunction asIntToLongFunction(IntToLongFunction intToLongFunction) {
  62. return intToLongFunction;
  63. }
  64. public static IntUnaryOperator asIntUnaryOperator(IntUnaryOperator intUnaryOperator) {
  65. return intUnaryOperator;
  66. }
  67. public static LongBinaryOperator asLongBinaryOperator(LongBinaryOperator longBinaryOperator) {
  68. return longBinaryOperator;
  69. }
  70. public static LongConsumer asLongConsumer(LongConsumer longConsumer) {
  71. return longConsumer;
  72. }
  73. public static LongFunction asLongFunction(LongFunction longFunction) {
  74. return longFunction;
  75. }
  76. public static LongPredicate asLongPredicate(LongPredicate longPredicate) {
  77. return longPredicate;
  78. }
  79. public static LongSupplier asLongSupplier(LongSupplier longSupplier) {
  80. return longSupplier;
  81. }
  82. public static LongToDoubleFunction asLongToDoubleFunction(LongToDoubleFunction longToDoubleFunction) {
  83. return longToDoubleFunction;
  84. }
  85. public static LongToIntFunction asLongToIntFunction(LongToIntFunction longToIntFunction) {
  86. return longToIntFunction;
  87. }
  88. public static LongUnaryOperator asLongUnaryOperator(LongUnaryOperator longUnaryOperator) {
  89. return longUnaryOperator;
  90. }
  91. public static ObjDoubleConsumer asObjDoubleConsumer(ObjDoubleConsumer objDoubleConsumer) {
  92. return objDoubleConsumer;
  93. }
  94. public static ObjIntConsumer asObjIntConsumer(ObjIntConsumer objIntConsumer) {
  95. return objIntConsumer;
  96. }
  97. public static ObjLongConsumer asObjLongConsumer(ObjLongConsumer objLongConsumer) {
  98. return objLongConsumer;
  99. }
  100. public static Predicate asPredicate(Predicate predicate) {
  101. return predicate;
  102. }
  103. public static Supplier asSupplier(Supplier supplier) {
  104. return supplier;
  105. }
  106. public static ToDoubleBiFunction asToDoubleBiFunction(ToDoubleBiFunction toDoubleBiFunction) {
  107. return toDoubleBiFunction;
  108. }
  109. public static ToDoubleFunction asToDoubleFunction(ToDoubleFunction toDoubleFunction) {
  110. return toDoubleFunction;
  111. }
  112. public static ToIntBiFunction asToIntBiFunction(ToIntBiFunction toIntBiFunction) {
  113. return toIntBiFunction;
  114. }
  115. public static ToIntFunction asToIntFunction(ToIntFunction ioIntFunction) {
  116. return ioIntFunction;
  117. }
  118. public static ToLongBiFunction asToLongBiFunction(ToLongBiFunction toLongBiFunction) {
  119. return toLongBiFunction;
  120. }
  121. public static ToLongFunction asToLongFunction(ToLongFunction toLongFunction) {
  122. return toLongFunction;
  123. }
  124. public static UnaryOperator asUnaryOperator(UnaryOperator unaryOperator) {
  125. return unaryOperator;
  126. }
  127. private FunctionCastUtil() {
  128. }

}

在静态导入了相关方法之后,我们就可以这样写:

</>复制代码

  1. Stream.of("A", "", "B").filter(asPredicate(String::isEmpty).negate()).count();
一个更好的解决方案

如果函数接口本身就包含一个接收方法引用并将其转换为某类函数接口的静态方法,那就更好了。举例来说,标准的Java Predicated函数接口就会变成这样:

</>复制代码

  1. @FunctionalInterface
  2. public interface Predicate {
  3. boolean test(T t);
  4. default Predicate and(Predicate other) {...}
  5. default Predicate negate() {...}
  6. default Predicate or(Predicate other) {...}
  7. static Predicate isEqual(Object targetRef) {...}
  8. // New proposed support method to return a
  9. // Predicate view of a Functional Reference
  10. public static Predicate of(Predicate predicate) {
  11. return predicate;
  12. }
  13. }

因此,我们可以这样写:

</>复制代码

  1. Stream.of("A", "", "B").filter(Predicate.of(String::isEmpty).negate()).count();

笔者觉得这样看起来好极了!

快联系离你最近的Open JDK开发人员,提出你的修改建议吧!

OneAPM 能为您提供端到端的 Java 应用性能解决方案,我们支持所有常见的 Java 框架及应用服务器,助您快速发现系统瓶颈,定位异常根本原因。分钟级部署,即刻体验,Java 监控从来没有如此简单。想阅读更多技术文章,请访问 OneAPM 官方技术博客。

本文转自 OneAPM 官方博客

原帖地址:https://dzone.com/articles/put-your-java-8-method-references-to-work

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/65913.html

相关文章

  • Java 8方法引用和Lambda表达式

    摘要:方法引用在之前只能进行值传递,方法是不能传递的。首先方法接受了一个类型的对象,方法是获取所有的文件,是用来存储筛选之后的元素,循环所有获得到的文件数组,然后调用中的方法来进行条件筛选,放入后返回。 方法引用: 在Java 8之前只能进行值传递,方法是不能传递的。如果你想调用一个方法你必须先获取到它所在的类的实例,然后再通过实例去调用这个方法,但是Java 8新增了方法引用这个新特性可以...

    legendmohe 评论0 收藏0
  • Java问题汇总,持续更新到GitHub

    摘要:目录介绍问题汇总具体问题好消息博客笔记大汇总年月到至今,包括基础及深入知识点,技术博客,学习笔记等等,还包括平时开发中遇到的汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善开源的文件是格式的同时也开源了生活博客,从年 目录介绍 00.Java问题汇总 01.具体问题 好消息 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技...

    beita 评论0 收藏0
  • 聊聊 Java8 以后各个版本的新特性

    摘要:于是抽时间看了看以后各个版本的特性,做了一个总结。年和公开版本发布,取名为。此后对应版本就是,。发布,是一个重大版本更新。在此之后,就是每六个月发布一次新版本。以上和参考资料聊了一些关于的历史,下面我们看看各个版本有那些新特性。 【这是 ZY 第 11 篇原创技术文章】 某天在网上闲逛,突然看到有篇介绍 Java 11 新特性的文章,顿时心里一惊,毕竟我对于 Java 的版本认识...

    K_B_Z 评论0 收藏0
  • Java编程思想》笔记2.一切都是对象

    摘要:方法的基本组成包括名称参数返回值方法体方法名和参数列表唯一的标识出某个方法。如果返回的类型是,则的作用仅是退出方法否则必须返回正确的返回值包名名字可见性约定以域名反转作为包名,用来划分子目录,并且全部小写。 点击进入我的博客 2.1用引用操纵对象 尽管一切都看作对象,但操纵的标识符实际上是对象的一个引用。 String s; // s是一个String类型的引用, 并没有任何对象与其...

    taohonghui 评论0 收藏0
  • Java 8 Lambda 表达式详解

    摘要:表达式简介表达式是一个匿名函数对于而言并不很准确,但这里我们不纠结这个问题。如果表达式的正文有一条以上的语句必须包含在大括号代码块中,且表达式的返回值类型要与匿名函数的返回类型相同。 版权声明:本文由吴仙杰创作整理,转载请注明出处:https://segmentfault.com/a/1190000009186509 1. 引言 在 Java 8 以前,若我们想要把某些功能传递给某些方...

    haoguo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<