01)JDK1.8 新特性学习 Lambda 函数式接口 方法引用

目录

1.Lambda

1.1 lambda表达式的使用前提

1.2 lambda和匿名内部类的对比

1.2 lambda语法练习  LambdaTest.class

2.函数式接口

2.1 Consumer :消费型接口,有参无返回值

2.2 Supplier:供给型接口,无参有返回值 T为返回值

2.3  Function::函数式接口,有参有返回值 应该是使用最多的

2.4 Predicate: 断言型接口,有参有返回值,返回值是boolean类型

3.方法引用

3.1构造器引用 ClassName::new 就是在函数式接口中简化 new Instance();

3.2  方法引用demo object::method 就是在函数式接口中简化 object.mothod();

3.3 数组引用 Type[]::new ..也是满足函数式接口才能使用的 相当于new String[x]


JDK1.8 新特性学习

学之前先网上抄一段什么是函数式编程?因为jdk1.8的lambda 函数式接口 方法引用都是围绕函数式编程来的

首先,什么是函数式编程,引用廖雪峰先生的教程里面的解释就是说:函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

简单的来说就是,函数也是一等公民了,在java里面一等公民有变量,对象,那么函数式编程语言里面函数也可以跟变量,对象一样使用了,也就是说函数既可以作为参数,也可以作为返回值了。

1.Lambda

1.1 lambda表达式的使用前提

lambda的语法是非常简洁的,但是lambda不是可以随便使用的,使用条件为以下2点

1.方法的参数,或者局部变量的类型必须为接口

2.接口中有且仅有一个抽象方法 ,接口上有@FunctionalInterface的肯定满足条件

1.2 lambda和匿名内部类的对比

1.所需类型不一样

(1.1)匿名内部类的类型可以的类,抽象类,接口

(1.2)lambda需要的类型必须是接口

2.抽象方法的数量不一样

(2.1)匿名内部类所需的接口中的抽象方法是可以任意个,匿名内部类全实现即可

(2.2)lambda表达式所需接口中的抽象方法只能有1个

3.实现原理不一样

(3.1)匿名内部类是在编译后生成一个class,(我们编译后,没运行时编译目录就多了一个$calss)

(3.2)lambda是在程序运行时动态生成class(jdk自带javap的反解析工具可查看)

 
 /*UserEntiry userEntiry=  getUser(new Supplier<UserEntiry>() {
            @Override
            public UserEntiry get() {
                return null;
            }
        });*/

        //生产UserEntiry , Supplier<T>为函数式接口 直接使用Lambda语法 我们只关注重写Supplier get方法里的逻辑,而new  Supplier<UserEntiry>
        /**
         * 生产UserEntiry , Supplier<T>为函数式接口 直接使用Lambda语法 我们只关注重写Supplier get方法里的逻辑,而
         * new Supplier<UserEntiry>()
         *  @Override
         *   public UserEntiry get() {
         *
         *   }
         *   这种匿名内部类多余的代码都能省略掉 有用的就是{}中的代码
         */


 /** 匿名内部类写法我们单独写一个匿名内部类 不指向任何目标也不会报错
         *   new AInterface() {
         *             @Override
         *             public String getName() {
         *                 return "第二种方式 匿名内部类写法,定义一个匿名类 传入构造器";
         *             }
         *
         *         };
         *
         *   而lambda 单独这样写是会报错的 因为没有目标,根本无法知道他是哪个匿名内部类的实现
         *   ()-> {
         *             return "第三种方式 lambda写法";
         *         };
         *      必须 把它放到方法入参中,蚕食为函数接口
         *       new LambdaTest(()-> {
         *             return "第三种方式 lambda写法";
         *         }).run();
         *         或者赋值给一个函数式接口
         *         AInterface a=()-> {return "第三种方式 lambda写法";
         *
         *
         */

/**
         * Lambda需要类型推断 并且限制挺多 因为出现冲突的话就不知道我要实现哪个方法
         * 所以要求AInterface 只有一个方法,如果有2个就会报错, 因为lambda不知道重写哪一个,可以使用@FunctionalInterface对接口限制,被限制后接口只能有一个方法
         * 在符合类型推断的场景下可使用 如最经典的 开启线程 实现Runnable接口重写run方法 在传入Thread构造器方式
         * new Thread(()-> {})
         */


  /***
         * 上面的方法之中可以看出,lambda表达式代替匿名内部类的时候,lambda代码块将会实现代替实现抽象类的方法体,lambda表达式的语法主要由三部分构成:
         *
         * (1)形参列表,如果只有一个参数可以省略括号,当无参数类型时可以使用()来代替。
         *
         * (2)箭头->
         *
         * (3)代码块部分{}
         *
         * Lambda表达式的类型,也被称为“目标类型(target type)”,lambda表达式的目标类型必须是“函数式接口(functional interface)”。
         * 函数式接口代表只包含一个抽象方法的接口。函数式接口可以包含多个默认方法,类方法,但只能声明一个抽象方法。
         * 如果采用匿名类型内部类来创建函数式接口的实例,则只需要实现一个抽象方法,在这种情况下即可采用lambda表达式来创建对象,
         * 该表达式创建出来的对象目标就是这个函数接口。(可以用@FunctionalInterface注解来对函数接口实行限制)
         *
         * ##表达式的目标类型必须是明确的函数式接口
         *
         * ##lambda表达式只能为函数式接口创建对象,lambda表达式只能实现一个方法,因此他它只能为只有一个抽象方法的借口(函数式接口)创建对象。
         *
         */

AInterface.class
package com.wying.demo.Lambda;

/**
 * description:Lambda学习 定义函数接口
 * date: 2021/9/15
 * author: gaom
 * version: 1.0
 *
 * @FunctionalInterface注解来对函数接口实行限制
 * 当有@FunctionalInterface注解时 只能有一个方法 当增加 getName1方法时会报错
 */

@FunctionalInterface
public interface AInterface {

    public String getName() ;
  //  public String getName1() ;
}

1.2 lambda语法练习  LambdaTest.class

package com.wying.demo.Lambda;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * description:Lambda语法学习
 * 总结 lambda本质上就是匿名内部类的简化写法,我们在实现匿名内部类时最终的目的就是重写方法里的代码段,其他的都不关心,但是必须都要有,导致代码看起来不简洁
 * 在满足lambda语法条件时,使用lambda简化代码,所以lambda并不是什么jdk功能的增强,只能说是简化代码而已。
 *
 *
 *
 * date: 2021/9/15
 * author: gaom
 * version: 1.0
 *
 *
 */
public class LambdaTest {
    public AInterface aInterface;
    //无参构造器
    public LambdaTest(){

    }
    public LambdaTest(AInterface aInterface){
        System.out.println("重载构造器 接收AInterface对象");
        this.aInterface=aInterface;
    }



    //新建一个类实现AInterface
    class BClass implements AInterface{

        @Override
        public String getName() {
            return "第一种方式,新建一个类实现AInterface";
        }


    }

    /**
     *  当构造器的参数 public LambdaTest(AInterface aInterface){}     为函数数接口类型时  Lambda表达式使用场景
     *  方法的参数list.stream().forEach(Consumer<? super T> action)  为函数数接口类型时  Lambda表达式使用场景
     * @param args
     */
    public static void main_1(String args[]){
        //第一种方式,新建一个类实现AInterface

        new LambdaTest(
                new LambdaTest().new BClass()
        ).run();




        //第二种方式 匿名内部类

        /** 匿名内部类写法我们单独写一个匿名内部类 不指向任何目标也不会报错
         *   new AInterface() {
         *             @Override
         *             public String getName() {
         *                 return "第二种方式 匿名内部类写法,定义一个匿名类 传入构造器";
         *             }
         *
         *         };
         *
         *   而lambda 单独这样写是会报错的 因为没有目标,根本无法知道他是哪个匿名内部类的实现
         *   ()-> {
         *             return "第三种方式 lambda写法";
         *         };
         *      必须 把它放到方法入参中,蚕食为函数接口
         *       new LambdaTest(()-> {
         *             return "第三种方式 lambda写法";
         *         }).run();
         *         或者赋值给一个函数式接口
         *         AInterface a=()-> {return "第三种方式 lambda写法";
         *
         *
         */

      new LambdaTest(new AInterface() {
            @Override
            public String getName() {
                return "第二种方式 匿名内部类写法,定义一个匿名类 传入构造器";
            }

        }).run();



      //jdk8之前 我们使用匿名内部类实现接口的方式   等同于我们新建一个Class 实现AInterface接口,重写getName方法

      //lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码

       //第三种方式  lambda表达式写法 等同于第二种写法

        /**
         * Lambda需要类型推断 并且限制挺多 因为出现冲突的话就不知道我要实现哪个方法
         * 所以要求AInterface 只有一个方法,如果有2个就会报错, 因为lambda不知道重写哪一个,可以使用@FunctionalInterface对接口限制,被限制后接口只能有一个方法
         * 在符合类型推断的场景下可使用 如最经典的 开启线程 实现Runnable接口重写run方法 在传入Thread构造器方式
         * new Thread(()-> {})
         */

        new LambdaTest(()-> {
            return "第三种方式 lambda写法";
        }).run();



        List<String> list=new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");

        list.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("遍历list:"+s);
            }
        });


        /**
         * list.stream().forEach 使用Lambda 因为forEach方法 接收的参数是一个函数式接口
         * forEach方法要求传入一个Consumer对象
         * void forEach(Consumer<? super T> action);
         *
         * Consumer类加了FunctionalInterface注解
         * @FunctionalInterface
         * public interface Consumer<T> {
         */

        list.stream().forEach(s -> {
            System.out.println("Lambda语法遍历list:"+s);
         });

        /***
         * 上面的方法之中可以看出,lambda表达式代替匿名内部类的时候,lambda代码块将会实现代替实现抽象类的方法体,lambda表达式的语法主要由三部分构成:
         *
         * (1)形参列表,如果只有一个参数可以省略括号,当无参数类型时可以使用()来代替。
         *
         * (2)箭头->
         *
         * (3)代码块部分{}
         *
         * Lambda表达式的类型,也被称为“目标类型(target type)”,lambda表达式的目标类型必须是“函数式接口(functional interface)”。
         * 函数式接口代表只包含一个抽象方法的接口。函数式接口可以包含多个默认方法,类方法,但只能声明一个抽象方法。
         * 如果采用匿名类型内部类来创建函数式接口的实例,则只需要实现一个抽象方法,在这种情况下即可采用lambda表达式来创建对象,
         * 该表达式创建出来的对象目标就是这个函数接口。(可以用@FunctionalInterface注解来对函数接口实行限制)
         *
         * ##表达式的目标类型必须是明确的函数式接口
         *
         * ##lambda表达式只能为函数式接口创建对象,lambda表达式只能实现一个方法,因此他它只能为只有一个抽象方法的借口(函数式接口)创建对象。
         *
         */



    }
    public void run(){
        System.out.println("LambdaTest--getName:"+aInterface.getName());

    }


    /**
     * Lambda 用法 代码段
     */
    public static void main(String args[]){

        AInterface a1=new AInterface(){

            @Override
            public String getName() {
                return "new一个匿名内部类实现AInterface接口,重写getname方法";
            }
        };

        new LambdaTest(a1).run();
        //Lambda写法


        /**
         * Lambda代码段用法要求定义的变量必须是函数接口 (目标类型必须是函数式接口)
         * 如Object o=  ()-> "Lambda写法 实现AInterface接口,重写getname方法"; 也会报错
         * Lambda代码段需要通过变量的类型 如 AInterface a2= 推导出 变量的值是实现AInterface的类
         *
         * 如果变量是object类型必须通过强转方式来显式的指定目前类型为函数式接口
         *  Object o= (AInterface) ()-> "Lambda写法 实现AInterface接口,重写getname方法";
         *
         */
        AInterface a2=()-> "Lambda写法 实现AInterface接口,重写getname方法";
        new LambdaTest(a2).run();



    }


}

 程序运行效果

2.函数式接口

函数式接口的提出是为了给Lambda表达式的使用提供更好的支持。

什么是函数式接口?
简单来说就是只定义了一个抽象方法的接口(Object类的public方法除外),就是函数式接口,并且还提供了注解:@FunctionalInterface

常见的四大函数式接口

2.1 Consumer <T>:消费型接口,有参无返回值

ConsumerDemo.java
package com.wying.demo.FunctionalInterface;

import org.junit.Test;

import java.util.function.Consumer;

/**
 * description:函数式接口学习   Consumer <T>:消费型接口,有参无返回值  T为参数
 * date: 2021/9/15
 * author: gaom
 * version: 1.0
 */
public class ConsumerDemo {
    @Test
    public   void test01(){

        String str="<id>00001</id><name>张三<name/>";
      /*  consumerStr(str, new Consumer<String>() {
            @Override
            public void accept(String s) {
                //自定义消费逻辑
                try {
                    //例如把s存入数据库
                     System.out.println("开始消费:"+s+"");
                     Thread.sleep(5000);
                     System.out.println("完成消费:"+s);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });*/
        //由于 Consumer <T>是函数式接口 上诉匿名表达式可使用Lambda语法
        consumerStr(str,(s)->{

            //自定义消费逻辑
            try {
                //例如把s存入数据库
                System.out.println("开始消费:" + s + "");
                Thread.sleep(5000);
                System.out.println("完成消费:" + s);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

         });
        System.out.println("消费完毕线程继续执行");

        /**
         * 说实话,刚看完jdk8的新特性 感觉这有啥用?我什么业务场景用?
         * 上面的代码就是把str存入数据库
         * 我得到str后直接封装一个方法写代码把str存数据库不就行了 ?
         * 这就是jdk1.8的特性 ,使java语言开始支持真正的数式编程 这样写出来代码还传统编程写出来的感觉模块化,低解耦,规范,我们看到Consumer<T>知道业务逻辑是要消费数据类型T,且不需要返回值
         * 在实际场景中,我们对数据的处理,写入数据库操作,不需要返回值的都可以尝试使用Consumer<T>
         *
         */
    }

    /**
     * 定义一个消费str的函数 适用于 有参无返回值的业务场景
     * @param str
     * @param consumer
     */
    public void consumerStr(String str, Consumer<String> consumer){
        consumer.accept(str);
    }
}

2.2 Supplier<T>:供给型接口,无参有返回值 T为返回值

SupplierDemo.class
package com.wying.demo.FunctionalInterface;

import com.wying.demo.entity.UserEntiry;
import org.junit.Test;

import java.util.function.Supplier;

/**
 * description:函数式接口学习 Supplier<T>:供给型接口,无参有返回值  T为返回值
 * date: 2021/9/15
 * author: gaom
 * version: 1.0
 */
public class SupplierDemo {
    @Test
    public  void test01(){


        /*UserEntiry userEntiry=  getUser(new Supplier<UserEntiry>() {
            @Override
            public UserEntiry get() {
                return null;
            }
        });*/

        //生产UserEntiry  Supplier<T>为函数式接口 直接使用Lambda语法 我们只关注重写Supplier get方法里的逻辑,而new  Supplier<UserEntiry>
        /**
         * 生产UserEntiry  Supplier<T>为函数式接口 直接使用Lambda语法 我们只关注重写Supplier get方法里的逻辑,而
         * new Supplier<UserEntiry>()
         *  @Override
         *   public UserEntiry get() {
         *
         *   }
         *   这种匿名内部类多余的代码都能省略掉
         */
        UserEntiry userEntiry=  getUser(()->{

            //实际业务场景 比如从数据库查询用户,放入实体 不过这个函数接口是没入参的 感觉场景还真有点少  有参数的场景多点
            UserEntiry userEntiry_1=new UserEntiry().setId(1).setIdCard("362424xxxx").setName("张三").setPhoneNum("18200010002");

            return userEntiry_1;
        });

        System.out.println("生产完毕 userEntiry:"+userEntiry.toString());

    }

    /**
     * 定义一个生产UserEntiry的函数 适用于 无参有返回值的业务场景
     * @param userEntirySupplier
     * @return
     */
    public UserEntiry getUser(Supplier<UserEntiry> userEntirySupplier){
        return   userEntirySupplier.get();
    }
}

2.3  Function<T,R>::函数式接口,有参有返回值 应该是使用最多的

FunctionDemo.java
package com.wying.demo.FunctionalInterface;

import com.wying.demo.entity.UserEntiry;
import org.junit.Test;

import java.util.function.Function;
import java.util.function.Supplier;

/**
 * description:函数式接口学习  Function<T,R>::函数式接口,有参有返回值
 * 这个函数式接口应该是使用场景最多,最使用的,有入参,有返回值
 * date: 2021/9/15
 * author: gaom
 * version: 1.0
 */
public class FunctionDemo {

    @Test
    public void test01(){
        String s="<id>1</id>";
        //根据s 参数 获取UserEntiry  Function<T,R>为函数式接口 直接使用Lambda语法
        getUser(s,(param)->{
            System.out.println("Function<T,R>入参 :"+param);

            // 根据param查询 数据库 获取 用户信息
            //....
            //查询到用户数据赋值
            UserEntiry userEntiry_1=new UserEntiry().setId(1).setIdCard("362424xxxx").setName("张三").setPhoneNum("18200010002");
            System.out.println("Function<T,R>返回 :"+userEntiry_1.toString());
            return userEntiry_1;
        });

    }



    /**
     * Function函数式接口,有参有返回值
     * @param s 入参
     * @param entiryFunction 返回值
     * @return 这里使用的业务场景为 通过入参String 执行业务 返回 UserEntiry
     */
    public UserEntiry getUser(String s,Function<String,UserEntiry> entiryFunction){
           return  entiryFunction.apply(s);
    }
}

2.4 Predicate<T>: 断言型接口,有参有返回值,返回值是boolean类型

PredicateDemo.class
package com.wying.demo.FunctionalInterface;

import org.junit.Test;

import java.util.function.Predicate;

/**
 * description:函数式接口学习 Predicate<T>: 断言型接口,有参有返回值,返回值是boolean类型
 * 适用于根据参数,执行业务 返回 true fasle断言的业务场景
 * date: 2021/9/15
 * author: gaom
 * version: 1.0
 */
public class PredicateDemo {

    @Test
    public void test01(){

        //使用场景
        //例如通过入参str 查询数据库,是否存在数据
        String str="<id>1</id>";
        boolean b=checkUser(str,(param)->{

            boolean bool_1=false;
            //通过param 查询数据库
            //如果数据存在 返回true 否则返回false
            /*if(){

            }*/
            return   bool_1;
        });
    System.out.println("根据str:"+ str+" 查询数据数据存在 返回:"+b);
    }

    /**
     *
     * @param str 入参
     * @param predicate  断言型接口
     * @return boolean
     */
    public boolean checkUser(String str, Predicate<String> predicate){
        return  predicate.test(str);
    }
}

3.方法引用

通过jdk1.8的自带的函数式接口使用简便的写法创建对象,数组,调用方法

3.1构造器引用 ClassName::new 就是在函数式接口中简化 new Instance();

当我们想通过函数式接口创建一个对象时可以使用

ConstructorInvokeDemo01.java
package com.wying.demo.FunctionInvoke;

import org.junit.Test;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * description:构造器引用 ClassName::new 就是在函数式接口中简化 new Instance();
 * 首先前提条件我们要知道 构造器引用的目的 是想用函数式接口创建一个构造器返回 ,我们使用的函数式接口必须是具有返回值的
 * jdk1.8自带的有 Supplier<T> 无参有返回值
 * Function<T,R> 有参有返回值
 * 这里的返回值是指返回构造器创建的对象 入参为构造器的参数
 *
 * 不要问我new 一个对象 我直接new就完事
 * 比如ConstructorInvokeDemo01 c=new ConstructorInvokeDemo01();即可
 * 干嘛要通过一个函数式接口创建 
 * 比如 new一个对象,构造器无传参数
 *  Supplier<ConstructorInvokeDemo01> supplier2=ConstructorInvokeDemo01::new;
 *         ConstructorInvokeDemo01 constructorInvokeDemo01_2= supplier2.get();
 *         
 *         new一个对象,构造器有参数
 *         Function<String,ConstructorInvokeDemo01> function3=ConstructorInvokeDemo01::new;
 *          System.out.println("构造器引用写法 有参构造器 通过apply传入构造器所需参数 返回一个对象");
 *         ConstructorInvokeDemo01 constructorInvokeDemo01_3=function3.apply("100");
 * 哈哈 可能就是通过函数式接口模块化,规范化把
 *
 *
 * date: 2021/10/27
 * author: gaom
 * version: 1.0
 */
public class ConstructorInvokeDemo01 {

    public ConstructorInvokeDemo01(){
        System.out.println("无参构建器");
    }

    public ConstructorInvokeDemo01(String x){
        System.out.println("有参构建器 参数:"+x);
    }

    /**
     * 这里没使用junit 测试  因为 junit内部运行时 也是要实例化一个对象调用test01方法
     * ConstructorInvokeDemo01有2个构造器时junit不知道选哪个 导致junit报错
     * junit要求实例化的对象只能有无参构造器,即使只有一个带参数的也不行,因为junit初始有参构造器不知道传递什么参数
     * @param args
     */
    public static  void main(String args[]){
        ConstructorInvokeDemo01 c=new ConstructorInvokeDemo01();
        c.test01();
    }

    public void test01(){

        Supplier<ConstructorInvokeDemo01> supplier=new Supplier() {
            @Override
            public ConstructorInvokeDemo01 get() {

                System.out.println("匿名表达式写法 返回一个对象");
                return new ConstructorInvokeDemo01();
            }
        };
        ConstructorInvokeDemo01 constructorInvokeDemo01= supplier.get();

        //------------------------------------------------------------------------
        Supplier<ConstructorInvokeDemo01> supplier1=()->{
            System.out.println("lambda表达式写法 返回一个对象");
            return  new ConstructorInvokeDemo01();
        };
        ConstructorInvokeDemo01 constructorInvokeDemo01_1= supplier1.get();

        //------------------------------------------------------------------------

        System.out.println("构造器引用写法 返回一个对象");
        Supplier<ConstructorInvokeDemo01> supplier2=ConstructorInvokeDemo01::new;
        ConstructorInvokeDemo01 constructorInvokeDemo01_2= supplier2.get();

        //------------------------------------------------------------------------

        System.out.println("构造器引用写法 有参构造器 <String>为参数,<ConstructorInvokeDemo01>为构造器类型 返回一个对象");
        Function<String,ConstructorInvokeDemo01> function3=ConstructorInvokeDemo01::new;
         System.out.println("构造器引用写法 有参构造器 通过apply传入构造器所需参数 返回一个对象");
        ConstructorInvokeDemo01 constructorInvokeDemo01_3=function3.apply("100");
        //------------------------------------------------------------------------

        //------------------------------------------------------------------------

        //------------------------------------------------------------------------


    }


}

3.2  方法引用demo object::method 就是在函数式接口中简化 object.mothod();

FunctionInvokeDemo01.java
package com.wying.demo.FunctionInvoke;

import org.junit.Test;

import java.util.function.Consumer;

/**
 * description:方法引用demo object::method 就是在函数式接口中简化 object.mothod();
 * date: 2021/10/27
 * author: gaom
 * version: 1.0
 */
public class FunctionInvokeDemo01 {

    /**
     * 总结就是方法引用也是需要先满足函数式接口 且引用的方法入参必须和函数式接口的方法参数个数,类型一致
     * 我们也看到了局限性,方法引用适用于{}代码段中只调用一个方法,如果{}需要调用几个方法及不适用
     * 比如 下面的    System.out.println(s); 可以使用方法引用,System.out::println;
     * public void accept(String s) {
     *                 System.out.println(s);
     *             }
     *      但是  如果{}中需要执行多个方法调用时 不能使用方法引用
     *       public void accept(String s) {
     *                       System.out.println(s);
     *                        System.out.println(s+"1");
     *                  }
     *
     */


    @Test
    public void test01(){

        Consumer<String> consumer=new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer.accept("hello 匿名表达式语法 实现Consumer 重写accept方法");
       //------------------------------------------------------------------------
        Consumer<String> consumer01=(s)->{System.out.println(s);};
        consumer01.accept("hello01 lambda表达式语法 实现Consumer 重写accept方法 ");
        //------------------------------------------------------------------------
        Consumer<String> consumer02=System.out::println;
        consumer02.accept("hello02 静态方法直接类名引用 要求println方法的入参和函数式接口的参数类型数量一致 ");
        //------------------------------------------------------------------------
        //this::save01 相当于实现了Consumer接口后 重写accept中 {}代码块里执行的语句
        Consumer<String> consumer03=this::save01;
        consumer03.accept("hello03 非静态方法通过对象引用 要求save01方法的入参和函数式接口的参数类型数量一致 ");
        //------------------------------------------------------------------------
        Consumer<String> consumer04= FunctionInvokeDemo01::save02;
        consumer04.accept("hello04 静态方法直接类名引用 要求save02方法的入参和函数式接口的参数类型数量一致");
    }

    public    void save01(String s01){
        System.out.println("保存 s01:"+s01);

    }

    public  static   void save02(String s02){
        System.out.println("保存 s02:"+s02);

    }
}

3.3 数组引用 Type[]::new ..也是满足函数式接口才能使用的 相当于new String[x]

ArrayInvoke.java
package com.wying.demo.FunctionInvoke;

import org.junit.Test;

import java.util.function.Function;

/**
 * description:数组引用 Type[]::new  ..也是满足函数式接口才能使用的 相当于new String[x]
 * date: 2021/10/27
 * author: gaom
 * version: 1.0
 */
public class ArrayInvoke {

    @Test
    public void test01(){
        // 常规创建数组方式
        String [] ary=new String[5];
        System.out.println("常规创建数组方式 ary.length:"+ary.length);
        //------------------------------------------------------------------------

        //数组需要用长度 通过入参传入 创建后需要返回  Function函数式接口满足
        //函数式接口创建 匿名内部类
        Function<Integer,String[]> function1=new Function<Integer, String[]>() {
            @Override
            public String[] apply(Integer integer) {
                return new String[integer];
            }
        };
        String[] ary1=function1.apply(10);
        System.out.println("函数式接口创建 匿名内部类 创建数组方式 ary1.length:"+ary1.length);
        //------------------------------------------------------------------------
        //函数式接口创建 lambda写法
        Function<Integer,String[]> function2=(x)->{return new String[x];};
        String[] ary2=function2.apply(20);
        System.out.println("函数式接口创建 lambda写法 创建数组方式 ary2.length:"+ary2.length);
        //------------------------------------------------------------------------
        //函数式接口创建 简化后的 数组引用创建方法 Type[]::new
        Function<Integer,String[]> function3=String[]::new;
        String[] ary3=function3.apply(30);
        System.out.println("函数式接口创建 数组引用写法 创建数组方式 ary3.length:"+ary3.length);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值