---
url: /notes/java-se/函数式接口/index.md
---
# 函数式接口

**有且只有一个公开抽象方法的接口**
还包括默认方法，静态和私有的

即适用于函数式编程场景的接口。函数式编程的体现：lambda表达式

所以函数式接口就是可以适用于lambda表达式的接口，java中的lambda才可以顺利的进行推导

# 语法糖

是指使用更方便，但原理不变的代码语法
比如：遍历集合时使用的增强for循环

# 函数式接口对应注解

```Java
@FunctionalInterface
可以检查该接口是否是函数式接口
```

# 函数式接口使用方式

一般可以用方法的参数作为返回值

```java
@FunctionalInterface
public interface MyInterface {
    public void come();
}

public static void main(String[] args) {
        show(new MyInterface() {
            @Override
            public void come() {
                System.out.println("调用函数式接口");
            }
        });

        // lambda
        show(()->{
            System.out.println("调用函数式接口");
        });
        //{}省略
        show(()->System.out.println("调用函数式接口"));
    }
    public static void show(MyInterface myInterface){
        myInterface.come();
    }
```

## 拼接字符串操作

发现代码性能浪费的问题调用showlog方法时，传递第二个参数是一个拼接的字符的串运行时会先进行字符的拼接, 然后调用showLog方法如果该方法传递的参数不是1的时候，那么就会发现拼接的字符没有用到白白浪费性能

```java
public static void main(String[] args) {
        String msg1 = "hello";
        String msg2 = "world";
        String msg3 = "hahah";

        //调用日志方法，传递参数
        showLog(1, msg1 + msg2 + msg3);
    }

    // 拼接日志信息
    public static void showLog(int level, String msg) {
        if (level == 1) {
            System.out.println(msg);
        }
    }
```

使用lambda表达式作为参数传递的时候，仅仅是把参数传递到showLog方法中只有满足Level为1时	才会调用接CMyBuilder接口中buiIderMsg方法	才会有字符拼接的功能如果条件不满足时	那么接口MyBuilder接口中builderMsg方法不会执行	不会有字符串的拼接所以性能不会浪费

```java
public static void main(String[] args) {
        String msg1 = "hello";
        String msg2 = "world";
        String msg3 = "hahah";
    
        showLog(1, () -> {
            System.out.println("如果方法满足就执行");
            return msg1 + msg2 + msg3;
        });

        showLog(2, () -> {
            System.out.println("如果方法不满足就不执行");
            return msg1 + msg2 + msg3;
        });
    }

    private static void showLog(int level, MyInterface myInterface) {
        if (level == 1) {
            myInterface.builderMsg();
        }
    }
```

![image-20211124224030888](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224030888.png)

## 使用Lambda进行性能的优化

`Lambda的特点`：**延时加载**
Lambda的使用前提：必须要使用函数式接口

## Runnable接口使用Lambda表达式

列如Runnable接口就是一-个函数式接口假设有一个方法使用该接口作为参数，那么我们就可以使用Lambda进行参数传递这种情况其实和Thread类的构造方法参数为Runnable没有本质的区别

```java
public static void main(String[] args) {
         startThread(new Runnable() {
             @Override
             public void run() {
                 System.out.println("使用匿名内部类调用线程");
             }
         });

         startThread(()->{
             System.out.println("使用Lambda表达式调用线程");
         });


    }
    public static void startThread(Runnable runnable){
        new Thread(runnable).start();
    }
```

## 字符串数组比较

```java
public static void main(String[] args) {
        String[] str={"dq2f","话费","dwegrw","hf90wu"};
        Arrays.sort(str,getComparator());
        System.out.println(Arrays.toString(str));

    }
    private static Comparator<String> getComparator(){
        // (1)
        return new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length()-o2.length();
            }
        };
        
        // (2)
        return (String o1,String o2)->{
            return o1.length()-o2.length();
        };
    
        // (3)
        return (o1,o2)-> o1.length()-o2.length();
        
        // (4)
        return Comparator.comparingInt(String::length);
    }
```

# 常用函数式接口

`java.util.Function`

## `Supplier`

`@FunctionalInterface`
`public interface Supplier<T>` 称为**生产型接口** ，指定接口的类型
指定接口的泛型是什么类型，该接口中的方法就能返回什么类型的数据

### 抽象方法`get`

`T get()`
用来获取一个泛型的参数指定类型的对象数据

```java
public static void main(String[] args) {
        getStr(() -> "hello" + "world");
    }

    public static String getStr(Supplier<String> stringSupplier) {
        return stringSupplier.get();
    }
```

### 求数组最大值

```java
public static void main(String[] args) {
        int[] arr = {34, 6, 78};
        getArrMax(() -> {
            int max = arr[0];
            for (int i : arr) {
                if (i > max) {
                    max = i;
                }
            }
            return max;
        });
        
    }

    private static Integer getArrMax(Supplier<Integer> supplier) {
        return supplier.get();
    }
```

## Consumer

`@FunctionalInterface`
`public interface Consumer<T>`
**消费者接口** ，泛型是什么类型，就可以使用accept方法消费什么类型的数据
至于怎么使用定义，可以计算，输出

### 抽象方法`accept`

`void accept(T t)`
对给定的参数执行此操作。

### 反转字符串

```java
public static void main(String[] args) {
        method("abcd",(name)->{
            String str=new StringBuilder(name).reverse().toString();
            System.out.println(str);
        });
    }
    public static void method(String name, Consumer<String> consumer){
        consumer.accept(name);
    }
```

### 默认方法`andThen`

`default Consumer<T> andThen(Consumer<? super T> after)`

需要两个Consumer接口，可以把Consumer接口组合到一起，对数据进行消费

![image-20211124224047282](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224047282.png)

```java
public static void main(String[] args) {
        // 让给定的字符串可以大写也可以小写
        String str="Hello";
        show(str,
                (name)-> System.out.println(name.toUpperCase()),
                (name)-> System.out.println(name.toLowerCase()));
    }
    public static void show(String name, Consumer<String> con1,Consumer<String> con2){
        con1.andThen(con2).accept(name);
    }
```

```java
package com.fac.demo5;

import java.util.function.Consumer;

/**
 * @Description TODO
 * @Classname Cousumer3
 * @Date 2021/8/19 11:46
 * @Created by 折腾的小飞
 */
public class Cousumer3 {
    public static void main(String[] args) {
//        String[] peoplename = {"张三", "男", "李四", "女"};
        String[] peoplename = {"张三,男", "李四,女"};
        show(peoplename,
                (name)->{
//                    System.out.println("姓名："+name);
                    System.out.println("姓名："+name.split(",")[0]);
                },
                (gender)->{
//                    System.out.println("性别："+gender);
                    System.out.println("性别："+gender.split(",")[1]);
                });
    }
    private static void show(String[] str, Consumer<String> con1,Consumer<String> con2){
        for (String s : str) {
            con1.andThen(con2).accept(s);
        }
        for (int i = 0; i < str.length; i++) {
            if (i%2==0){
                con1.accept(str[i]);
            }else{
                con2.accept(str[i]);
            }
        }
    }
}
```

![image-20211124224058682](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224058682.png)

## `Predicate`

`@FunctionalInterface`
`public interface Predicate<T>`
作用：对某种数据类型的数据进行一个判断，结果返回boolean

### 抽象方法`test`

`boolean test(T t)`用来对指定数据类型数据的判断
结果：符合条件就是true，不符合就是false

```java
public static void main(String[] args) {
        String str="bdfuiegb从吃完饭";
        boolean b = checkLength(str, (s) ->
            s.length() > 10
        );
        System.out.println(b);
    }
    public static boolean checkLength(String s, Predicate<String> predicate){
        return predicate.test(s);
    }
```

### 默认方法

逻辑表达式：可以连接多个判断条件
相当于逻辑运算关系：
`&&`：`default Predicate<T> and(Predicate<? super T> other)`
`||`：`default Predicate<T> or(Predicate<? super T> other)`
`!`：`default Predicate<T> negate()`

### 静态方法

`==`：`static <T> Predicate<T> isEqual(Object targetRef)`

```java
// 判断大于10且包含k
public static void main(String[] args) {
        String str = "g8dgf";
        checkString(
                s -> s.length() > 10,
                s -> s.contains("k"),
                str);
    }

    public static boolean checkString(Predicate<String> pr1, Predicate<String> pr2, String str) {
        return pr1.and(pr2).test(str); // pr1.test(str)&&pr2.test(str)
    }
```

```java
//// 判断大于10或者包含k
public static void main(String[] args) {
        String str = "hoifho";
        boolean b = isAccord(s -> s.length() > 10,
                s -> s.contains("k"), str);
        System.out.println(b);
    }

    private static boolean isAccord(Predicate<String> pre1, Predicate<String> pre2, String s) {
        return pre1.or(pre2).test(s);
    }
```

```java
//筛选女生且名字等于4个字
public static void main(String[] args) {
        String[] strName = {"欧阳拉拉,女", "杨洋,男", "司樊登,男", "迪丽热巴,女", "杨幂,女"};
        HashSet<String> set=check(
                strName,
                s->s.split(",")[1].equals("女"),
                s->s.split(",")[0].length()>=4
        );
        System.out.println(set);
    }

    private static HashSet<String> check(String[] s, Predicate<String> pre1, Predicate<String> pre2) {
        HashSet<String> set=new HashSet<>();
        for (String s1 : s) {
            if(pre1.and(pre2).test(s1)){
                set.add(s1);
            }
        }
        return set;
    }
```

## Function

`@FunctionalInterface]`
`public interface Function<T,R>`
用来根据一个类型的数据得到另一个类型的数据
前者称为前置条件，后者称为后置条件

### 抽象方法`apply`

`R apply(T t)`
根据类型T的参数获取类型R的结果
使用场景：String类型的数据转换为Integer类型

### 默认方法

`default <V> Function<T,V> andThen(Function<? super R,? extends V> after)`
相当于进行两次转换

```java
public static void main(String[] args) {
        String str = "30";
        IntConversionStr(str,s -> Integer.valueOf(s)+50,s->String.valueOf(s));
    }

    public static void IntConversionStr(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {
//        Integer applyInt = fun1.apply(s);
//        System.out.println(applyInt);
//        String applyStr = fun2.apply(applyInt);
//        System.out.println(applyStr);
        String apply = fun1.andThen(fun2).apply(s);
        System.out.println(apply);
    }
```

# 方法引用​

```java
package com.fac.Work8_19.Test11;

/**
 * @Description TODO
 * @Classname Student
 * @Date 2021/8/19 21:19
 * @Created by 折腾的小飞
 */
public class Student {
    private String name;
    private int score;

    public Student() {
    }

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}

public static void main(String[] args) {
        ArrayList<Student> list=new ArrayList();
        Collections.addAll(
                list,
                new Student("谢霆锋",85),
                new Student("章子怡",63),
                new Student("刘亦菲",77),
                new Student("黄晓明",33),
                new Student("岑小村",92)
                );
        // 从小到大，升序 匿名内部类
        Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student student, Student t1) {
                return student.getScore()-t1.getScore();
            }
        });
        System.out.println(list);

        // 从大到小，降序 Lambda表达式
        Collections.sort(list,(o1,o2)->{
            return o2.getScore()-o1.getScore();
        });
        System.out.println(list);

        // 方法引用
        Collections.sort(list,Comparator.comparingInt(Student::getScore)); // 升序
        System.out.println(list);

        Collections.sort(list,Comparator.comparingInt(Student::getScore).reversed()); // 降序
        System.out.println(list);

    }
```
