Java Lambda表达式常用的函数式接口

作者:万猫学社 时间:2021-10-30 13:43:53 

前言:

在Java8支持Lambda表达式以后,为了满足Lambda表达式的一些典型使用场景,JDK为我们提供了大量常用的函数式接口。它们主要在 java.util.function 包中,下面简单介绍几个其中的接口及其使用示例。

Supplier接口

Supplier接口是对象实例的提供者,定义了一个名叫get的抽象方法,它没有任何入参,并返回一个泛型T对象,具体源码如下:

package java.util.function;

@FunctionalInterface
public interface Supplier<T> {
   T get();
}

源码比较简单,我们来个例子。这是之前提过的表示口罩的类:

package one.more.study;

/**
* 口罩
*/
public class Mask {
   public Mask(String brand, String type) {
       this.brand = brand;
       this.type = type;
   }
   /**
    * 品牌
    */
   private String brand;
   /**
    * 类型
    */
   private String type;

public String getBrand() {
       return brand;
   }

public void setBrand(String brand) {
       this.brand = brand;
   }

public String getType() {
       return type;
   }

public void setType(String type) {
       this.type = type;
   }
}

下面我们使用Lambda表达式声明一个Supplier的实例:

Supplier<Mask> supplier = () -> new Mask("3M", "N95");

用它来创建品牌为3M、类型为N95的Mask实例:

Mask mask = supplier.get();
System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());

运行结果如下:

Brand: 3M, Type: N95

特别需要注意的是,本例中每一次调用get方法都会创建新的对象。

Consumer接口

Consumer接口是一个类似消费者的接口,定义了一个名叫accept的抽象方法,它的入参是一个泛型T对象,没有任何返回(void),主要源码如下:

package java.util.function;

@FunctionalInterface
public interface Consumer<T> {
   void accept(T t);
}

结合上面的Supplier接口,我们来个例子:

Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Consumer<Mask> consumer = (Mask mask) -> {
   System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
};
consumer.accept(supplier.get());

首先使用Lambda表达式声明一个Supplier的实例,它是用来创建品牌为3M、类型为N95的Mask实例;再使用Lambda表达式声明一个Consumer的实例,它是用于打印出Mask实例的相关信息;最后Consumer消费了Supplier生产的Mask

运行结果如下:

Brand: 3M, Type: N95

Predicate接口

Predicate接口是判断是与否的接口,定义了一个名叫test的抽象方法,它的入参是一个泛型T对象,并返回一个boolean类型,主要源码如下:

package java.util.function;

@FunctionalInterface
public interface Predicate<T> {
   boolean test(T t);
}

结合上面的Supplier接口,我们来个例子:

Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Predicate<Mask> n95 = (Mask mask) -> "N95".equals(mask.getType());
Predicate<Mask> kn95 = (Mask mask) -> "KN95".equals(mask.getType());
System.out.println("是否为N95口罩:" + n95.test(supplier.get()));
System.out.println("是否为KN95口罩:" + kn95.test(supplier.get()));

首先使用Lambda表达式声明一个Supplier的实例,它是用来创建品牌为3M、类型为N95的Mask实例;再使用Lambda表达式声明一个Predicate的实例n95,它是用于判断是否为N95口罩;再使用Lambda表达式声明一个Predicate的实例kn95,它是用于判断是否为KN95口罩;最后分别用两个Predicate判断Supplier生产的Mask

运行结果如下:

是否为N95口罩:true
是否为KN95口罩:false

Function接口

Function接口是对实例进行处理转换的接口,定义了一个名叫apply的抽象方法,它的入参是一个泛型T对象,并返回一个泛型R对象,主要源码如下:

package java.util.function;

@FunctionalInterface
public interface Function<T, R> {
   R apply(T t);
}

结合上面的Supplier接口,我们来个例子:

Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Function<Mask, String> brand = (Mask mask) -> mask.getBrand();
Function<Mask, String> type = (Mask mask) -> mask.getType();
System.out.println("口罩品牌:" + brand.apply(supplier.get()));
System.out.println("口罩类型:" + type.apply(supplier.get()));

首先使用Lambda表达式声明一个Supplier的实例,它是用来创建品牌为3M、类型为N95的Mask实例;再使用Lambda表达式声明一个Function的实例brand,它是用于获取口罩的品牌;再使用Lambda表达式声明一个Function的实例type,它是用于获取口罩的类型;最后分别用两个Function分析Supplier生产的Mask

运行结果如下:

口罩品牌:3M
口罩类型:N95

BiFunction接口

Function接口的入参只有一个泛型对象,JDK还为我们提供了两个泛型对象入参的接口:BiFunction接口,主要源码如下:

package java.util.function;

@FunctionalInterface
public interface BiFunction<T, U, R> {
   R apply(T t, U u);
}

我们可以用BiFunction接口传入两个String直接创建Mask实例:

BiFunction<String,String,Mask> biFunction = (String brand, String type) -> new Mask(brand, type);
Mask mask = biFunction.apply("3M", "N95");
System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());

运行结果如下:

Brand: 3M, Type: N95

基本数据类型

以上介绍的几个常用的函数式接口入参和返回,都是泛型对象的,也就是必须为引用类型。当我们传入或获取的是基本数据类型时,将会发生自动装箱和自动拆箱,带来不必要的性能损耗,比如:

Supplier&lt;Long&gt; supplier = () -&gt; System.currentTimeMillis();
long timeMillis = supplier.get();

在上面例子里,发生了一次自动装箱(long被装箱为Long)和一次自动拆箱(Long被拆箱为long),如何避免这种不必要的性能损耗呢?JDK为我们提供相应的函数式接口,如LongSupplier接口,定义了一个名叫getAsLong的抽象方法,签名是() -> long

上面的例子可以优化为:

LongSupplier supplier = () -&gt; System.currentTimeMillis();
long timeMillis = supplier.getAsLong();

类似这样的接口还有很多,我为大家整理了一下:

Supplier相关的接口

接口名称方法名称方法签名
Supplierget() -> T
BooleanSuppliergetAsBoolean() -> boolean
DoubleSuppliergetAsDouble() -> double
IntSuppliergetAsInt() -> int
LongSuppliergetAsLong() -> long

Consumer相关的接口

接口名称方法名称方法签名
Consumeraccept(T) -> void
DoubleConsumeraccept(double) -> void
IntConsumeraccept(int) -> void
LongConsumeraccept(long) -> void
ObjDoubleConsumeraccept(T, double) -> void
ObjIntConsumeraccept(T, int) -> void
ObjLongConsumeraccept(T, long) -> void

Predicate相关的接口

接口名称方法名称方法签名
Predicatetest(T) -> boolean
BiPredicatetest(T, U) -> boolean
DoublePredicatetest(double) -> boolean
IntPredicatetest(int) -> boolean
LongPredicatetest(long) -> boolean

Function相关的接口

接口名称方法名称方法签名
Functionapply(T) -> R
BiFunctionapply(T, U) -> R
DoubleFunctionapply(double) -> R
DoubleToIntFunctionapplyAsInt(double) -> int
DoubleToLongFunctionapplyAsLong(double) -> long
IntFunctionapply(int) -> R
IntToDoubleFunctionapplyAsDouble(int) -> double
IntToLongFunctionapplyAsLong(int) -> long
LongFunctionapply(long) -> R
LongToDoubleFunctionapplyAsDouble(long) -> double
LongToIntFunctionapplyAsInt(long) -> int
ToDoubleFunctionapplyAsDouble(T) -> double
ToDoubleBiFunctionapplyAsDouble(T, U) -> double
ToIntFunctionapplyAsInt(T) -> int
ToIntBiFunctionapplyAsInt(T, U) -> int
ToLongFunctionapplyAsLong(T) -> long
ToLongBiFunctionapplyAsLong(T, U) -> long

来源:https://blog.51cto.com/u_6740480/5180488

标签:Java,Lambda,表达式,函数式,接口
0
投稿

猜你喜欢

  • Android编程学习之抽象类AbsListView用法实例分析

    2023-03-18 12:19:49
  • Java tomcat中的类加载器和安全机制你了解吗

    2022-05-11 15:45:02
  • spring boot + mybatis实现动态切换数据源实例代码

    2021-11-14 03:37:59
  • Java使用Iterator迭代器遍历集合数据的方法小结

    2021-10-28 00:22:40
  • 简单谈谈C#中深拷贝、浅拷贝

    2022-06-25 04:36:56
  • Lombok 的@StandardException注解解析

    2022-09-16 23:37:19
  • 基于C#调用OCX控件的常用方法(推荐)

    2021-06-24 11:56:29
  • C#通过链表实现队列的方法

    2023-06-19 15:14:17
  • Android WebView 不支持 H5 input type="file" 解决方法

    2022-08-30 21:07:08
  • Android App中自定义View视图的实例教程

    2021-08-16 16:54:35
  • kafka生产者发送消息流程深入分析讲解

    2022-10-12 08:39:30
  • springboot结合maven实现多模块打包

    2022-01-16 07:13:51
  • Android中ImageView用法实例分析

    2023-04-03 19:42:28
  • jpa多数据源时Hibernate配置自动生成表不生效的解决

    2023-04-24 06:19:55
  • Java接口返回省市区树形结构的实现

    2021-10-16 05:07:05
  • C#简单获取时间差的小例子

    2022-02-20 10:12:34
  • 深入学习java枚举的应用

    2022-10-27 19:56:34
  • SpringMVC利用dropzone组件实现图片上传

    2022-01-19 00:37:00
  • C#获取图片文件扩展名的方法

    2022-03-06 04:27:43
  • 简单了解4种分布式session解决方案

    2023-08-09 11:45:49
  • asp之家 软件编程 m.aspxhome.com