day28

96 阅读10分钟
typora-copy-images-to: imgs

今日内容一

  1. 回顾接口 (掌握)
  2. Lambda表达式 (理解并掌握)

一.回顾接口(掌握)

  • 需求:已经知道有一个接口,想调用接口中的方法

  • 如何实现:

    • 方式一:定义一个类,实现该接口,重写接口中的方法。

      接口 对象 = new 实现类();

      对象调用方法。

    • 方式二:直接通过匿名内部类的方式实现的。

      接口 对象 = new 接口(){};

    • 方式三:通过lambda表达式实现的。

  • 演示代码

    package lession;
    ​
    public class Demo1 {
        public static void main(String[] args){
    ​
            //1.创建对象: 通过lambda表达式实现
            //lambda表达式基本语法:
            //1. () 来定义接口方法的形式参数
            //2. {}  来定义接口中的方法体
            //3. -> 将(形式参数)--->{方法体} 构建联系关系
            A a = ()->{
                System.out.println("测试方法11111");
            };
            //2.使用对象调用方法
            a.test();
    ​
    ​
    ​
        }
        //方式二: 通过子类来创建对象,调用方法
        private static void test2(){
            //1. 通过子类来创建对象
            A a  = new SonA();
            //2. 通过对象来调用方法
            a.test();
        }
    ​
        //1.方式一:通过匿名内部类来创建对象,调用接口中的方法
        private static void test(){
            //需求: 调用接口中的test方法
            //1.通过匿名内部类创建对象
            A a = new A() {
                @Override
                public void test(){
                    System.out.println("测试方法");
                }
            };
            //2.通过对象来调用方法
            a.test();
        }
    }
    ​
    //1.提供接口
    interface  A{
        void test();
    }
    //2.提供一个实现类
    class SonA  implements  A{
        public void test(){
            System.out.println("子类进行测试方法");
        }
    }
    

总结:

函数式编程概述:

函数式编程是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值) 。

一句话总结: lambda表达式来替代匿名内部类(替代函数式接口),进行函数式输入和输出运算.

  • lambda表达式输入: 通过前面的小括号进行参数传递,实现输入
  • lambda表达式输出: 通过后面的大括号的方法体,进行数据的返回.

通过lambda表达式的写法,其实就是函数式编程思想的体现。

特点:

  1. 不用关注具体的实现过程(不用给接口提供实现类),关注方法实现结果就可以了。
  2. 在函数式编程中,lambda表达式可以作为参数使用(替代函数式接口,或者说替代匿名内部类)。

注意:

lambda表达式在函数式编程中,可以替代接口,要求该接口必须是函数式接口。

函数式接口特点:有且仅有一个抽象方法。

区分是不是函数式接口:

标记了@FunctionalInterface注解的接口都是函数式接口。

二.Lambda表达式(理解和掌握)

2.1 基本语法

语法格式: (参数列表)->{方法体}

注意:

  • (参数列表):对应接口中方法的形式参数。

  • {方法体}: 具体的方法实现效果,其实就是方法体.

  • 比如:

    public String  test(int a, String b){
         String str = a+b;
         return str;
    }
    //方法的形参: a,  b
    //方法体: String str = a+b;  return str;
    //lambda表达式书写:
    (int a,String b)->{ // int a, String b 就是lambda表达式的输入(把参数传递给方法体去使用)
        String str= a+b; 
        return str;// str 就是lambda表达式的输出(使用参数完毕后,返回值)
    };
    

2.2 作用

Lambda表达式的作用:替代函数式接口(替代匿名内部类的)。

应用场景有两个地方:

  1. 使用lambda给接口创建对象.
  2. 在方法的参数里面使用lambda表达式(前提方法的参数是函数式接口)
  3. 一句话总结: Lambda表达式的作用不就是替代匿名内部类的

优点:简化接口的开发(不用关注接口的具体实现,简化开发)。

应用场景如下:

package lession2;
​
/**
 * 演示: lambda表达式的应用场景, 具体指的在两个地方使用
 * 1. 使用lambda给接口创建对象.
 * 2. 在方法的参数里面使用lambda表达式(前提方法的参数是函数式接口)
 */
public class Demo2 {
    public static void main(String[] args){
        //需求1: 不使用lambda调用接口中的方法
      /*  C cc = new C() {
            @Override
            public void test(int a){
                System.out.println("打印数据:"+a);
            }
        };
        cc.test(100);//输入*/
        //需求2 : 使用lambda给接口创建对象.
        C cc = (int a)->{System.out.println(a);};
        //cc.test(2000);//输入
        //需求2 : 在方法的参数里面使用lambda表达式(前提方法的参数是函数式接口)
        //---------1.使用匿名内部类创建对象,传递到方法中------------------
        C cc2 = new C() {
            @Override
            public void test(int a){
                System.out.println(a);
            }
        };
        operationData(10101,cc2);
        //--------2.先使用lambda表达式创建对象,传递到方法中------------
        C cc3 = (int a)->{
            System.out.println(a);
        };
        operationData(301301,cc3);
        //---------3.直接将lambda表达式传体到方法中-----------------
        operationData(401401,(int a)->{
            System.out.println(a);
        });
        //----------------------------------
    }
    public static  void operationData(int a, C cc){
        cc.test(a);
    }
}
​
interface  C{
    void test(int a);
}

2.3 具体应用

注意:Lambda表达式 替代函数式接口(函数式接口里面有且仅有一个抽象方法)

  • 1.替换函数式接口:没有参数没有返回值的方法,如:()->{方法体}
package lession2;
​
/**
 * 演示:1.函数式接口:没有参数没有返回值的方法
 */
public class Demo1 {
    public static void main(String[] args) {
        //方式一:自定义类实现接口,创建对象
        show(new Zi22());
        //方式二:匿名内部类的方式,创建对象
        show(new MyInterface2() {
            @Override
            public void test() {
                System.out.println("匿名内部类的方式test---");
            }
        });
        //方式三:lambda表达式的写法,(参数列表)->{方法体}
        show(()->{System.out.println("lambda的方式test---");});
    }
    //1.提供一个方法:传递对象,调用接口中的方法
    public static  void  show(MyInterface2 m){
        m.test();
    }
​
}
​
@FunctionalInterface
interface MyInterface2{
    void  test();
}
class  Zi22 implements MyInterface2{
    @Override
    public void test() {
        System.out.println("子类实现接口的test方法---");
    }
}
​
  • 2.替换函数式接口:有参数没有返回值的方法,如:(接口中的参数)->{方法体}
package lession2;
​
/**
 * 演示:2.替换函数式接口:有参数没有返回值的方法,如:(接口中的参数)->{方法体}
 */
public class Demo2 {
    public static void main(String[] args) {
        //1.方式一:自定义类创建对象
        show(new ZiImpl3());// MyInterface3 m3 = new ZiImpl3();
        //2.方式二:匿名内部类创建对象
        show(new MyInterface3() {
            @Override
            public void test(String name) {
                System.out.println("匿名内部类,传递参数:" + name);
            }
        });
        //3.方式三:lambda
        show((name)->{
            System.out.println("lambda表达式,传递参数:"+name);
        });
    }
​
    public static void show(MyInterface3 m3) {
        m3.test("YY要下载喔!!!");
    }
​
}
​
@FunctionalInterface
interface MyInterface3 {
    void test(String name);
}
​
class ZiImpl3 implements MyInterface3 {
    @Override
    public void test(String name) {
        System.out.println("自定义类,传递的参数:" + name);
    }
}
​
  • 3.替换函数式接口: 没有参数有返回值的方法,如:()->{方法体; return 值;}
/**
 * 演示;3.替换函数式接口: 没有参数有返回值的方法,如:()->{方法体; return 值;}
 */
public class Demo3 {
    public static void main(String[] args) {
        //1.方式二:匿名内部类的写法
        show(new MyInterface4() {
            @Override
            public String test() {
                return "下载YY喔!!!";
            }
        });
        //2.方式三:lambada表达式
        show(()->{
            System.out.println("lambda表达式写法");
            return "下载YY喔!!!";
        });
​
    }
    public  static void  show(MyInterface4 m4){
       String str =  m4.test();
        System.out.println("返回值:"+str);
    }
}
​
@FunctionalInterface
interface  MyInterface4{
     String  test();
}
  • 4.替换函数式接口: 有参数有返回值的方法,如:(参数列表)->{方法体; return 值;}
/**
 * 演示:4.替换函数式接口: 有参数有返回值的方法,如:(参数列表)->{方法体; return 值;}
 */
public class Demo4 {
​
    public static void main(String[] args) {
        //1.方式二:匿名内部类
        show(new MyInterface5() {
            @Override
            public int add(int x, int y) {
                return x+y;
            }
        });
        //2.方式三:lambda表达式
        show((int x2,int y2)->{
            System.out.println("lambda表达式");
            return  x2+y2;
        });
    }
    public  static  void show(MyInterface5 m5){
        int sum = m5.add(1,9);
        System.out.println("返回值:"+sum);
    }
}
​
@FunctionalInterface
interface MyInterface5{
   public abstract int add(int x,int y);
   //public  abstract   void test();
}

2.4 简写方式

  • 1.如果方法里面只有一个参数,可以省略小括号

    public class Demo5 {
        
        MyInterface6 m6 =(int x)->{
            System.out.println("测试---");
        };
        MyInterface6 m6_1 = x->{//省略小括号
            System.out.println("测试---");
        };
    }
    ​
    interface  MyInterface6{
        void test(int x);
    }
    
  • 2.lambda表达式里面的参数,可以省略类型,还可以省略小括号

    MyInterface6 m6_1 =(x)->{//可以省略类型
            System.out.println("测试---");
        };
    
  • 3.如果方法体里面,有且仅有一个语句,可以省略大括号

     MyInterface6 m6_2 =x-> System.out.println("测试");//可以省略大括号
    
  • 4.如果方法里面,有且仅有一个语句,且是返回值,可以省略大括号,并且省略return

    public class Demo5 {
    ​
    ​
        MyInterface7 m7 = x->{return 6;};  //返回值
        MyInterface7 m7_1 = x-> 6;
        
    }
    ​
    interface  MyInterface7{
        int  test(int x);
    }
    

2.5 Lambda使用注意事项

  1. Lambda表达式是用于替代函数式接口(替代匿名内部类),必须保证该接口里面有且仅有一个抽象方法。

  2. Lambda表达式是的使用上下文环境 (以MyInterface7举例)

    • 给接口创建对象使用:

      比如: MyInterface7 m7 = x->6; //返回值

    • 作为参数使用:

      show( x->6);

2.6 Lambda和匿名内部类区别(理解)

  • 区别1: 从jdk版本来说

    lambda从jdk8以后才有的,新特性。

    匿名内部类:没有版本区别

  • 区别2:从使用范围来说

    lambda只能替换函数式接口(有且仅有一个抽象方法的接口),

    匿名内部类:可以是任何接口,任何类(抽象类和普通类)。

  • 区别3:从原理来说 (掌握)

    lambda(函数式编程,只关注方法的结果),不会编译对应的class文件(效率高,没有编译过程)。

    匿名内部类时,在使用过程中,会编译class文件。

三.接口组成的新特性(更新,理解)

3.1 JDK7之前,接口里面只能写常量值和抽象方法

/**
 * 演示:jdk7之前,接口的组成:
 * 1.常量
 * 2.抽象方法
 */
public class Demo1 {
}
interface  MyInterface10{
    public static  final String TRAFICC_lIGHT_COLOR="RED";//1.定义常量值, public static  final可以省略的
    public abstract void test10();//2.抽象方法,public abstract可以省略的
}

3.2 JDK8以后(JDK9,JDK10-)接口里面可以写静态方法,默认方法,普通私有方法

  1. 除了在接口中可以定义常量值和抽象方法(常量值可以直接通过接口调用,不能通过对象调用)

  2. 在接口中定义静态方法,默认被public修饰,可以直接通过接口调用,不能通过对象调用静态方法

  3. 在接口中定义默认方法,默认被public修饰,只能通过对象调用默认方法

  4. 在接口中定义私有方法,只能在接口中调用(从JDK9以后才有的)。

    /**
     * 演示:jdk8以后,接口的组成
     *  1. 常量值
     *  2.抽象方法
     *  3. 静态方法
     *  4. 默认方法
     *  5. 普通方法: 只能定义私有的普通方法
     */
    public class Demo3 {
        public static void main(String[] args) {
            //1.接口直接调用 常量值
            String  v = MyInterafce11.COLOR;
            System.out.println("交通灯的颜色:"+v);
            //2.获取接口对象
            MyInterafce11 m11 = new MyInterafce11() {
                @Override
                public void test11() {
                    System.out.println("抽象方法---test11");
                }
            };
            m11.test11();//调用抽象方法
           //3.调用静态方法
            MyInterafce11.test12();
            //4.调用默认方法
            m11.test13();
            //5.调用私有方法
            //m11.test14();//报错,因为test14方法,是被private修饰,只能在本类中使用。
        }
    }
    @FunctionalInterface
    interface  MyInterafce11{
        public static final  String COLOR="red";//1.常量值,可以通过接口名称直接调用,不能使用对象调用
        public abstract  void test11();//2.抽象方法
        public static void test12(){//3.静态方法: public可以省略的,不能使用对象调用
            System.out.println("static----test12");
        }
        public  default void  test13(){//4.默认方法 ,public可以省略的
            System.out.println("default---test13");
        }
        private  void test14(){//5.普通的私有方法:
            System.out.println("普通方法");
        }
    }
    

    为什么定义私有方法,如下代码:

    public class Demo3 {
    }
    /*
        1.存在哪些问题?
                静态方法和默认方法代码 存在冗余问题(重复问题)
        2.如何解决存在的问题
               对于存在的冗余代码,可以抽取出来,放在私有方法中。
     */interface  MyInterface13{
        //1.定义静态方法
        public static  void test1(){
    //        System.out.println("aaa");
    //        System.out.println("bbb");
            test666();
            System.out.println("static---test1");
        }
        //2.定义默认方法
        public default void test2(){
    //        System.out.println("aaa");
    //        System.out.println("bbb");
            test666();
            System.out.println("default-----test2");
        }
        //3.定义私有方法:抽取冗余代码
        private static  void  test666(){
            System.out.println("aaa");
            System.out.println("bbb");
        }
    }