博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java8 函数接口
阅读量:4879 次
发布时间:2019-06-11

本文共 3062 字,大约阅读时间需要 10 分钟。

最近在做团队代码 code review 的时候发现了有人使用了 @FunctionalInterface 注解。我对这个注解不是很熟悉,基本上没用过。于是我就问对应的开发人员,给我讲一讲这个注解的用法,为什么要用这个注解?他讲的不太全,于是我就查询了一些资料,分享给大家!

在讲 @FunctionalInterface 之前,我们先熟悉一下,什么是函数式接口(Functional Interface)?

函数式接口(Functional Interface)

函数式接口(Functional Interface)是 Java 8对一类特殊类型的接口的称呼。 这类接口只定义了唯一的抽象方法的接口(除了隐含的Object对象的公共方法), 因此最开始也就做SAM类型的接口(Single Abstract Method)。

说白了,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个非 Object 对象的公共方法的抽象方法,可以有多个静态方法和默认方法。

上面说的是概念,如果你还没看懂,没关系,我们继续通过下面的几个例子,我相信你就会明白。

JDK 8之前已有的函数式接口

JDK 8之前已有的 JDK 中提供的支持函数式编程的函数式接口。

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.security.PrivilegedAction
  • java.util.Comparator
  • java.io.FileFilter
  • java.nio.file.PathMatcher
  • java.lang.reflect.InvocationHandler
  • java.beans.PropertyChangeListener
  • java.awt.event.ActionListener
  • javax.swing.event.ChangeListener

Java8 中新定义的函数式接口

Java8 中有一个 java.util.function 包。其中定义了几组类型的函数式接口以及针对基本数据类型的子接口。

  • Predicate:传入一个参数,返回一个bool结果, 方法为boolean test(T t)
  • Consumer:传入一个参数,无返回值,纯消费。 方法为void accept(T t)
  • Function:传入一个参数,返回一个结果,方法为R apply(T t)
  • Supplier:无参数传入,返回一个结果,方法为T get()
  • UnaryOperator:一元操作符, 继承Function,传入参数的类型和返回类型相同。
  • BinaryOperator:二元操作符, 传入的两个参数的类型和返回类型相同, 继承 BiFunction

下面我们来看一个案例。

1
2
3
4
@FunctionalInterface
public
interface
XttblogService {
    
void
sayMessage(String message);
}

那么我们现在就可以使用 Lambda 表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):

1
XttblogService xttblogService = message -> System.out.println(
"Hello "
+ message);

@FunctionalInterface 注解的接口,只能有一个 public 接口。

@FunctionalInterface

如果定义了两个,就会报错。

但是我们可以定义多个默认方法。因为默认方法不是抽象方法,其有一个默认实现,所以是符合函数式接口的定义的。

1
2
3
4
5
6
7
8
9
@FunctionalInterface
public
interface
XttblogService{
    
void
sayMessage(String message);
    
default
void
doSomeMoreWork1(){
        
// 业余草:www.xttblog.com
    
}
    
default
void
doSomeMoreWork2(){
    
}
}

除此之外,我们还可以定义多个静态方法。

1
2
3
4
5
6
7
8
9
10
@FunctionalInterface
public
interface
XttblogService {
    
void
sayMessage(String message);
    
static
void
printHello(){
        
System.out.println(
"Hello"
);
    
}
    
static
void
xttblogHello(){
        
System.out.println(
"Xttblog Hello"
);
    
}
}

函数式接口里允许定义默认方法和静态方法,上面的两种写法都不会报错。

另外,函数式接口里还允许定义 java.lang.Object 里的 public 方法。

函数式接口里是可以包含 Object 里的 public 方法,这些方法对于函数式接口来说,不被当成是抽象方法(虽然它们是抽象方法);因为任何一个函数式接口的实现,默认都继承了 Object 类,包含了来自 java.lang.Object 里对这些抽象方法的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
@FunctionalInterface
public
interface
XttblogService  {
    
void
sayMessage(String message);
 
    
@Override
    
boolean
equals(Object obj);
 
    
@Override
    
String toString();
 
    
@Override
    
int
hashCode();
}

我们常用的一些接口 Callable、Runnable、Comparator 等在 JDK8 中都添加了 @FunctionalInterface 注解。

那么 Java 中为什么需要 @FunctionalInterface 注解呢?

没有这个注解,我们也可以实现 Lambda 表达式。

但是 Java 推出 @FunctionalInterface 注解的原因是在 Java Lambda 的实现中,开发组不想再为 Lambda 表达式单独定义一种特殊的 Structural 函数类型,称之为箭头类型(arrow type),依然想采用 Java 既有的类型系统(class, interface, method等)。增加一个结构化的函数类型会增加函数类型的复杂性,破坏既有的 Java 类型,并对成千上万的 Java 类库造成严重的影响。权衡利弊,因此最终还是利用 SAM 接口作为 Lambda 表达式的目标类型。

JDK 中已有的一些接口本身就是函数式接口,如 Runnable。JDK 8 中又增加了 java.util.function 包,提供了常用的函数式接口。

函数式接口代表的一种契约,一种对某个特定函数类型的契约。在它出现的地方,实际期望一个符合契约要求的函数。Lambda 表达式不能脱离上下文而存在,它必须要有一个明确的目标类型,而这个目标类型就是某个函数式接口。

 

转载于:https://www.cnblogs.com/vana/p/11016349.html

你可能感兴趣的文章
jsp/post中文乱码问题
查看>>
C# 插入或删除word分页符
查看>>
数据库数据的查询----连接查询
查看>>
找不到可安装的ISAM ,asp.net读取数据丢失,解决的一列里有字符与数字的
查看>>
Java学习笔记三(对象的基本思想一)
查看>>
Java程序(文件操作)
查看>>
KMP算法 最小循环节 最大重复次数
查看>>
Proving Equivalences (强连通,缩点)
查看>>
Period (KMP算法 最小循环节 最大重复次数)
查看>>
sgu 103. Traffic Lights
查看>>
poj 3621 Sightseeing Cows
查看>>
hdu 3666 THE MATRIX PROBLEM
查看>>
TopCoder SRM 176 Deranged
查看>>
java 内存模型
查看>>
Javascript中数组与字典(即map)的使用
查看>>
C++不完整的类型
查看>>
memcached(十三)注意事项
查看>>
ITerms2在mac系统下的安装和配色,并和go2shell关联
查看>>
nginx常见面试题1
查看>>
小白用shiro(1)
查看>>