欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Java 函数式接口

程序员文章站 2022-03-26 21:02:17
文章目录一、什么是函数式接口(Functional Interface)二、函数式接口用途三、关于@FunctionalInterface 注解四、函数式接口里允许定义静态方法五、函数式接口里允许定义java.lang.Object里的public方法六、常用函数式接口①、`Consumer`:消费型接口②、`Supplier`: 供给型接口③、`Function`: 函数型接口④、`Predicate` : 断言型接口一、什么是函数式接口(Functional Interface)  有且只有一个....

一、什么是函数式接口(Functional Interface)

  有且只有一个抽象方法的接口被称为函数式接口,函数式接口适用于函数式编程的场景,Lambda就是Java中函数式编程的体现,可以使用Lambda表达式创建一个函数式接口的对象,一定要确保接口中有且只有一个抽象方法,这样Lambda才能顺利的进行推导。

二、函数式接口用途

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

如定义了一个函数式接口如下:

@FunctionalInterface
interface GreetingService {
	void sayMessage(String message);
}

那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):

GreetingService greetService1 = message -> System.out.println("Hello " + message);

三、关于@FunctionalInterface 注解

  Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。

正确例子,没有报错 :

@FunctionalInterface
public interface MyInterface {

    void method01();
    
}

错误例子,接口中包含了两个抽象方法,违反了函数式接口的定义,

详解Java 函数式接口

  提醒:加不加@FunctionalInterface对于接口是不是函数式接口没有影响,该注解知识提醒编译器去检查该接口是否仅包含一个抽象方法

四、函数式接口里允许定义静态方法

  函数式接口里是可以包含静态方法,因为静态方法不能是抽象方法,是一个已经实现了的方法,所以是符合函数式接口的定义的;

如下代码不会报错:

    @FunctionalInterface
    interface MyInterface {
    
        void sayMessage(String message);
        
        static void printHello(){
            System.out.println("Hello");
        }
        
    }

五、函数式接口里允许定义java.lang.Object里的public方法

  函数式接口里是可以包含Object里的public方法,这些方法对于函数式接口来说,不被当成是抽象方法(虽然它们是抽象方法);因为任何一个函数式接口的实现,默认都继承了Object类,包含了来自java.lang.Object里对这些抽象方法的实现;

如下代码不会报错:

    @FunctionalInterface
    interface GreetingService  
    {
        void sayMessage(String message);
        
        @Override
        boolean equals(Object obj);
    }

六、常用函数式接口

接口 方法 示例
UnaryOperator T apply(T t) String::toLowerCase
BinaryOperator T apply(T t1, T t2) BigInteger::add
Predicate boolean test(T t) Collection::isEmpty
Function<T,R> R apply(T t) Arrays::asList
Supplier T get() Instant::now
Consumer void accept(T t) System.out::println

①、Consumer:消费型接口

抽象方法: void accept(T t),接收一个参数进行消费,但无需返回结果。

使用方式:

  Consumer consumer = System.out::println;
  consumer.accept("hello function");

默认方法: andThen(Consumer<? super T> after),先消费然后在消费,先执行调用andThen接口的accept方法,然后在执行andThen方法参数after中的accept方法。

使用方式:

  Consumer<String> consumer1 = s -> System.out.print("车名:"+s.split(",")[0]);
  Consumer<String> consumer2 = s -> System.out.println("-->颜色:"+s.split(",")[1]);

  String[] strings = {"保时捷,白色", "法拉利,红色"};
  for (String string : strings) {
     consumer1.andThen(consumer2).accept(string);
  }

输出: 车名:保时捷–>颜色:白色 车名:法拉利–>颜色:红色

②、Supplier: 供给型接口

抽象方法:T get(),无参数,有返回值。

使用方式:

 Supplier<String> supplier = () -> "我要变的很有钱";
 System.out.println(supplier.get());

最后输出就是“我要变得很有钱”,这类接口适合提供数据的场景。

③、Function: 函数型接口

抽象方法: R apply(T t),传入一个参数,返回想要的结果。

使用方式:

 Function<Integer, Integer> function1 = e -> e * 6;
 System.out.println(function1.apply(2));

很简单的一个乘法例子,显然最后输出是12。

默认方法:

  • compose(Function<? super V, ? extends T> before),先执行compose方法参数before中的apply方法,然后将执行结果传递给调用compose函数中的apply方法在执行。

使用方式:

 Function<Integer, Integer> function1 = e -> e * 2;
 Function<Integer, Integer> function2 = e -> e * e;

 Integer apply2 = function1.compose(function2).apply(3);
 System.out.println(apply2);

  还是举一个乘法的例子,compose方法执行流程是先执行function2的表达式也就是33=9,然后在将执行结果传给function1的表达式也就是92=18,所以最终的结果是18。

  • andThen(Function<? super R, ? extends V> after),先执行调用andThen函数的apply方法,然后在将执行结果传递给andThen方法after参数中的apply方法在执行。它和compose方法整好是相反的执行顺序。

使用方式:

 Function<Integer, Integer> function1 = e -> e * 2;
 Function<Integer, Integer> function2 = e -> e * e;

 Integer apply3 = function1.andThen(function2).apply(3);
 System.out.println(apply3);

  这里我们和compose方法使用一个例子,所以是一模一样的例子,由于方法的不同,执行顺序也就不相同,那么结果是大大不同的。andThen方法是先执行function1表达式,也就是32=6,然后在执行function2表达式也就是66=36。结果就是36。 **静态方法:**identity(),获取一个输入参数和返回结果相同的Function实例。

使用方式:

 Function<Integer, Integer> identity = Function.identity();
 Integer apply = identity.apply(3);
 System.out.println(apply);

平常没有遇到过使用这个方法的场景,总之这个方法的作用就是输入什么返回结果就是什么。

④、Predicate : 断言型接口

抽象方法: boolean test(T t),传入一个参数,返回一个布尔值。

使用方式:

 Predicate<Integer> predicate = t -> t > 0;
 boolean test = predicate.test(1);
 System.out.println(test);

  当predicate函数调用test方法的时候,就会执行拿test方法的参数进行t -> t > 0的条件判断,1肯定是大于0的,最终结果为true。

默认方法:

  • and(Predicate<? super T> other),相当于逻辑运算符中的&&,当两个Predicate函数的返回结果都为true时才返回true。

使用方式:

 Predicate<String> predicate1 = s -> s.length() > 0;
 Predicate<String> predicate2 = Objects::nonNull;
 boolean test = predicate1.and(predicate2).test("&&测试");
 System.out.println(test);
  • or(Predicate<? super T> other) ,相当于逻辑运算符中的||,当两个Predicate函数的返回结果有一个为true则返回true,否则返回false。

使用方式:

 Predicate<String> predicate1 = s -> false;
 Predicate<String> predicate2 = Objects::nonNull;
 boolean test = predicate1.and(predicate2).test("||测试");
 System.out.println(test);
  • negate(),这个方法的意思就是取反。

使用方式:

 Predicate<String> predicate = s -> s.length() > 0;
 boolean result = predicate.negate().test("取反");
 System.out.println(result);

很明显正常执行test方法的话应该为true,但是调用negate方法后就返回为false了。 静态方法: isEqual(Object targetRef),对当前操作进行"="操作,即取等操作,可以理解为 A == B。

使用方式:

 boolean test1 = Predicate.isEqual("test").test("test");
 boolean test2 = Predicate.isEqual("test").test("equal");
 System.out.println(test1);   //true
 System.out.println(test2);   //false

参考链接:

  • https://juejin.im/post/5d2ff837f265da1bd424b710

  • https://www.cnblogs.com/runningTurtle/p/7092632.html

  • https://www.jianshu.com/p/56e1ef91e34e

本文地址:https://blog.csdn.net/VariatioZbw/article/details/107367797

相关标签: Java java