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

前言

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

当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

总结

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

(0)

相关推荐

  • 30分钟入门Java8之方法引用学习

    前言 之前两篇文章分别介绍了Java8的lambda表达式和默认方法和静态接口方法.今天我们继续学习Java8的新语言特性--方法引用(Method References). 在学习lambda表达式之后,我们通常使用lambda表达式来创建匿名方法.然而,有时候我们仅仅是调用了一个已存在的方法.如下: Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2)); 在Java8中,我们可以直接通过方法引用来简写lambda表达式中已

  • Java 8新特性方法引用详细介绍

    Java 8新特性方法引用 对于引用来说我们一般都是用在对象,而对象引用的特点是:不同的引用对象可以操作同一块内容! Java 8的方法引用定义了四种格式: 引用静态方法     ClassName :: staticMethodName 引用对象方法:  Object:: methodName 引用特定类型方法: ClassName :: methodName 引用构造方法: ClassName  :: new  静态方法引用示例 /** * 静态方法引用 * @param <P> 引用方法

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

    前言 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法.方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文.计算时,方法引用会创建函数式接口的一个实例. 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些.方法引用是一种更简洁易懂的Lambda表达式. 注意:方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::". 在Java8中,使用方法引用非常简单,如String

  • Java8新特性:Lambda表达式之方法引用详解

    1.方法引用简述 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法.方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文.计算时,方法引用会创建函数式接口的一个实例. 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些.方法引用是一种更简洁易懂的Lambda表达式. Lambda表达式全文详情地址:http://blog.csdn.net/sun_promise/article/details/

  • Java8中方法引用的使用详解

    1. 引言 Java8中最受广大开发中喜欢的变化之一是因为引入了 lambda 表达式,因为这些表达式允许我们放弃匿名类,从而大大减少了样板代码,并提高了可读性. 方法引用是lambda表达式的一种特殊类型.它们通常通过引用现有方法来创建简单的lambda表达式. 方法引用包括以下四种类型: 静态方法 特定对象的实例方法 特定类型的任意对象的实例方法 构造方法 在本篇文章中,我们将探讨Java中的方法引用. 2. 引用静态方法 We'll begin with a very simple exa

  • 使用java8的方法引用替换硬编码的示例代码

    背景 想必大家在项目中都有遇到把一个列表的多个字段累加求和的情况,也就是一个列表的总计.有的童鞋问,这个不是给前端做的吗?后端不是只需要把列表返回就行了嘛...没错,我也是这样想的,但是在一场和前端的撕逼大战中败下阵来之后,这个东西就落在我身上了.当时由于工期原因,时间比较紧,也就不考虑效率和易用性了,只是满足当时的需求,就随便写了个方法统计求和.目前稍微闲下来了,就把原来的代码优化下.我们先来看一下原来的代码... 原代码 工具类 import org.apache.commons.lang3

  • Vue中使用方法、计算属性或观察者的方法实例详解

    熟悉 Vue 的都知道 方法methods.计算属性computed.观察者watcher 在 Vue 中有着非常重要的作用,有些时候我们实现一个功能的时候可以使用它们中任何一个都是可以的,但是它们之间又存在一些不同之处,每一个都有一些适合自己的场景,我们要想知道合适的场景,肯定先对它们有一个清楚的了解,先看一个小例子. <div id="app"> <input v-model="firstName" type="text"&

  • JavaScript中十种一步拷贝数组的方法实例详解

    JavaScript中我们经常会遇到拷贝数组的场景,但是都有哪些方式能够来实现呢,我们不妨来梳理一下. 1.扩展运算符(浅拷贝) 自从ES6出现以来,这已经成为最流行的方法.它是一个很简单的语法,但是当你在使用类似于React和Redux这类库时,你会发现它是非常非常有用的. numbers = [1, 2, 3]; numbersCopy = [...numbers]; 这个方法不能有效的拷贝多维数组.数组/对象值的拷贝是通过引用而不是值复制. // numbersCopy.push(4);

  • Java8 Comparator排序方法实例详解

    这篇文章主要介绍了Java8 Comparator排序方法实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Java8 中 Comparator 接口提供了一些静态方法,可以方便于我们进行排序操作,下面通过例子讲解下如何使用 对整数列表排序(升序) List<Integer> list = Arrays.asList(1, 4, 2, 6, 2, 8); list.sort(Comparator.naturalOrder()); Sys

  • js中getBoundingClientRect( )方法案例详解

    一.getBoundingClientRect() 解析 getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置. 语法 rectObject = object.getBoundingClientRect(); 值 rectObject.top:元素上边到视窗上边的距离; rectObject.right:元素右边到视窗左边的距离; rectObject.bottom:元素下边到视窗上边的距离; rectObject.left:元素左边到视窗左边的距离; rect

  • Java中Thread类详解及常用的方法

    目录 一.Thread 的常见构造方法 二.Thread 的常见属性 三.创建线程 四.中断线程 五.线程等待 六.获取线程引用 七.线程休眠 八.线程状态 总结 一.Thread 的常见构造方法 方法 说明 Thread() 创建线程对象 Thread(Runnable target) 使用 Runnable 对象创建线程对象 Thread(String name) 创建线程对象并命名 Thread(Runnable target,String name) 使用 Runnable 对象创建线程

  • MongoDB中aggregate()方法实例详解

    目录 前言 1,了解aggergate()方法 2,实现聚合表达式运算符 总结 前言 MongoDB的一个很大的好处是能够使用MapReduce来吧数据库查询的结果简化成一个与原来的集合完全不同的结构.MapReduce把一个数据库查询的值映射为一个完全不同的形式,然后简化结果,使它们的可用性更好. MongoDB有一个MapReduce框架,它也允许你使用聚合来简化吧一个MapReduce操作传输到另一个MapReduce操作的一系列过程.有了MapReduce和聚合,可以用数据生成一些不平凡

随机推荐