【精选】函数式接口-lambda函数与jdk8自带的函数接口

199 阅读4分钟

目录

写在前面

一、常见写法

二、@FunctionalInterface注解

三、default方法

四、jdk8自带的函数接口(重点)

 Predicate

Consumer

Function

Supplier

BiFunction

jdk提供了很多基本数据类型的类,可以直接使用不需要加泛型

实例


写在前面

本文主要是介绍jdk8自带的函数接口,默认认为读者已经了解或接触过lambda函数基础。

学习jdk8自带的函数接口,主要是为了进一步学习stream流式编程。

在 Java8 中为了让现在有的函数能够更加友好的使用 Lambda 表达式,因此引入了函数式接口这个概念。其是一个仅有一 个抽象方法的普通接口。如果声明多个抽象方法则会报错。 但是默认方法和静态方法在此接口中可以定义多个。

一、常见写法

interface Interface1 {
   int doubleNum(int i);
}

public static void main(String[] args) {
   Interface1 i1 = (i) -> i * 2;

   Interface1 i2 = i -> i * 2;

   Interface1 i3 = (int i) -> i * 2;

   Interface1 i4 = (int i) -> {
      System.out.println("-----");
      return i * 2;
   };

}

二、@FunctionalInterface注解

lambda表达式实现的接口,必须有且仅有一个要实现的方法,使用@FunctionalInterface注解标注之后,如果不符合lambda接口格式,会编译报错。

@FunctionalInterface
public interface MyFunctionalInterface {

    void exec();

}

@Test
public void exec(){

    //jdk8之前
    demo(new MyFunctionalInterface(){

        @Override
        public void exec() {
            System.out.println("jdk8 before");
        }
    });

    //jdk8 lambda
    demo(()-> System.out.println("jdk8 later"));

}

三、default方法

java8可以在接口中编写default默认实现的方法。

若两个接口,都有一个相同的名称、参数的default方法,两个接口被同一个类实现之后,这个类必须要重写这个default方法(编译期就会报错)。

@FunctionalInterface
interface Interface1 {
   int doubleNum(int i);

   default int add(int x, int y) {
      return x + y;
   }
}

四、jdk8自带的函数接口(重点)

在 Java8 的类库设计中,已经引入了几个函数式接口: Predicate、 Consumer 、 Function 、 Supplier,以及这几个的扩展。

jdk提供了很多基本数据类型的类,可以直接使用不需要加泛型:

 

1、Predicate

Predicate 接口是 Java8 定义的一个函数式接口,属于 java.util.function 包下,用于进行判断操作,内部定义一个 抽象方法test 、三个默认方法 and , negate , or 、一个静态方法isEqual。

核心方法:

boolean test(T t);

输入一个任意类型的参数,输出一个boolean类型。

// 将符合条件的学生放入集合中,并将集合最终返回
public class MyPredicateDemo {

    public static List<Student> filter(List<Student> studentList, Predicate<Student> predicate){

        List<Student> list = new ArrayList<>();

        studentList.forEach(s->{

            if (predicate.test(s)){
                list.add(s);
            }
        });

        return list;
    }

    public void demo(){

        int port = 8086;
        Runnable runnable = ()-> System.out.println(port);
    }

    public static void main(String[] args) {

        List<Student> students = new ArrayList<>();
        students.add(new Student(1,"张三","M"));
        students.add(new Student(2,"李四","M"));
        students.add(new Student(3,"王五","F"));

        List<Student> result = filter(students, (s) -> s.getSex().equals("F"));

        System.out.println(result.toString());
    }
}

2、Consumer

Consumer 也是 JDK8 提供的函数式接口,用于进行获取数据 的操作,其内部定义了一个抽象方法accept 、一个默认方法 andThen。

核心方法:

void accept(T t);

输入一个任意类型的参数,无输出。

对于 accept() 方法来说,它接受一个泛型 T 对象。如果现在需要访问类型T 对象,并对其进行某些操作的话,就可以使用这 个接口。

public class MyConsumerDemo {

    public static void foreach(List<String> list, Consumer<String> consumer){

        list.forEach(v->consumer.accept(v));
    }

    public static void main(String[] args) {

        List<String> arrays = new ArrayList<>();
        arrays.add("java");
        arrays.add("python");
        arrays.add("go");
        arrays.add("hive");

        foreach(arrays,(s)-> System.out.println(s+","));
    }
}

3、Function

Function 主要用于进行类型转换的操作。内部提供一个抽象 方法apply 、两个默认方法 compose , andThen 、一个静态 方法identity。

核心方法:

R apply(T t);

输入一个任意类型的参数,输出一个任意类型的参数。

public class MyFunctionDemo {

    public static Integer convert(String value, Function<String,Integer> function){

        return function.apply(value);
    }

    public static void main(String[] args) {

        String value ="666";

        Integer result = convert(value, (s) -> Integer.parseInt(value) + 222);

        System.out.println(result);
    }
}

4、Supplier

Supplier 也是用来进行值获取操作,内部只有一个抽象方法 get。

核心方法:

T get();

无输入参数,输出一个任意类型的参数。

public class MySupplierDemo {

    public static Integer getMin(Supplier<Integer> supplier){

        return supplier.get();
    }

    public static void main(String[] args) {

        int[] arr = {100,20,50,30,99,101,-50};

        Integer result = getMin(() -> {
            int min = arr[0];

            for (int i : arr) {
                if (i < min) {
                    min = i;
                }
            }

            return min;
        });

        System.out.println(result);
    }
}

5、BiFunction

核心方法:

R apply(T t, U u);

输入两个参数,输出一个任意类型的参数。

实例

import java.text.DecimalFormat;
import java.util.function.Function;

class MyMoney {
   private final int money;

   public MyMoney(int money) {
      this.money = money;
   }

    // jdk8自带的接口,Integer为入参,String为出参
   public void printMoney(Function<Integer, String> moneyFormat) {
      System.out.println("我的存款:" + moneyFormat.apply(this.money));
   }
}

public class MoneyDemo {

   public static void main(String[] args) {
      MyMoney me = new MyMoney(99999999);

      Function<Integer, String> moneyFormat = i -> new DecimalFormat("#,###")
            .format(i);
      // 函数接口链式操作
      me.printMoney(moneyFormat.andThen(s -> "人民币 " + s));
   }

}

// 执行结果:
// 我的存款:人民币 99,999,999
public static void main(String[] args) {
   // 断言函数接口
   IntPredicate predicate = i -> i > 0;
   System.out.println(predicate.test(-9));

   // IntConsumer,jdk中自带一些基本数据类型的,就不需要写泛型了
   // 消费函数接口
   Consumer<String> consumer = s -> System.out.println(s);
   consumer.accept("输入的数据");
}