如何更好的使用Java8中方法引用详解

所属分类: 软件编程 / java 阅读数: 21
收藏 0 赞 0 分享

前言

方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。

当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些。方法引用是一种更简洁易懂的Lambda表达式。

注意:方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。

在Java8中,使用方法引用非常简单,如String::isEmpty,但无法使用它否定的方法引用。本文内容即如何解决此问题使得我们能够更加全面地使用方法引用。

首先看一个使用方法引用的例子:

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

上面代码的输出为1,即空字符串的数目。如果我们想要获取非空字符串的数目,就不能直接使用方法引用了。

Stream.of("A", "", "B").filter(s -> !s.isEmpty()).count()

Java8中的Predicate,有predicate.negate()可以转换为断言的否定形式,但String::isEmpty却无法这么做(String::isEmpty.negate()或者!String::isEmpty )。因为方法引用并不是一个lambda或者函数接口,它能够被解析为一个或者多个函数接口。如,String::isEmpty至少可以被解析如下:

Predicate<String>
Function<String, Boolean>

为了解决上述的问题,我们可以通过某种机制显式地将方法引用转换为一个函数接口:

public static <T> Predicate<T> as(Predicate<T> predicate) {
 return predicate;
}

通过使用一个静态方法,接受方法引用参数,返回一个函数接口,即可实现方法引用到函数接口的转换。接着,我们就可以使用方法引用来实现上面例子中的获取非空字符串的数目。

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

进一步还能使用各种组合的Predicate。

.filter(as(String::isEmpty).negate().and("A"::equals))

由于一个方法引用可能会被解析为多种函数接口,因此如果我们实现很多参数不同的as方法,那么很容易造成混淆。更好的方式则是在方法名中加入函数参数的类型来区分。

import java.util.function.*;

public class FunctionCastUtil {
 public static <T, U> BiConsumer<T, U> asBiConsumer(BiConsumer<T, U> biConsumer) {
 return biConsumer;
 }
 public static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> biFunction) {
 return biFunction;
 }
 public static <T> BinaryOperator<T> asBinaryOperator(BinaryOperator<T> binaryOperator) {
 return binaryOperator;
 }
 public static <T, U> BiPredicate<T, U> asBiPredicate(BiPredicate<T, U> biPredicate) {
 return biPredicate;
 }
 public static BooleanSupplier asBooleanSupplier(BooleanSupplier booleanSupplier) {
 return booleanSupplier;
 }
 public static <T> Consumer<T> asConsumer(Consumer<T> consumer) {
 return consumer;
 }
 public static DoubleBinaryOperator asDoubleBinaryOperator(DoubleBinaryOperator doubleBinaryOperator) {
 return doubleBinaryOperator;
 }
 public static DoubleConsumer asDoubleConsumer(DoubleConsumer doubleConsumer) {
 return doubleConsumer;
 }
 public static <R> DoubleFunction<R> asDoubleFunction(DoubleFunction<R> doubleFunction) {
 return doubleFunction;
 }
 public static DoublePredicate asDoublePredicate(DoublePredicate doublePredicate) {
 return doublePredicate;
 }
 public static DoubleToIntFunction asDoubleToIntFunction(DoubleToIntFunction doubleToIntFunctiontem) {
 return doubleToIntFunctiontem;
 }
 public static DoubleToLongFunction asDoubleToLongFunction(DoubleToLongFunction doubleToLongFunction) {
 return doubleToLongFunction;
 }
 public static DoubleUnaryOperator asDoubleUnaryOperator(DoubleUnaryOperator doubleUnaryOperator) {
 return doubleUnaryOperator;
 }
 public static <T, R> Function<T, R> asFunction(Function<T, R> function) {
 return function;
 }
 public static IntBinaryOperator asIntBinaryOperator(IntBinaryOperator intBinaryOperator) {
 return intBinaryOperator;
 }
 public static IntConsumer asIntConsumer(IntConsumer intConsumer) {
 return intConsumer;
 }
 public static <R> IntFunction<R> asIntFunction(IntFunction<R> intFunction) {
 return intFunction;
 }
 public static IntPredicate asIntPredicate(IntPredicate intPredicate) {
 return intPredicate;
 }
 public static IntSupplier asIntSupplier(IntSupplier intSupplier) {
 return intSupplier;
 }
 public static IntToDoubleFunction asIntToDoubleFunction(IntToDoubleFunction intToDoubleFunction) {
 return intToDoubleFunction;
 }
 public static IntToLongFunction asIntToLongFunction(IntToLongFunction intToLongFunction) {
 return intToLongFunction;
 }
 public static IntUnaryOperator asIntUnaryOperator(IntUnaryOperator intUnaryOperator) {
 return intUnaryOperator;
 }
 public static LongBinaryOperator asLongBinaryOperator(LongBinaryOperator longBinaryOperator) {
 return longBinaryOperator;
 }
 public static LongConsumer asLongConsumer(LongConsumer longConsumer) {
 return longConsumer;
 }
 public static <R> LongFunction<R> asLongFunction(LongFunction<R> longFunction) {
 return longFunction;
 }
 public static LongPredicate asLongPredicate(LongPredicate longPredicate) {
 return longPredicate;
 }
 public static <T> LongSupplier asLongSupplier(LongSupplier longSupplier) {
 return longSupplier;
 }
 public static LongToDoubleFunction asLongToDoubleFunction(LongToDoubleFunction longToDoubleFunction) {
 return longToDoubleFunction;
 }
 public static LongToIntFunction asLongToIntFunction(LongToIntFunction longToIntFunction) {
 return longToIntFunction;
 }
 public static LongUnaryOperator asLongUnaryOperator(LongUnaryOperator longUnaryOperator) {
 return longUnaryOperator;
 }
 public static <T> ObjDoubleConsumer<T> asObjDoubleConsumer(ObjDoubleConsumer<T> objDoubleConsumer) {
 return objDoubleConsumer;
 }
 public static <T> ObjIntConsumer<T> asObjIntConsumer(ObjIntConsumer<T> objIntConsumer) {
 return objIntConsumer;
 }
 public static <T> ObjLongConsumer<T> asObjLongConsumer(ObjLongConsumer<T> objLongConsumer) {
 return objLongConsumer;
 }
 public static <T> Predicate<T> asPredicate(Predicate<T> predicate) {
 return predicate;
 }
 public static <T> Supplier<T> asSupplier(Supplier<T> supplier) {
 return supplier;
 }
 public static <T, U> ToDoubleBiFunction<T, U> asToDoubleBiFunction(ToDoubleBiFunction<T, U> toDoubleBiFunction) {
 return toDoubleBiFunction;
 }
 public static <T> ToDoubleFunction<T> asToDoubleFunction(ToDoubleFunction<T> toDoubleFunction) {
 return toDoubleFunction;
 }
 public static <T, U> ToIntBiFunction<T, U> asToIntBiFunction(ToIntBiFunction<T, U> toIntBiFunction) {
 return toIntBiFunction;
 }
 public static <T> ToIntFunction<T> asToIntFunction(ToIntFunction<T> ioIntFunction) {
 return ioIntFunction;
 }
 public static <T, U> ToLongBiFunction<T, U> asToLongBiFunction(ToLongBiFunction<T, U> toLongBiFunction) {
 return toLongBiFunction;
 }
 public static <T> ToLongFunction<T> asToLongFunction(ToLongFunction<T> toLongFunction) {
 return toLongFunction;
 }
 public static <T> UnaryOperator<T> asUnaryOperator(UnaryOperator<T> unaryOperator) {
 return unaryOperator;
 }
 private FunctionCastUtil() {
 }
}

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

英文原文:https://dzone.com/articles/put-your-java-8-method-references-to-work

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

更多精彩内容其他人还在看

Java的面向对象编程基本概念学习笔记整理

这篇文章主要介绍了Java的面向对象编程基本概念学习笔记整理,包括类与方法以及多态等支持面向对象语言中的重要特点,需要的朋友可以参考下
收藏 0 赞 0 分享

Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法

这篇文章主要介绍了Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法 的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

基于Java实现杨辉三角 LeetCode Pascal's Triangle

这篇文章主要介绍了基于Java实现杨辉三角 LeetCode Pascal's Triangle的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Java中Spring获取bean方法小结

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中获取Spring配置的bean呢?下面通过本文给大家介绍Java中Spring获取bean方法小结,对spring获取bean方法相关知识感兴趣的朋友一起学习吧
收藏 0 赞 0 分享

如何计算Java对象占用了多少空间?

在Java中没有sizeof运算符,所以没办法知道一个对象到底占用了多大的空间,但是在分配对象的时候会有一些基本的规则,我们根据这些规则大致能判断出来对象大小,需要的朋友可以参考下
收藏 0 赞 0 分享

剖析Java中的事件处理与异常处理机制

这篇文章主要介绍了Java中的事件处理与异常处理机制,讲解Java是如何对事件或者异常作出响应以及定义异常的一些方法,需要的朋友可以参考下
收藏 0 赞 0 分享

详解Java的Struts2框架的结构及其数据转移方式

这篇文章主要介绍了详解Java的Struts2框架的结构及其数据转移方式,Struts框架是Java的SSH三大web开发框架之一,需要的朋友可以参考下
收藏 0 赞 0 分享

Java封装好的mail包发送电子邮件的类

本文给大家分享了2个java封装好的mail包发送电子邮件的类,并附上使用方法,小伙伴们可以根据自己的需求自由选择。
收藏 0 赞 0 分享

在Java的Struts中判断是否调用AJAX及用拦截器对其优化

这篇文章主要介绍了在Java的Struts中判断是否调用AJAX及用拦截器对其优化的方法,Struts框架是Java的SSH三大web开发框架之一,需要的朋友可以参考下
收藏 0 赞 0 分享

java多线程Future和Callable类示例分享

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。今天我们就来研究下Future和Callab
收藏 0 赞 0 分享
查看更多