JDK8内置函数式接口(三)

418 阅读4分钟

内置函数式接口的由来

我们知道使用Lambda表达式的前提是需要有函数式接口.而Lambda表达式使用时不关心接口名,抽象方法名,只关心抽象方法的参数列表和返回值类型.因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口.

常用的内置函数式接口介绍

他们主要在java.util.function包中,下面是常用的几个接口

  1. Supplier接口 - 供给型接口,没有参数但是有返回值

SupplierFunction 不同,它不接受入参,直接为我们生产一个指定的结果,有点像生产者模式

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

供给型接口,通过Supplier接口中的get()方法可以得到一个值,无参有返回值的接口。

public class Demo3UseFunctionInterface {
    public static void main(String[] args) {
        test((int a, int b) -> {
            System.out.println(a + b);
        });
    }

    public static void test(Operation operation) {
        operation.getSum(1, 3);
    }
}

interface Operation {
    public abstract void getSum(int a, int b);
}

使用Supplier接口作为方法参数类型,通过lambda表达式求出int数组中的最大值。

  //使用lambda表达式返回数组最大元素
    public static void main(String[] args) {
        System.out.println("开始了");
        printMax(()->{
       	    System.out.println("步骤2");
            int [] arr = {11,2,3,45,54,99};
	    Arrays.sort(arr);
            return arr[arr.length-1];
        });
    }

    private static void printMax(Supplier<Integer> supplier){
        System.out.println("步骤1");
        int max = supplier.get();
        System.out.println("max:"+ max);
    }

执行步骤:

  1. 先执行main()开始了,输出开始了

  2. 执行printMax(),输出步骤1

  3. 执行步骤supplier.get() 实际是执行printMax()里的实现方法,输出步骤2 3.最后执行main的剩余代码,输出99

  4. Consumer接口 - 消费性接口 有参数但是没有返回值

对于 Consumer,我们需要提供入参,用来被消费

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
public static void main(String[] args) {
   System.out.println("开始了");
   printMax((String str)->{
       System.out.println(str.toUpperCase());
   });
}

private static void printMax(Consumer<String> consumer){
    System.out.println("aa");
    consumer.accept("hello world");
}

默认方法: andThen

如果一个方法的参数和返回值全都是comsumer类型,那么就可以实现效果:消费一个数据的时候,首先做一个操作,然后在做一个操作,实现组合。而这个方法就是comsumer接口中的default方法andThen

 public static void main(String[] args) {
        System.out.println("开始了");
        printMax((String str)->{
            System.out.println(str.toLowerCase());
        },(String str)->{
            System.out.println(str.toUpperCase());
        });
    }

    private static void printMax(Consumer<String> consumer1,Consumer<String> consumer2){
        System.out.println("aa");
        String str = "Hello World";
       // consumer1.accept(str);
       // consumer2.accept(str);
        consumer1.andThen(consumer2).accept(str);
    }
  1. Function 接口

Function 函数式接口的作用是,我们可以为其提供一个原料,他给生产一个最终的产品。通过它提供的默认方法,组合,链行处理(compose, andThen):

 @FunctionalInterface
 public interface Function<T, R> {
    R apply(T t);
 }
    public static void main(String[] args) {
        System.out.println("开始了");
        getNum((String str) -> {
            return Integer.parseInt(str);
        }, (Integer integer) -> {
            return integer * 5;
        });
    }

    private static void getNum(Function<String, Integer> function1, Function<Integer, Integer> function2) {
        System.out.println("aa");
        Integer num1 = function1.andThen(function2).apply("20");
       // Integer num2 = function2.apply(num1);
        System.out.println("num1= " + num1);
    }
  1. Predicate断言

Predicate 是一个可以指定入参类型,并返回 boolean 值的函数式接口。它内部提供了一些带有默认实现的方法,可以 被用来组合一个复杂的逻辑判断(and, or, negate

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}
    public static void main(String[] args) {
        idLongName((String name) ->{
           return name.length()>3;
        });

    }

    public static void idLongName (Predicate<String> predicate){
        System.out.println("aa");
        boolean isLong = predicate.test("迪丽热巴");
        System.out.println(isLong);
    }

方法引用

方法引用的格式

符号表示: ::

符号说明: 双冒号为方法引用运算符,而他所在的表达式被称为方法引用

应用场景: 如果Lambda所要实现的方案,已经有其它方法存在的相同方案,那么可以使用方法引用

常用引用方式

方法引用在JDK8中使用方式相当灵活,有一下几种形式

  1. instanceName :: methodName 对象::方法名
  2. ClassName :: staticMethodName 类名:: 静态方法
  3. ClassName :: methodName 类名:: 普通方法
  4. ClassName :: new 类名 :: new 调用构造器
  5. TypeName [] :: new String ::new 调用数组的构造器

对象名 :: 引用成员方法

 public void test01(){
        Date now = new Date();

        Supplier<Long> su1 = ()->{
            return now.getTime();
        };
        Supplier<Long> su2  =now:: getTime;
        Long aLong = su1.get();
        System.out.println("aLong="+aLong);
    }

方法引用有2个注意事项

  1. 被引用的方法,参数要和接口抽象方法的参数一样
  2. 当接口抽象方法有返回值时,被引用的方法也必须有返回值

类名 :: 引用静态方法

  public void test02(){
        Supplier<Long> su1 = ()->{
            return System.currentTimeMillis();
        };
        Long aLong = su1.get();
        System.out.println("aLong="+aLong);

        Supplier<Long> su2  =System::currentTimeMillis;
        Long aLong2 = su2.get();
        System.out.println("aLong2="+aLong2);
    }

类名 :: 实例方法

 public static void test03(){
        Function<String,Integer> su1 = (String str)->{
            return str.length();
        };
        Integer count = su1.apply("hello");
        System.out.println("count="+count);

        //类名:: 实例方法(注意: 类名::实例方法 实例方法实际上会将第一个参数作为方法的调用者)
        Function<String,Integer> su2  =String::length;
        Integer count2 = su2.apply("hello");
        System.out.println("count2="+count2);

        //类名:: 实例方法(注意: 类名::实例方法 实例方法实际上会将第一个参数作为方法的调用者)
        //BiFunction<String,Integer,String> bif2  =String::substring;
        BiFunction<String,Integer,String> bif2 = (String str,Integer index) ->{
                return str.substring(index);
        };
        String str2= bif2.apply("helloword",3);
        System.out.println("str2="+str2);
    }

类名:: new 引用类的构造器

public static void test04(){

        Supplier<Person> person = ()->{
            return new Person();
        };
       // Supplier<Person> person = Person::new;
        Person person1 = person.get();
        System.out.println("person1="+person1);
  
        BiFunction<String,Integer,Person> bif = (String name,Integer age) ->{
            return new Person(name,age);
        };
        //BiFunction<String,Integer,Person> bif =  Person:: new;
        Person p2 = bif.apply("刘新", 29);
        System.out.println("p2="+p2);

    }

数组::new 引用数组构造器

数组也是object 的子类对象,所以同样具有构造器,只是语法稍有不同

public static void test05(){

        Function<Integer,int [] > f1 = (Integer index)->{
            return new int[index];
        };
        //Function<Integer,int [] > f1 = int[]::new;
        int[] arr = f1.apply(10);
        System.out.println("arr="+arr);

    }