函数式接口

函数式编程

# 函数式接口

# 一、概述

# 1.1、什么是函数式接口?

只有一个抽象方法的接口我们称之为函数接口。

JDK的函数式接口都加上了**@FunctionalInterface** 注解进行标识。

但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口。

jdk自带的一些常用的一些接口Callable、Runnable、Comparator等在JDK8中都添加了@FunctionalInterface注解。

# 1.2、FunctionalInterface注解说明

  1. 该注解只能标记在"有且仅有一个抽象方法"的接口上。
  2. JDK8接口中的静态方法和默认方法,都不算是抽象方法。
  3. 接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
  4. 该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。
  5. 为了规范,建议给所有需要使用函数式编程的接口都加上注解。

# 二、自定义函数式接口

只有一个抽象方法的情况

@FunctionalInterface
public interface MyInterface {
    
    int test(int i);
}
1
2
3
4
5

有多个方法,但只有一个抽象方法,其他方法有默认实现

@FunctionalInterface
public interface MyInterface {

    int test(int i);

    default int add(int a, int b) {
        return a + b;
    }

    default void sum(int a, int b) {
        System.out.println("sum:" + a + b);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

使用一下,看看效果

public static void main(String[] args) {
    // 使用lombda实现test方法
    MyInterface myInterface = i -> i*2;
    
    // 调用刚刚实现的方法
    System.out.println(myInterface.test(22));
    
    // 调用默认重写的方法
    System.out.println(myInterface.add(10,20));
    myInterface.sum(100,20);
}
1
2
3
4
5
6
7
8
9
10
11

结果

44
30
sum:10020
1
2
3

# 三、JDK自带函数式接口

大多数情况下我们不需要自己去撰写函数式接口,因此jdk自带的函数接口应该是日常开发中,使用频率最高的函数式接口了,这里已经整理成表格的形式方便后续查阅使用。

接口 输入参数 返回类型 使用说明
Predicate T boolean 断言
Consumer T / 消费一个数据
Function T R 输入T输出R的函数
Supplier / T 提供一个数据
UnaryOperator T T 一元函数(输入输出类型相同)
BiFunction (T,U) R 两个输入的函数
BinaryOperator (T,T) T 二元函数(输入输出类型相同)

# 3.1、Consumer 消费接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数进行消费。

image-20211028145622163

# 3.2、Function 计算转换接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数计算或转换,把结果返回

image-20211028145707862

# 3.3、Predicate 判断接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数条件判断,返回判断结果

image-20211028145818743

# 3.4、Supplier 生产型接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中创建对象,把创建好的对象返回

image-20211028145843368

# 3.5、使用

public static void main(String[] args) {
    // 断言
    Predicate<Integer> predicate = i -> i > 0;
    System.out.println(predicate.test(-1));

    // 消费
    Consumer<String> consumer = s -> System.out.println(s);
    consumer.accept("张三");

    // 输入T输出R
    Function<Integer, String> function = i -> i >= 0 ? "正数" : "负数";
    function.apply(7);

    // 提供一个数据
    Supplier<String> stringSupplier = () -> "测试";
    System.out.println(stringSupplier.get());

    // 一元函数
    UnaryOperator<String> unaryOperator = s -> "处理后" + s;
    System.out.println(unaryOperator.apply("Test"));

    // 两个输入的函数
    BiFunction<String,Boolean,Integer> biFunction = (s, b) -> {
        // 如果b为true,返回0;如果s为test返回1,否则返回-1
        if (b){
            return 0;
        }
        if ("test".equals(s)){
            return 1;
        }
        return -1;
    };
    System.out.println(biFunction.apply("test", false));

    // 二元函数
    BinaryOperator<String> binaryOperator = (s, s2) -> s+s2;
    System.out.println(binaryOperator.apply("雷军", "666"));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

结果

false
张三
测试
处理后Test
1
雷军666
1
2
3
4
5
6

# 四、常用的默认方法

  • and

    我们在使用Predicate接口时候可能需要进行判断条件的拼接。而and方法相当于是使用&&来拼接两个判断条件

    例如:

    打印作家中年龄大于17并且姓名的长度大于1的作家。

    List<Author> authors = getAuthors();
    Stream<Author> authorStream = authors.stream();
    authorStream.filter(new Predicate<Author>() {
        @Override
        public boolean test(Author author) {
            return author.getAge()>17;
        }
    }.and(new Predicate<Author>() {
        @Override
        public boolean test(Author author) {
            return author.getName().length()>1;
        }
    })).forEach(author -> System.out.println(author));
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  • or

    我们在使用Predicate接口时候可能需要进行判断条件的拼接。而or方法相当于是使用||来拼接两个判断条件。

    例如:

    打印作家中年龄大于17或者姓名的长度小于2的作家。

    //        打印作家中年龄大于17或者姓名的长度小于2的作家。
    List<Author> authors = getAuthors();
    authors.stream()
        .filter(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getAge()>17;
            }
        }.or(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getName().length()<2;
            }
        })).forEach(author -> System.out.println(author.getName()));
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • negate

    Predicate接口中的方法。negate方法相当于是在判断添加前面加了个! 表示取反

    例如:

    打印作家中年龄不大于17的作家。

    //        打印作家中年龄不大于17的作家。
    List<Author> authors = getAuthors();
    authors.stream()
        .filter(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getAge()>17;
            }
        }.negate()).forEach(author -> System.out.println(author.getAge()));
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
最近修改于: 2025/2/9 23:54:19
和宇宙温柔的关联
房东的猫