Java8之函数式接口及常用函数式接口讲解

 更新时间:2022年11月21日 14:29:52   作者:代码大师麦克劳瑞  
这篇文章主要介绍了Java8之函数式接口及常用函数式接口,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

函数式接口

1.概念

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

函数式接口可以被隐式转换为 lambda 表达式。

Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。

2.@FunctionalInterface

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

我们常用的Runnable接口就是个典型的函数式接口,我们可以看到它有且仅有一个抽象方法run。并且可以看到一个注解@FunctionalInterface,这个注解的作用是强制你的接口只有一个抽象方法。

如果有多个话直接会报错,如图:

idea错误提示:

编译时错误提示:

这里当你写了第二个方法时,编译就无法通过,idea甚至在编码阶段就行了提示。

3.函数式接口使用方式

我们直接上代码,首先定义一个函数式接口

@FunctionalInterface
public interface SingleAbstraMethodInterface {
    public abstract void singleMethod();
}

我们定一个test类,封装一个方法,将SingleAbstraMethodInterface当做参数传入方法,并打印一句话

public class Test {
    public void testMethod(SingleAbstraMethodInterface single){
        System.out.println("即将执行函数式接口外部定义方法");
        single.singleMethod();
    }
    public static void main(String[] args) {
        Test test = new Test();
        test.testMethod(new SingleAbstraMethodInterface() {
            @Override
            public void singleMethod() {
                System.out.println("执行函数式接口定义方法");
            }
        });
    }
}

执行结果:

即将执行函数式接口外部定义方法
执行函数式接口定义方法

是不是和我们预期结果一样。这个过程是不是有的同学已经发现,怎么这么像jdk里面的一些接口的使用,比如常用的Runnable接口。

我们来看看代码。

public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("run方法执行了");
            }
        }).start();
}

再看下Runnable接口源码,是不是一样

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

这时,有的同学会说,我用Runnable接口可不是这么用的,我的写法比你优雅,我是这么写的。

没错函数式接口,函数式编程,我们可以使用lambda表达式的写法,可以让代码更优雅,具体可以参照我的前一篇帖子。Java8之Lambda表达式

public static void main(String[] args) {
        new Thread(()-> {
           System.out.println("run方法执行了");
        }).start();
}

常用函数式接口

1.JDK提供的函数式接口举栗

java.lang.Runnable,
java.awt.event.ActionListener,
java.util.Comparator,
java.util.concurrent.Callable

java.util.function包下的接口,如Consumer、Predicate、Supplier等

其实,jdk中给我们提供了很多的函数式接口,我们平时都会用到,只不过大家没有注意到而已,这里我结合实际代码讲解几个常用的函数式接口。想想大家平时常常用到stream流的各种方法来处理list。我看去stream类中看一下它提供的方法。可以看到有几个出镜率较高的函数式接口

  • Supplier
  • Comsumer
  • Predicate
  • Function

2.Supplier

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

Supplier接口的get方法没有入参,返回一个泛型T对象。

我们来看几个使用 的实例。

先写一个实验对象girl,我们定义一个方法,创建对象,我们使用lambda的方式来调用并创建对象。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Girl {

    private String name;

    private Double size;

    private Double price;

    public static Girl create(final Supplier<Girl> supplier) {
        return supplier.get();
    }

    public static void main(String[] args) {
    	//创建对象
        Girl girl1 = Girl.create(Girl::new);
        Girl girl2 = Girl.create(()-> new Girl("lily",33d,1700d));
        Girl girl = null;
        //orElseGet
        Girl girl3 = Optional.ofNullable(girl).orElseGet(Girl::new);
    }
    
}

需要注意的是,我没每调用一次get方法,都会重新创建一个对象

orElseGet方法入参同样也是Supplier,这里对girl实例进行判断,通过Supplier实现了懒加载,也就是说只有当判断girl为null时,才会通过orElseGet方法创建新的对象并且返回。不得不说这个设计是非常的巧妙。

3.Consumer

源码如下:

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

可以看到accept方法接受一个对象,没有返回值。

那么我们来实战,首先使用Lambda表达式声明一个Supplier的实例,它是用来创建Girl实例;再使用Lambda表达式声明一个Consumer的实例,它是用于打印出Girl实例的toString信息;最后Consumer消费了Supplier生产的Girl。

我们常用的forEach方法入参也是Consumer。

使用代码如下:

	Supplier<Girl> supplier = ()-> new Girl("lucy",33d,1700d);
	Consumer<Girl> consumer = (Girl g)->{
	   System.out.println(g.toString());
	};
	consumer.accept(supplier.get());
	ArrayList<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);
    list.forEach(System.out::println);

4.Predicate

@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);
}

可以看到test方法接受一个对象,返回boolean类型,这个函数显然是用来判断真假。

那么我们用这个接口来构造一个判断女孩子条件的示例,还有我们常用的stream流中,filter的入参也是Predicate,代码如下:

		Supplier<Girl> supplier = ()-> new Girl("lucy",33d,1700d);
        Predicate<Girl> girl36d = (Girl g)-> Objects.equals(g.getSize(),36d);
        Predicate<Girl> girl33d = (Girl g)-> Objects.equals(g.getSize(),33d);
        boolean test33 = girl33d.test(supplier.get());
        boolean test36 = girl36d.test(supplier.get());
        System.out.println(supplier.get().getName() +"是否为[36d] :"+test36);
        System.out.println(supplier.get().getName() +"是否为[33d] :"+test33);

结果为:

lucy是否为[36d] :false
lucy是否为[33d] :true

		ArrayList<Girl> list = Lists.newArrayList();
        list.add(new Girl("露西", 33d, 2000d));
        list.add(new Girl("格蕾丝", 36d, 3000d));
        list.add(new Girl("安娜", 28d, 1500d));
        list.add(new Girl("克瑞斯", 31d, 1800d));
        Predicate<Girl> greaterThan30d = (Girl g)-> g.getSize()>=30d;
        list.stream().filter(greaterThan30d).forEach(System.out::println);

结果如下:

Girl(name=露西, size=33.0, price=2000.0)
Girl(name=格蕾丝, size=36.0, price=3000.0)
Girl(name=克瑞斯, size=31.0, price=1800.0)

5.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);
}

这个看到apply接口接收一个泛型为T的入参,返回一个泛型为R的返回值,所以它的用途和Supplier还是略有区别。还是一样我们举个栗子用代码来说明:

Supplier<Girl> supplier = ()-> new Girl("lucy",33d,1700d);
 Function<Girl,String> girlMark = (Girl g)-> g.getName()+"的尺寸是"+g.getSize()+",每次能赚"+g.getPrice()+"。";
 System.out.println(girlMark.apply(supplier.get()));

我们可以看到funtion接口接收Girl对象实例,对girl的成员变量进行拼接,返回girl的描述信息。其基本用法就是如此。

lucy的尺寸是33.0,每次能赚1700.0。

6.常用函数式接口相关扩展接口

这里我列举一些Supplier相关接口

a.Supplier相关拓展接口

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

b.Comsumer相关拓展接口

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

c.Predicate相关拓展接口

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

d.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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • springboot如何集成Swagger2

    springboot如何集成Swagger2

    这篇文章主要介绍了springboot集成Swagger2的方法,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下
    2020-12-12
  • Mybatis批量修改时出现报错问题解决方案

    Mybatis批量修改时出现报错问题解决方案

    这篇文章主要介绍了Mybatis批量修改时出现报错问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • springboot 增加过滤器方法操作示例

    springboot 增加过滤器方法操作示例

    这篇文章主要介绍了springboot 增加过滤器方法操作,结合实例形式分析了springboot过滤器配置、加载等相关操作技巧,需要的朋友可以参考下
    2019-12-12
  • 详解Idea中HTTP Client请求测试工具的使用

    详解Idea中HTTP Client请求测试工具的使用

    今天抽空给大家分享Idea中HTTP Client请求测试工具的使用,小编在这建议使用HTTP Client的Idea版本最好在2018以上,不然的话体验不是多好,今天就给大家介绍Idea中HTTP Client怎么使用的,感兴趣的朋友跟随小编一起看看吧
    2021-05-05
  • Java设计模式之观察者模式_动力节点Java学院整理

    Java设计模式之观察者模式_动力节点Java学院整理

    这篇文章给大家介绍流量java设计模式之观察者模式,定义对象间一种一对多的依赖关系,使得当每一个对象改变状态。下面通过类图和实例代码给大家介绍java设计模式之观察者模式,感兴趣的朋友一起看看吧
    2017-08-08
  • 一道Java集合框架题 多种解题思路

    一道Java集合框架题 多种解题思路

    这篇文章主要介绍了一道Java集合框架题,多种解题思路,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • Java面向对象之猜拳游戏

    Java面向对象之猜拳游戏

    这篇文章主要为大家详细介绍了Java面向对象之猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • Spring JPA学习之delete方法示例详解

    Spring JPA学习之delete方法示例详解

    这篇文章主要为大家介绍了Spring JPA学习delete方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • Springboot拦截filter中异常的处理

    Springboot拦截filter中异常的处理

    SpringBoot提供了全局异常处理机制可以拦截所有异常,包括Filter中的异常,本文主要介绍了Springboot拦截filter中异常的处理,具有一定的参考价值,感兴趣的可以了解一下
    2023-11-11
  • Scala 操作Redis使用连接池工具类RedisUtil

    Scala 操作Redis使用连接池工具类RedisUtil

    这篇文章主要介绍了Scala 操作Redis使用连接池工具类RedisUtil,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06

最新评论