函数式接口(Functional Interface)

函数式接口(Functional Interface)

简介

它是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。

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

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

public class GreetingDemo {
    @FunctionalInterface
    interface GreetingInterface {
        void sayMessage(String message);
    }

    public static void main(String[] args) {
        GreetingInterface greetingInterface = message -> {
            System.out.println("Hello " + message);
        };
        greetingInterface.sayMessage("Tom");
    }
}

输出即为:Hello Tom

function包下的函数式接口

java.util.function 它包含了很多类,用来支持 Java的 函数式编程,该包中的函数式接口有

序号接口 & 描述
1BiConsumer<T,U> 代表了一个接受两个输入参数的操作,并且不返回任何结果
2BiFunction<T,U,R> 代表了一个接受两个输入参数的方法,并且返回一个结果
3BinaryOperator 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
4BiPredicate<T,U> 代表了一个两个参数的boolean值方法
5BooleanSupplier 代表了boolean值结果的提供方
6Consumer 代表了接受一个输入参数并且无返回的操作
7DoubleBinaryOperator 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。
8DoubleConsumer 代表一个接受double值参数的操作,并且不返回结果。
9DoubleFunction 代表接受一个double值参数的方法,并且返回结果
10DoublePredicate 代表一个拥有double值参数的boolean值方法
11DoubleSupplier 代表一个double值结构的提供方
12DoubleToIntFunction 接受一个double类型输入,返回一个int类型结果。
13DoubleToLongFunction 接受一个double类型输入,返回一个long类型结果
14DoubleUnaryOperator 接受一个参数同为类型double,返回值类型也为double 。
15Function<T,R> 接受一个输入参数,返回一个结果。
16IntBinaryOperator 接受两个参数同为类型int,返回值类型也为int 。
17IntConsumer 接受一个int类型的输入参数,无返回值 。
18IntFunction 接受一个int类型输入参数,返回一个结果 。
19IntPredicate :接受一个int输入参数,返回一个布尔值的结果。
20IntSupplier 无参数,返回一个int类型结果。
21IntToDoubleFunction 接受一个int类型输入,返回一个double类型结果 。
22IntToLongFunction 接受一个int类型输入,返回一个long类型结果。
23IntUnaryOperator 接受一个参数同为类型int,返回值类型也为int 。
24LongBinaryOperator 接受两个参数同为类型long,返回值类型也为long。
25LongConsumer 接受一个long类型的输入参数,无返回值。
26LongFunction 接受一个long类型输入参数,返回一个结果。
27LongPredicate R接受一个long输入参数,返回一个布尔值类型结果。
28LongSupplier 无参数,返回一个结果long类型的值。
29LongToDoubleFunction 接受一个long类型输入,返回一个double类型结果。
30LongToIntFunction 接受一个long类型输入,返回一个int类型结果。
31LongUnaryOperator 接受一个参数同为类型long,返回值类型也为long。
32ObjDoubleConsumer 接受一个object类型和一个double类型的输入参数,无返回值。
33ObjIntConsumer 接受一个object类型和一个int类型的输入参数,无返回值。
34ObjLongConsumer 接受一个object类型和一个long类型的输入参数,无返回值。
35Predicate 接受一个输入参数,返回一个布尔值结果。
36Supplier 无参数,返回一个结果。
37ToDoubleBiFunction<T,U> 接受两个输入参数,返回一个double类型结果
38ToDoubleFunction 接受一个输入参数,返回一个double类型结果
39ToIntBiFunction<T,U> 接受两个输入参数,返回一个int类型结果。
40ToIntFunction 接受一个输入参数,返回一个int类型结果。
41ToLongBiFunction<T,U> 接受两个输入参数,返回一个long类型结果。
42ToLongFunction 接受一个输入参数,返回一个long类型结果。
43UnaryOperator 接受一个参数为类型T,返回值类型也为T。

几种常见的函数式接口

Consumer

Represents an operation that accepts a single input argument and returns no result.
源码如下,

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

使用方法示例如下,

import java.util.function.BiConsumer;
import java.util.function.Consumer;

public class ConsumerDemo {
    public static void main(String[] args) {
        Consumer<String> f = System.out::println;
        Consumer<String> f2 = n -> System.out.println(n + "F2");

        // 执行完f后再执行f2的Accept方法
        f.andThen(f2).accept("test");

        // 连续执行f2的Accept方法
        f2.andThen(f2).andThen(f2).accept("test1");

        BiConsumer<String, String> f3 = (x, y) -> System.out.println(x + "," + y);
        f3.accept("x=5", "y=6");
    }
}

输出结果如下,
在这里插入图片描述

Function

Represents a function that accepts one argument and produces a result.
源码如下,

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
    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;
    }
}

使用示例如下,

import java.util.function.BiFunction;
import java.util.function.Function;

public class FunctionDemo {
    public static void main(String[] args) {
        Function<Integer, Integer> f = s -> ++s;
        Function<Integer, Integer> g = s -> s * 2;

        // 先执行g再执行f,3*2 +1 = 7
        System.out.println(f.compose(g).apply(3));
        // 先执行f再执行g,(3+1)*2 = 8
        System.out.println(f.andThen(g).apply(3));
        // identify方法会返回一个不进行处理的Function,即输出和输入值相等
        System.out.println(Function.identity().apply("a"));

        // 泛型中第一个第二个为输入类型,第三个为输出类型
        BiFunction<String, String, Integer> biFunction = (x, y) -> Integer.parseInt(x) + Integer.parseInt(y);
        System.out.println(biFunction.apply("51", "94"));
    }
}

输出结果如下,
在这里插入图片描述

Predicate

Represents a predicate (boolean-valued function) of one argument.
源码如下,

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

使用示例如下,

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Assert;

import java.util.function.Predicate;
import java.util.stream.Stream;

public class PredicateDemo {
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Data
    static class Gift {
        private String name;
        private int price;
    }

    public static void main(String[] args) {
        Predicate<String> p = "test"::equals;
        Predicate<String> g = o -> o.startsWith("t");
        // negate:用于对原来的Predicate做取反处理;
        Assert.assertFalse(p.negate().test("test"));
        // 针对同一个输入值,多个Predicate均返回true时返回true,否则返回false
        Assert.assertTrue(p.and(g).test("test"));
        // 针对同一个输入值,多个Predicate只要有一个返回true则返回true,否则返回false
        Assert.assertTrue(p.or(g).test("test"));

        Gift exceptGift = new Gift("Ps4", 1000);
        Predicate<Gift> predicate = Predicate.isEqual(exceptGift);
        System.out.println(
                Stream.of(
                        Gift.builder().name("egg").price(1).build(),
                        Gift.builder().name("apple").price(3).build(),
                        Gift.builder().name("Ps4").price(1000).build(),
                        Gift.builder().name("banana").price(2).build(),
                        Gift.builder().name("Ps4").price(1000).build(),
                        Gift.builder().name("belt").price(20).build(),
                        Gift.builder().name("Ps4").price(1000).build(),
                        Gift.builder().name("book").price(50).build()
                ).filter(predicate).count()
        );
    }
}

Supplier

Represents a supplier of results.
源码如下,

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

Supplier看起来应该是最简单的一个函数式接口,下面看看怎么用它,

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.function.Supplier;

public class SupplierDemo {
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Data
    static class Product {
        private String name;

        private String expiration = currentDateTime();
    }

    public static void main(String[] args) {
        Supplier<Product> supplier = Product::new;
        System.out.println(supplier.get().expiration);
    }

    private static String currentDateTime() {
        long millis = System.currentTimeMillis();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
        return format.format(millis);
    }
}

输出结果如下,
在这里插入图片描述

总结

上面介绍了几个简单的函数式接口以及该函数式接口如何使用,引入函数式接口在一定程度上可以提高编码效率,使用过程也更加简便。需要开发者自行熟悉。

如果感兴趣的可以思考一下函数式接口在效率上是否更快呢?

可以先去查看编译后的class文件,以上面的ConsumerDemo为例,对应的ConsumerDemo.class文件代码如下,

package com.hust.zhang.functional;

import java.io.PrintStream;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

public class ConsumerDemo {
    public ConsumerDemo() {
    }

    public static void main(String[] args) {
        PrintStream var10000 = System.out;
        Consumer<String> f = var10000::println;
        Consumer<String> f2 = (n) -> {
            System.out.println(n + "F2");
        };
        f.andThen(f2).accept("test");
        f2.andThen(f2).andThen(f2).accept("test1");
        BiConsumer<String, String> f3 = (x, y) -> {
            System.out.println(x + "," + y);
        };
        f3.accept("x=5", "y=6");
    }
}

再使用javap -c ConsumerDemo.class反编译class文件看看源码如下,

public class com.hust.zhang.functional.ConsumerDemo {
  public com.hust.zhang.functional.ConsumerDemo();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: dup
       4: invokevirtual #3                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
       7: pop
       8: invokedynamic #4,  0              // InvokeDynamic #0:accept:(Ljava/io/PrintStream;)Ljava/util/function/Consumer;
      13: astore_1
      14: invokedynamic #5,  0              // InvokeDynamic #1:accept:()Ljava/util/function/Consumer;
      19: astore_2
      20: aload_1
      21: aload_2
      22: invokeinterface #6,  2            // InterfaceMethod java/util/function/Consumer.andThen:(Ljava/util/function/Consumer;)Ljava/util/function/Consumer;
      27: ldc           #7                  // String test
      29: invokeinterface #8,  2            // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V
      34: aload_2
      35: aload_2
      36: invokeinterface #6,  2            // InterfaceMethod java/util/function/Consumer.andThen:(Ljava/util/function/Consumer;)Ljava/util/function/Consumer;
      41: aload_2
      42: invokeinterface #6,  2            // InterfaceMethod java/util/function/Consumer.andThen:(Ljava/util/function/Consumer;)Ljava/util/function/Consumer;
      47: ldc           #9                  // String test1
      49: invokeinterface #8,  2            // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V
      54: invokedynamic #10,  0             // InvokeDynamic #2:accept:()Ljava/util/function/BiConsumer;
      59: astore_3
      60: aload_3
      61: ldc           #11                 // String x=5
      63: ldc           #12                 // String y=6
      65: invokeinterface #13,  3           // InterfaceMethod java/util/function/BiConsumer.accept:(Ljava/lang/Object;Ljava/lang/Object;)V
      70: return
}

参考链接:https://www.runoob.com/java/java8-functional-interfaces.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值