简介

java 8引入了lambda表达式,lambda表达式实际上表示的就是一个匿名的function。

在java 8之前,如果需要使用到匿名function需要new一个类的实现,但是有了lambda表达式之后,一切都变的非常简介。

我们看一个之前讲线程池的时候的一个例子:

//ExecutorService using class
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Runnable() {
@Override
public void run() {
log.info("new runnable");
}
});

executorService.submit需要接收一个Runnable类,上面的例子中我们new了一个Runnable类,并实现了它的run()方法。

上面的例子如果用lambda表达式来重写,则如下所示:

//ExecutorService using lambda
executorService.submit(()->log.info("new runnable"));

看起是不是很简单,使用lambda表达式就可以省略匿名类的构造,并且可读性更强。

那么是不是所有的匿名类都可以用lambda表达式来重构呢?也不是。

我们看下Runnable类有什么特点:

@FunctionalInterface
public interface Runnable

Runnable类上面有一个@FunctionalInterface注解。这个注解就是我们今天要讲到的Functional Interface。

Functional Interface

Functional Interface是指带有 @FunctionalInterface 注解的interface。它的特点是其中只有一个子类必须要实现的abstract方法。如果abstract方法前面带有default关键字,则不做计算。

其实这个也很好理解,因为Functional Interface改写成为lambda表达式之后,并没有指定实现的哪个方法,如果有多个方法需要实现的话,就会有问题。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

Functional Interface一般都在java.util.function包中。

根据要实现的方法参数和返回值的不同,Functional Interface可以分为很多种,下面我们分别来介绍。

Function:一个参数一个返回值

Function接口定义了一个方法,接收一个参数,返回一个参数。

@FunctionalInterface
public interface Function<T, R> { /**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);

一般我们在对集合类进行处理的时候,会用到Function。

Map<String, Integer> nameMap = new HashMap<>();
Integer value = nameMap.computeIfAbsent("name", s -> s.length());

上面的例子中我们调用了map的computeIfAbsent方法,传入一个Function。

上面的例子还可以改写成更短的:

Integer value1 = nameMap.computeIfAbsent("name", String::length);

Function没有指明参数和返回值的类型,如果需要传入特定的参数,则可以使用IntFunction, LongFunction, DoubleFunction:

@FunctionalInterface
public interface IntFunction<R> { /**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
R apply(int value);
}

如果需要返回特定的参数,则可以使用ToIntFunction, ToLongFunction, ToDoubleFunction:

@FunctionalInterface
public interface ToDoubleFunction<T> { /**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
double applyAsDouble(T value);
}

如果要同时指定参数和返回值,则可以使用DoubleToIntFunction, DoubleToLongFunction, IntToDoubleFunction, IntToLongFunction, LongToIntFunction, LongToDoubleFunction:

@FunctionalInterface
public interface LongToIntFunction { /**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
int applyAsInt(long value);
}

BiFunction:接收两个参数,一个返回值

如果需要接受两个参数,一个返回值的话,可以使用BiFunction:BiFunction, ToDoubleBiFunction, ToIntBiFunction, ToLongBiFunction等。

@FunctionalInterface
public interface BiFunction<T, U, R> { /**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
*/
R apply(T t, U u);

我们看一个BiFunction的例子:

//BiFunction
Map<String, Integer> salaries = new HashMap<>();
salaries.put("alice", 100);
salaries.put("jack", 200);
salaries.put("mark", 300); salaries.replaceAll((name, oldValue) ->
name.equals("alice") ? oldValue : oldValue + 200);

Supplier:无参的Function

如果什么参数都不需要,则可以使用Supplier:

@FunctionalInterface
public interface Supplier<T> { /**
* Gets a result.
*
* @return a result
*/
T get();
}

Consumer:接收一个参数,不返回值

Consumer接收一个参数,但是不返回任何值,我们看下Consumer的定义:

@FunctionalInterface
public interface Consumer<T> { /**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);

看一个Consumer的具体应用:

//Consumer
nameMap.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));

Predicate:接收一个参数,返回boolean

Predicate接收一个参数,返回boolean值:

@FunctionalInterface
public interface Predicate<T> { /**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);

如果用在集合类的过滤上面那是极好的:

//Predicate
List<String> names = Arrays.asList("A", "B", "C", "D", "E");
List<String> namesWithA = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());

Operator:接收和返回同样的类型

Operator接收和返回同样的类型,有很多种Operator:UnaryOperator BinaryOperator ,DoubleUnaryOperator, IntUnaryOperator, LongUnaryOperator, DoubleBinaryOperator, IntBinaryOperator, LongBinaryOperator等。

@FunctionalInterface
public interface IntUnaryOperator { /**
* Applies this operator to the given operand.
*
* @param operand the operand
* @return the operator result
*/
int applyAsInt(int operand);

我们看一个BinaryOperator的例子:

 //Operator
List<Integer> values = Arrays.asList(1, 2, 3, 4, 5);
int sum = values.stream()
.reduce(0, (i1, i2) -> i1 + i2);

总结

Functional Interface是一个非常有用的新特性,希望大家能够掌握。

本文的例子:https://github.com/ddean2009/learn-java-streams/tree/master/functional-interface

更多内容请访问 www.flydean.com

java中functional interface的分类和使用的更多相关文章

  1. java中的interface

    转载: Java不支持多重继承,即一个类只能有一个父类 为了克服单继承的缺点,Java使用了接口,一个类可以实现多个接口 接口是抽象方法和常量值定义的集合,是一种特殊的抽象类接口中只包含常量和方法的定 ...

  2. Java中常见的锁分类以及对应特点

    对于 Java 锁的分类没有严格意义的规则,我们常说的分类一般都是依据锁的特性.锁的设计.锁的状态等进行归纳整理的,所以常见的分类如下: 公平锁和非公平锁:公平锁是多线程按照锁申请的顺序获取锁,非公平 ...

  3. Java中常见流的分类及简单讲解

    流在Java中是指计算中流动的缓冲区. 从外部设备流向中央处理器的数据流成为“输入流”,反之成为“输出流”. 字符流和字节流的主要区别: 1.字节流读取的时候,读到一个字节就返回一个字节:字符流使用了 ...

  4. Java中的各种锁--分类总结

    前言 本文需要具备一定的多线程基础才能更好的理解. 学习java多线程时,最头疼的知识点之一就是java中的锁了,什么互斥锁.排它锁.自旋锁.死锁.活锁等等,细分的话可以罗列出20种左右的锁,光是看着 ...

  5. JMM之Java中锁概念的分类总结

    在Java的并发编程中不可避免的涉及到锁.从不同维护可以将锁进行不同的分类,如下: 1.乐观锁和悲观锁(根据读写操作的比例划分) 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数 ...

  6. Java中的日期操作 分类: B1_JAVA 2015-02-16 17:55 6014人阅读 评论(0) 收藏

    在日志中常用的记录当前时间及程序运行时长的方法: public void inject(Path urlDir) throws Exception { SimpleDateFormat sdf = n ...

  7. java中的interface接口

    接口:java接口是一些方法表征的集合,但是却不会在接口里实现具体的方法. java接口的特点如下: 1.java接口不能被实例化 2.java接口中声明的成员自动被设置为public,所以不存在pr ...

  8. java 中的interface是否继承object

    首先我们从C++说起, c++可以多继承.也就是一个类型 --- class,可以继承自2个以上的父类型.多继承导致一个问题,很多人知道.例如,如果类型B,类型C均继承自类型A.然后类型D继承自类型B ...

  9. JAVA中abstract,interface,final,static语法

    转自:http://www.cnblogs.com/yueue/archive/2010/04/20/1715863.html 一,抽象类:abstract     1,只要有一个或一个以上抽象方法的 ...

随机推荐

  1. P1343 地震逃生(最大流板题)

    P1343 地震逃生 题目描述 汶川地震发生时,四川**中学正在上课,一看地震发生,老师们立刻带领x名学生逃跑,整个学校可以抽象地看成一个有向图,图中有n个点,m条边.1号点为教室,n号点为安全地带, ...

  2. ceph概述

                                                                            ceph概述   基础知识 什么是分布式文件系统 •   ...

  3. time_wait 详解和解决方案

    1. 产生原因 2. 导致问题 3. Nginx 3.1 长连接 4. 解决方案 5 .参考 产生原因 TCP 连接关闭时,会有 4 次通讯(四次挥手),来确认双方都停止收发数据了.如上图,主动关闭方 ...

  4. 如何关闭Springboot应用服务

    背景 以往的单机应用会采用kill方式关闭应用服务,但是这种关闭应用的方式在springboot中会让当前应用将所有处理中的请求丢弃,返回失败响应.我们在处理重要业务逻辑要极力避免的这种响应失败在,所 ...

  5. DVWA系列精品教程:2、命令注入

    文章更新于:2020-04-11 注:如何搭建环境参见:搭建DVWA Web渗透测试靶场 DVWA之命令注入漏洞 一.介绍 1.1.官方说明 1.2.总结 二.命令注入实践 2.1.安全级别:LOW ...

  6. python 函数--递归函数

    一.递归函数的定义:在一个函数里面调用函数本身 python限制最大层数:998层 def foo(n): print(n) n+=1 foo(n) foo(1)

  7. 2020-3-3 20175110王礼博 《网络对抗技术》Exp1 PC平台逆向破解

    目录 1.实践目标与基础知识 2.直接修改程序机器指令,改变程序执行流程 3.通过构造输入参数,造成BOF攻击,改变程序执行流 4.注入Shellcode并执行 5.实验收获与感想 6.什么是漏洞?漏 ...

  8. "三号标题"组件:<h3> —— 快应用组件库H-UI

     <import name="h3" src="../Common/ui/h-ui/text/c_h3"></import> < ...

  9. git处理fork的个人库代码与远程项目库待代码同步与合并

    由于每个项目组git代码管理规范都不一致,分支开发和fork开发模式.我就说下fork处理的流程吧. 问题点: 我的代码是从自己的远程个人仓库clone的.我的个人远程仓库代码是从项目的远程仓库弄fo ...

  10. spark 大杂烩

    累加器 val dataRdd = sc.makeRDD(List(1, 2, 3, 4), 2) var sum = 0 //累加器可以收集driver和各个excuter中累加的结果 //如果此处 ...