函数式接口】【Java基础】java8的函数式接口

2020-11-05 20:40发布

7条回答
豆豆
1楼 · 2020-11-06 10:19.采纳回答

JDK1.8版本中,提供了4种内置函数式接口, 为了在不同的场景下可以直接使用而不需要开发人员自己定义

1. 消费型接口:

   Consumer

      void accept(T t) : 对于T类型数据的处理方式

2. 供给型接口:

   Supplier

      T get(): 获取到T类型数据

3. 函数型接口:

   Function

      R apply(T) : 通过T类型参数, 获取到R类型数据结果

4. 断言型接口 :

   Predicate

       boolean test(T) : 提供一个T类型参数,判断出T类型参数是否符合规则和要求

函数式接口是一种设计思想的提供, 因为实际开发中, 不仅仅需要数据, 还需要对于数据的处理方式, 处理理念, 因此函数式接口将处理数据的方式封装起来使用

天天
2楼 · 2020-11-06 09:22

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,函数式接口可以被隐式转换为 lambda 表达式。


猜不到结尾
3楼 · 2020-11-06 09:42

2、接口:

接口中方法都默认是public 的,不能有方法体。

接口中的变量都常量,都是public static final 的,必须先赋值。

如果一个类实现了此接口,必须覆盖接口中的所有抽象方法。


小猪仔
4楼 · 2020-11-06 09:47
序号接口 & 描述
1BiConsumer

代表了一个接受两个输入参数的操作,并且不返回任何结果

2BiFunction

代表了一个接受两个输入参数的方法,并且返回一个结果

3BinaryOperator

代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果

4BiPredicate

代表了一个两个参数的boolean值方法

5BooleanSupplier

代表了boolean值结果的提供方

6Consumer

代表了接受一个输入参数并且无返回的操作

7DoubleBinaryOperator

代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。

8DoubleConsumer

代表一个接受double值参数的操作,并且不返回结果。

9DoubleFunction

代表接受一个double值参数的方法,并且返回结果

10DoublePredicate

代表一个拥有double值参数的boolean值方法

11DoubleSupplier

代表一个double值结构的提供方

12DoubleToIntFunction

接受一个double类型输入,返回一个int类型结果。

13DoubleToLongFunction

接受一个double类型输入,返回一个long类型结果

14DoubleUnaryOperator

接受一个参数同为类型double,返回值类型也为double 。

15Function

接受一个输入参数,返回一个结果。

16IntBinaryOperator

接受两个参数同为类型int,返回值类型也为int 。

17IntConsumer

接受一个int类型的输入参数,无返回值 。

18IntFunction

接受一个int类型输入参数,返回一个结果 。

19IntPredicate

:接受一个int输入参数,返回一个布尔值的结果。

20IntSupplier

无参数,返回一个int类型结果。

21IntToDoubleFunction

接受一个int类型输入,返回一个double类型结果 。

22IntToLongFunction

接受一个int类型输入,返回一个long类型结果。

23IntUnaryOperator

接受一个参数同为类型int,返回值类型也为int 。

24LongBinaryOperator

接受两个参数同为类型long,返回值类型也为long。

25LongConsumer

接受一个long类型的输入参数,无返回值。

26LongFunction

接受一个long类型输入参数,返回一个结果。

27LongPredicate

R接受一个long输入参数,返回一个布尔值类型结果。

28LongSupplier

无参数,返回一个结果long类型的值。

29LongToDoubleFunction

接受一个long类型输入,返回一个double类型结果。

30LongToIntFunction

接受一个long类型输入,返回一个int类型结果。

31LongUnaryOperator

接受一个参数同为类型long,返回值类型也为long。

32ObjDoubleConsumer

接受一个object类型和一个double类型的输入参数,无返回值。

33ObjIntConsumer

接受一个object类型和一个int类型的输入参数,无返回值。

34ObjLongConsumer

接受一个object类型和一个long类型的输入参数,无返回值。

35Predicate

接受一个输入参数,返回一个布尔值结果。

36Supplier

无参数,返回一个结果。

37ToDoubleBiFunction

接受两个输入参数,返回一个double类型结果

38ToDoubleFunction

接受一个输入参数,返回一个double类型结果

39ToIntBiFunction

接受两个输入参数,返回一个int类型结果。

40ToIntFunction

接受一个输入参数,返回一个int类型结果。

41ToLongBiFunction

接受两个输入参数,返回一个long类型结果。

42ToLongFunction

接受一个输入参数,返回一个long类型结果。

43UnaryOperator

接受一个参数为类型T,返回值类型也为T。


我的网名不再改
5楼 · 2020-11-08 14:28

引言

目前由于系统已经全面切换为JDK8,所以有必要系统的了解一下Java8的一些新特性,以便后续在日常工作中可以使用一些高级特性来提高编程效率。

因为Java8引入了函数式接口,在java.util.function包含了几大类函数式接口声明。这里第一篇主要研究一下Function相关的接口。

FunctionalInterface注解

Java8的新引入,包含函数式的设计,接口都有@FunctionalInterface的注解。就像这个注解的注释说明一样,它注解在接口层面,且注解的接口要有且仅有一个抽象方法。具体就是说,注解在Inteface上,且interface里只能有一个抽象方法,可以有default方法。因为从语义上来讲,一个函数式接口需要通过一个***逻辑上的***方法表达一个单一函数。那理解这个单一就很重要了,单一不是说限制你一个interface里只有一个抽象方法,单是多个方法的其他方法需要是继承自Object的public方法,或者你要想绕过,就自己实现default。函数式接口自己本身一定是只有一个抽象方法。同时,如果是Object类的public方法,也是不允许的。官方的说明翻译如下:

如果一个接口I,I有一组抽象方法集合M,且这些方法都不是Object类的public签名方法,那么如果存在一个M中的方法m,满足:

m的签名是所有M中方法签名的子签名。

m对于M中的每个方法都是返回类型可替换的。 此时,接口I是一个函数式接口。

怎么理解,看几个例子。

比如:你声明一个接口:

这会编译错,编译器会告诉你*no target method*。而如果加一个方法:

这就OK了,一个函数式接口声明好了。再加一个呢?

不ok,明确说了只有一个抽象方法嘛。但是如果换一种函数签名:

错误依旧,因为这个方法签名是Object类的public方法。而再改一下:

这就OK了。一个抽象方法,一个Object的public方法,相安无事。Object还有其他方法,clone方法试试会怎么样?

这又不行了,因为前面明确说了,要是Object的public方法,而clone是protected的。

所以总结一句话就是:

函数式接口,有且仅有一个抽象方法,Object的public方法除外。

因为Java本身支持多接口实现,你定义一个Class可以implements多个interface。所以这个限制也没什么影响,如果想约定一个函数式接口来统一,也可以做一些默认的实现来达到一个接口多个抽象方法的目的,比如下面这种做法:

一个普通接口NonFunc:

函数式接口Func:

实现的测试类:

函数式接口的一大特性就是可以被lambda表达式和函数引用表达式代替。也就是说声明这样的接口,是可以灵活的以方法来传参。看个例子:

上面例子列举了一个lambda模式和一个方法引用模式,这样就可以利用函数式编程强大的能力,将方法作为参数了。

另一个大的话题是针对上文的***逻辑上的方法***。所谓逻辑上,就是说当你出现函数式接口多重继承其他接口时,如果继承的多个接口有相同的方法签名,那么也是OK的。而这种相同签名的方法,也包括了泛型的情况,以下的声明中的Z接口,都是函数式接口。

但是要注意的是,这种泛型的支持,是因为函数式接口的官方声明规范里要求类型可替换和子签名,不是因为泛型擦除。

比如下面的例子就不是函数式接口:

最后,Java8里关于函数式接口的包是java.util.function,里面全部是函数式接口。主要包含几大类:Function、Predicate、Supplier、Consumer和*Operator(没有Operator接口,只有类似BinaryOperator这样的接口)。后面依次展开详细说明一下。

Function

关于Function接口,其接口声明是一个函数式接口,其抽象表达函数为

函数意为将参数T传递给一个函数,返回R。即$R=Function(T)$

其默认实现了3个default方法,分别是compose、andThen和identity,对应的函数表达为:compose对应$V=Function(ParamFunction(T))$,体现嵌套关系;andThen对应$V=ParamFunction(Function(T))$,转换了嵌套的顺序;还有identity对应了一个传递自身的函数调用对应$Function(T)=T$。从这里看出来,compose和andThen对于两个函数f和g来说,f.compose(g)等价于g.andThen(f)。看个例子:

高阶函数

只是普通的lambda表达式,其能力有限。我们会希望引入更强大的函数能力——高阶函数,可以定义任意同类计算的函数。

比如这个函数定义,参数是z,返回值是一个Function,这个Function本身又接受另一个参数y,返回z+y。于是我们可以根据这个函数,定义任意加法函数:

由于高阶函数接受一个函数作为参数,结果返回另一个函数,所以是典型的函数到函数的映射。

BiFunction提供了二元函数的一个接口声明,举例来说:

其输出结果将是:f(z)=x*y, when x=3,y=5, then f(z)=15。

二元函数没有compose能力,只是默认实现了andThen。

有了一元和二元函数,那么可以通过组合扩展出更多的函数可能。

Function接口相关的接口包括:

BiFunction :R apply(T t, U u);接受两个参数,返回一个值,代表一个二元函数;

DoubleFunction :R apply(double value);只处理double类型的一元函数;

IntFunction :R apply(int value);只处理int参数的一元函数;

LongFunction :R apply(long value);只处理long参数的一元函数;

ToDoubleFunction:double applyAsDouble(T value);返回double的一元函数;

ToDoubleBiFunction:double applyAsDouble(T t, U u);返回double的二元函数;

ToIntFunction:int applyAsInt(T value);返回int的一元函数;

ToIntBiFunction:int applyAsInt(T t, U u);返回int的二元函数;

ToLongFunction:long applyAsLong(T value);返回long的一元函数;

ToLongBiFunction:long applyAsLong(T t, U u);返回long的二元函数;

DoubleToIntFunction:int applyAsInt(double value);接受double返回int的一元函数;

DoubleToLongFunction:long applyAsLong(double value);接受double返回long的一元函数;

IntToDoubleFunction:double applyAsDouble(int value);接受int返回double的一元函数;

IntToLongFunction:long applyAsLong(int value);接受int返回long的一元函数;

LongToDoubleFunction:double applyAsDouble(long value);接受long返回double的一元函数;

LongToIntFunction:int applyAsInt(long value);接受long返回int的一元函数;

Operator

Operator其实就是Function,函数有时候也叫作算子。算子在Java8中接口描述更像是函数的补充,和上面的很多类型映射型函数类似。

算子Operator包括:UnaryOperator和BinaryOperator。分别对应单元算子和二元算子。

算子的接口声明如下:

二元算子的声明:

很明显,算子就是一个针对同类型输入输出的一个映射。在此接口下,只需声明一个泛型参数T即可。对应上面的例子:

例子里补充一点的是,BinaryOperator提供了两个默认的static快捷实现,帮助实现二元函数min(x,y)和max(x,y),使用时注意的是排序器可别传反了:)

其他的Operator接口:(不解释了)

LongUnaryOperator:long applyAsLong(long operand);

IntUnaryOperator:int applyAsInt(int operand);

DoubleUnaryOperator:double applyAsDouble(double operand);

DoubleBinaryOperator:double applyAsDouble(double left, double right);

IntBinaryOperator:int applyAsInt(int left, int right);

LongBinaryOperator:long applyAsLong(long left, long right);

Predicate

predicate是一个谓词函数,主要作为一个谓词演算推导真假值存在,其意义在于帮助开发一些返回bool值的Function。本质上也是一个单元函数接口,其抽象方法test接受一个泛型参数T,返回一个boolean值。等价于一个Function的boolean型返回值的子集。

其默认方法也封装了and、or和negate逻辑。写个小例子看看:

Predicate在Stream中有应用,Stream的filter方法就是接受Predicate作为入参的。这个具体在后面使用Stream的时候再分析深入。

其他Predicate接口:

BiPredicate:boolean test(T t, U u);接受两个参数的二元谓词

DoublePredicate:boolean test(double value);入参为double的谓词函数

IntPredicate:boolean test(int value);入参为int的谓词函数

LongPredicate:boolean test(long value);入参为long的谓词函数

Consumer

看名字就可以想到,这像谓词函数接口一样,也是一个Function接口的特殊表达——接受一个泛型参数,不需要返回值的函数接口。

这个接口声明太重要了,对于一些纯粹consume型的函数,没有Consumer的定义真无法被Function家族的函数接口表达。因为Function一定需要一个泛型参数作为返回值类型(当然不排除你使用Function来定义,但是一直返回一个无用的值)。比如下面的例子,如果没有Consumer,类似的行为使用Function表达就一定需要一个返回值。

其他Consumer接口:

BiConsumer:void accept(T t, U u);接受两个参数

DoubleConsumer:void accept(double value);接受一个double参数

IntConsumer:void accept(int value);接受一个int参数

LongConsumer:void accept(long value);接受一个long参数

ObjDoubleConsumer:void accept(T t, double value);接受一个泛型参数一个double参数

ObjIntConsumer:void accept(T t, int value);接受一个泛型参数一个int参数

ObjLongConsumer:void accept(T t, long value);接受一个泛型参数一个long参数

Supplier

最后说的是一个叫做Supplier的函数接口,其声明如下:

其简洁的声明,会让人以为不是函数。这个抽象方法的声明,同Consumer相反,是一个只声明了返回值,不需要参数的函数(这还叫函数?)。也就是说Supplier其实表达的不是从一个参数空间到结果空间的映射能力,而是表达一种生成能力,因为我们常见的场景中不止是要consume(Consumer)或者是简单的map(Function),还包括了new这个动作。而Supplier就表达了这种能力。

比如你要是返回一个常量,那可以使用类似的做法:

这保证supplier对象输出的一直是1。

如果是要利用构造函数的能力呢?就可以这样:

这样的输出可以看到,全部的对象都是new出来的。

这样的场景在Stream计算中会经常用到,具体在分析Java 8中Stream的时候再深入。

其他Supplier接口:

BooleanSupplier:boolean getAsBoolean();返回boolean

DoubleSupplier:double getAsDouble();返回double

IntSupplier:int getAsInt();返回int

LongSupplier:long getAsLong();返回long

总结

整个函数式接口的大概总结如下:


py大白
6楼 · 2020-11-30 16:56

JDK在1.8版本中,提供了4种内置函数式接口, 为了在不同的场景下可以直接使用而不需要开发人员自己定义

1. 消费型接口:

   Consumer

      void accept(T t) : 对于T类型数据的处理方式

2. 供给型接口:

   Supplier

      T get(): 获取到T类型数据

3. 函数型接口:

   Function

      R apply(T) : 通过T类型参数, 获取到R类型数据结果

4. 断言型接口 :

   Predicate

       boolean test(T) : 提供一个T类型参数,判断出T类型参数是否符合规则和要求

函数式接口是一种设计思想的提供, 因为实际开发中, 不仅仅需要数据, 还需要对于数据的处理方式, 处理理念, 因此函数式接口将处理数据的方式封装起来使用


相关问题推荐

    没有解决我的问题,去提问