Java8函数式接口

函数式接口

函数式接口是什么?

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

@FunctionalInterface注解

与@Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解:@FunctionalInterface 。该注解可用于一个接口的定义上,一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。但是这个注解不是必须的,只要符合函数式接口的定义,那么这个接口就是函数式接口。

static方法和default方法

实在不知道该在哪介绍这两个方法了,所以就穿插在这里了。

static方法:

java8中为接口新增了一项功能,定义一个或者多个静态方法。用法和普通的static方法一样,例如:

public interface Interface {
    /**
     * 静态方法
     */
    static void staticMethod() {
        System.out.println("static method");
    }
}

注意:实现接口的类或者子接口不会继承接口中的静态方法。

default方法:

java8在接口中新增default方法,是为了在现有的类库中中新增功能而不影响他们的实现类,试想一下,如果不增加默认实现的话,接口的所有实现类都要实现一遍这个方法,这会出现兼容性问题,如果定义了默认实现的话,那么实现类直接调用就可以了,并不需要实现这个方法。default方法怎么定义?

public interface Interface {
    /**
     * default方法
     */
    default void print() {
        System.out.println("hello default");
    }
}

注意:如果接口中的默认方法不能满足某个实现类需要,那么实现类可以覆盖默认方法。不用加default关键字,例如:

public class InterfaceImpl implements Interface {
    @Override
    public  void print() {
        System.out.println("hello default 2");
    }
}

在函数式接口的定义中是只允许有一个抽象方法,但是可以有多个static方法和default方法。

自定义函数式接口

按照下面的格式定义,你也能写出函数式接口:

 @FunctionalInterface
 修饰符 interface 接口名称 {
    返回值类型 方法名称(可选参数信息);
    // 其他非抽象方法内容
 }

虽然@FunctionalInterface注解不是必须的,但是自定义函数式接口最好还是都加上,一是养成良好的编程习惯,二是防止他人修改,一看到这个注解就知道是函数式接口,避免他人往接口内添加抽象方法造成不必要的麻烦。

@FunctionalInterface
public interface MyFunction {
    void print(String s);
}

看上图是我自定义的一个函数式接口,那么这个接口的作用是什么呢?就是输出一串字符串,属于消费型接口,是模仿Consumer接口写的,只不过这个没有使用泛型,而是将参数具体类型化了,不知道Consumer没关系,下面会介绍到,其实java8中提供了很多常用的函数式接口,Consumer就是其中之一,一般情况下都不需要自己定义,直接使用就好了。那么怎么使用这个自定义的函数式接口呢?我们可以用函数式接口作为参数,调用时传递Lambda表达式。如果一个方法的参数是Lambda,那么这个参数的类型一定是函数式接口。例如:

public class MyFunctionTest {
    public static void main(String[] args) {
        String text = "试试自定义函数好使不";
        printString(text, System.out::print);
    }

    private static void printString(String text, MyFunction myFunction) {
        myFunction.print(text);
    }
}

常用函数式接口


  • Predicate-- 传入一个参数,返回一个bool结果, 方法为boolean test(T t)
  • Consumer-- 传入一个参数,无返回值,纯消费。 方法为void accept(T t)
  • Function<T,R> -- 传入一个参数,返回一个结果,方法为R apply(T t)
  • Supplier-- 无参数传入,返回一个结果,方法为T get()
  • UnaryOperator-- 一元操作符, 继承Function<T,T>,传入参数的类型和返回类型相同。
  • BinaryOperator-- 二元操作符, 传入的两个参数的类型和返回类型相同, 继承BiFunction<T,T,T>

Consumer<T>:消费型接口

接收一个类型T的参数,没有返回值。

源码介绍:

@FunctionalInterface
public interface Consumer<T> {
    /**
     * 接收一个类型T的参数,没有返回值。
     */
    void accept(T t);
​
    /**
     * 相当于链式操作,对给定的参数进行多次操作。
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

代码示例:

public static void main(String[] args)  {
    // 方法一:普通方法
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer.accept("hello world");
​
        // 方法二:lambda表达式
        Consumer<String> consumer2 = str-> System.out.println(str);
        consumer2.accept("gogogo");
​
        // andThen 方法
        consumer.andThen(consumer2).accept("xiaoming");
}

抽象方法: 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>: 供给型接口

不接受任何参数,返回类型T的结果。

源码介绍:

@FunctionalInterface
public interface Supplier<T> {
    /**
     * 不接受任何参数,返回类型T的结果。
     */
    T get();
}

代码示例

public static void main(String[] args) {
    // 方法一:普通方法
    Supplier<String> supplier = new Supplier() {
        @Override
        public String get() {
            return "hello world";
        }
    };
    System.out.println(supplier.get());
​
    // 方法二:lambda表达式
    Supplier<String> supplier2 = () -> "hello world";
    System.out.println(supplier2.get());
}

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

使用方式:

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

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


Function<T,R>: 函数型接口

接收一个类型T参数,返回一个类型R的结果。

源码介绍

@FunctionalInterface
public interface Function<T, R> {
    /**
     * 接收一个类型T参数,返回一个类型R的结果。
     */
    R apply(T t);
​
    /**
     * 相当于链式操作,先将给定的参数传入before进行操作,操作结果再使用外层函数进行操作。
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
​
    /**
     * 相当于链式操作,先将给定的参数传入外层函数进行操作,操作结果再使用after进行操作。
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
​
    /**
     * 返回该函数的参数。
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

代码示例

public static void main(String[] args) {
    // 方法一:普通方法
    Function<Integer, Integer> function = new Function<Integer, Integer>() {
        @Override
        public Integer apply(Integer i) {
            return i + i;
        }
    };
    System.out.println(function.apply(2));
​
    // 方法二:lambda表达式
    Function<Integer, Integer> function2 = (i) -> i * i;
    System.out.println(function2.apply(3));
​
    // compose 方法
    System.out.println(function.compose(function2).apply(4));
​
    // andThen 方法
    System.out.println(function.andThen(function2).apply(4));
​
    // identity 方法 相当于 this -> this
    Arrays.asList("a", "b", "c").stream()
        .map(Function.identity()) // <- This,
        .map(str -> str)          // <- is the same as this.
        .collect(Collectors.toMap(
            Function.identity(), // <-- And this,
            str -> str));        // <-- is the same as this.
}

抽象方法: 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<T> : 断言型接口

接收一个类型T的参数,给出判断结果。

源码介绍

@FunctionalInterface
public interface Predicate<T> {
    /**
     * 接收一个类型T的参数,给出判断结果。
     */
    boolean test(T t);
​
    /**
     * 先使用外层方法判断,再使用other方法判断,理解为:this&&other
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    
    /**
     * 先使用外层方法判断,将结果值进行取反,理解为:!this
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
​
    /**
     * 先使用外层方法判断,再使用other方法判断,理解为:this||other
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
​
    /**
     * 使用外层方法判断,再和other方法结果进行比较,理解为:this==other
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

代码示例

public static void main(String[] args) {
    // 方法一:普通方法
        Predicate<String> predicate = new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.isEmpty();
            }
        };
        System.out.println(predicate.test("1024"));
​
        // 方法二:lambda表达式
        Predicate<String> predicate2 = (str) -> str.isEmpty();
        System.out.println(predicate2.test(""));
​
        // and 方法
        System.out.println(predicate.and(predicate2).test("1024"));
​
        // or 方法
        System.out.println(predicate.or(predicate2).test("1024"));
​
        // negate 方法
        System.out.println(predicate.negate().test("1024"));
​
        // isEqual 方法
        System.out.println(Predicate.isEqual("1024"));
}

抽象方法: 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

整理:

Consumer T void 接收一个类型T的参数,没有返回值。
Supplier T 不接受任何参数,返回类型T的结果。
Function<T,R> T R 接收一个类型T参数,返回一个类型R的结果。
Predicate T blooean 接收一个类型T的参数,给出判断结果.
posted @ 2021-06-15 23:45  蔚蓝的海洋  阅读(140)  评论(0编辑  收藏  举报