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

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

总结

到此这篇关于java中functional interface的分类和使用详解的文章就介绍到这了,更多相关java中functional interface的分类和使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java8中stream和functional interface的配合使用详解

    前言 Java 8 提供了一组称为 stream 的 API,用于处理可遍历的流式数据.stream API 的设计,充分融合了函数式编程的理念,极大简化了代码量. 大家其实可以把Stream当成一个高级版本的Iterator.原始版本的Iterator,用户只能一个一个的遍历元素并对其执行某些操作:高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如"过滤掉长度大于10的字符串"."获取每个字符串的首字母"等,具体这些操作如何应用到每个元素上,

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

    java 8引入了lambda表达式,lambda表达式实际上表示的就是一个匿名的function. 在java 8之前,如果需要使用到匿名function需要new一个类的实现,但是有了lambda表达式之后,一切都变的非常简介. 我们看一个之前讲线程池的时候的一个例子: //ExecutorService using class ExecutorService executorService = Executors.newSingleThreadExecutor(); executorSer

  • Java中Validated、Valid 、Validator区别详解

    目录 1. 结论先出 JSR 380 Valid VS Validated 不同点? Validator 2. @Valid和​​​​​​​@Validated 注解 3. 例子 4.使用@Valid嵌套校验 5. 组合使用@Valid和@Validated 进行集合校验 6. 自定义校验 自定义约束注解 工作原理 结论 参考链接: 1. 结论先出 Valid VS Validated 相同点 都可以对方法和参数进行校验 @Valid和@Validated 两种注释都会导致应用标准Bean验证.

  • java 中Excel转shape file的实例详解

    java  中Excel转shape file的实例详解 概述: 本文讲述如何结合geotools和POI实现Excel到shp的转换,再结合前文shp到geojson数据的转换,即可实现用户上传excel数据并在web端的展示功能. 截图: 原始Excel文件 运行耗时 运行结果 代码: package com.lzugis.geotools; import com.lzugis.CommonMethod; import com.vividsolutions.jts.geom.Coordina

  • 基于java中的PO VO DAO BO POJO(详解)

    一.PO:persistant object 持久对象,可以看成是与数据库中的表相映射的ava对象. 最简单的PO就是对应数据库中某个表中的一条记录,多个记录可以用PO的集合PO中应该不包含任何对数据库的操作. 二.VO:value object值对象.通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已.但应是抽象出的业务对象可以和表对应也可以不这根据业务的需要 三.DAO:data access object 数据访问对象,此对象用于访问数据库.通常和PO结合使用,DAO中包含了各种

  • JAVA 中解密RSA算法JS加密实例详解

    JAVA 中解密RSA算法JS加密实例详解 有这样一个需求,前端登录的用户名密码,密码必需加密,但不可使用MD5,因为后台要检测密码的复杂度,那么在保证安全的前提下将密码传到后台呢,答案就是使用RSA非对称加密算法解决 . java代码 需要依赖 commons-codec 包 RSACoder.Java import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import java.security.

  • Java 中组合模型之对象结构模式的详解

    Java 中组合模型之对象结构模式的详解 一.意图 将对象组合成树形结构以表示"部分-整体"的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 二.适用性 你想表示对象的部分-整体层次结构 你希望用户忽略组合对象与单个对象的不同,用户将统一使用组合结构中的所有对象. 三.结构 四.代码 public abstract class Component { protected String name; //节点名 public Component(String n

  • Java中对List集合的常用操作详解

    目录: 1.list中添加,获取,删除元素: 2.list中是否包含某个元素: 3.list中根据索引将元素数值改变(替换): 4.list中查看(判断)元素的索引: 5.根据元素索引位置进行的判断: 6.利用list中索引位置重新生成一个新的list(截取集合): 7.对比两个list中的所有元素: 8.判断list是否为空: 9.返回Iterator集合对象: 10.将集合转换为字符串: 11.将集合转换为数组: 12.集合类型转换: 备注:内容中代码具有关联性. 1.list中添加,获取,

  • Java中成员方法与成员变量访问权限详解

    记得在一次面试的笔试题中,有的面试官会要求写出具体的像pullic这些访问限定符的作用域.其实,平常我都没去系统的考虑这些访问限定符的作用域,特别是包内包外的情况,OK,笔试不行了. 这是java基本的知识,也是公司看重的,那没办法啦,我的脑袋记不住东西,那我只能把这些东西写下来方便自己温故知新,不废话了,贴代码了. 代码如下: package com.jaovo; /** *_1_ 成员变量访问权限的求证 * public private protected default(默认的权限) *自

  • Java中map遍历方式的选择问题详解

    1. 阐述 对于Java中Map的遍历方式,很多文章都推荐使用entrySet,认为其比keySet的效率高很多.理由是:entrySet方法一次拿到所有key和value的集合:而keySet拿到的只是key的集合,针对每个key,都要去Map中额外查找一次value,从而降低了总体效率.那么实际情况如何呢? 为了解遍历性能的真实差距,包括在遍历key+value.遍历key.遍历value等不同场景下的差异,我试着进行了一些对比测试. 2. 对比测试 一开始只进行了简单的测试,但结果却表明k

  • java 中序列化与readResolve()方法的实例详解

    java 中序列化与readResolve()方法的实例详解 readResolve方法是作用是什么?这个方法跟对象的序列化相关(这样倒是解释了为什么 readResolve方法是private修饰的). 怎么跟对象的序列化相关了? 下面我们先简要地回顾下对象的序列化.一般来说,一个类实现了 Serializable接口,我们就可以把它往内存地写再从内存里读出而"组装"成一个跟原来一模一样的对象.不过当序列化遇到单例时,里边就有了个问题:从内存读出而组装的对象破坏了单例的规则.单例是要

随机推荐