java中functional interface的分类和使用详解

作者:flydean 时间:2021-09-15 15:59:20 

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

来源:http://www.flydean.com/java-functional-interface/

标签:java,functional,interface
0
投稿

猜你喜欢

  • Java热门笔试试题整理

    2023-11-25 08:56:33
  • Java中驼峰命名与下划线命名相互转换

    2021-10-01 00:56:47
  • Mybatis基础概念与高级应用小结

    2023-11-26 20:18:22
  • Android 在程序运行时申请权限的实例讲解

    2023-08-04 17:35:57
  • 深入JAVA对象深度克隆的详解

    2022-01-05 14:03:13
  • mybatis if标签判断不生效的解决方法

    2023-11-28 12:30:49
  • c#实现16进制和字符串之间转换的代码

    2023-07-22 08:28:09
  • springboot整合quartz项目使用案例

    2023-02-13 19:57:12
  • Android使用xUtils3.0实现文件上传

    2023-08-04 19:50:02
  • 浅析java移位符的具体使用

    2023-12-21 09:36:13
  • Android自定义View之组合控件实现类似电商app顶部栏

    2023-07-26 22:14:10
  • Java中SimpleDateFormat日期格式转换详解及代码示例

    2023-09-04 22:13:43
  • 基于Java接口回调详解

    2023-11-09 00:03:11
  • 使用@pathvariable与@requestparam碰到的一些问题及解决

    2023-11-27 16:30:34
  • Java实现二叉搜索树的插入、删除功能

    2023-07-15 20:54:53
  • Spring Cache+Redis缓存数据的实现示例

    2023-11-26 11:53:20
  • Java解决约瑟夫问题代码实例

    2023-09-20 19:17:02
  • C++实现softmax函数的面试经验

    2023-06-16 02:07:47
  • 一文了解Java读写锁ReentrantReadWriteLock的使用

    2023-10-12 19:28:21
  • C++右值引用与move和forward函数的使用详解

    2023-07-05 19:27:33
  • asp之家 软件编程 m.aspxhome.com