day22-JDK新特性

Posted teayear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了day22-JDK新特性相关的知识,希望对你有一定的参考价值。

接口中的新特性

接口我们之前已经学过了,那么接口中内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。

接口中可以有的内容

  • JDK1.7之前

    抽象方法

    常量

  • JDK1.8

    默认方法
    静态方法

  • JDK1.9

    私有方法

接口默认方法的定义和使用

默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。

默认方法定义格式

public default 返回值类型  方法的名称(参数列表)
    方法体

默认方法的好处

接口的默认方法,实现类可以不用重写,默认方法可以用于接口升级

/**
 * @Auther: yanqi
 * @Desc   实现类没有没重写默认方法呢?
 *              接口中的抽象方法是必须要重写(实现)
 *              接口中的默认方法,不用重写,也可以手动重写,你默认方法存在的意义?
 *
 *              如果今后项目代码已以经写好,后期可能要扩展,接口中加新的方法(功能),如果你加抽象方法(功能)
 *              所有的实现类有影响,所以针对以上后期可能要扩展功能的话,代码的维护性比较差,出现了默认方法
 */
  • 定义接口
    public interface LiveAble 
        //接口的默认方法
        public default void fly() 
            System.out.println("天上飞"); 
         
    
    
  • 定义实现类
    public class Animal implements LiveAble     
        // default 可以选择是否重写,也可以根据实际需求进行重写
        /*
        	@Override
       		public void fly() 
            	System.out.println("自由自在的飞");   
            
        */
    
    
  • 定义测试类
    public class InterfaceDemo 
        public static void main(String[] args)        
            // 创建子类对象 
            Animal a = new Animal();
            // 调用默认方法
            a.fly();
        
    
    

接口静态方法的定义和使用

静态方法:使用 static 修饰,供接口直接调用。

静态与.class文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用

静态方法定义格式

public static 返回值类型 方法名称(参数列表)
    方法体

静态方法使用

  • 定义接口
    public interface LiveAble 
        //静态方法
        public static void show2()
            System.out.println("静态方法-show2");
        
    
    
  • 定义实现类
    public class Animal implements LiveAble     
      // 无法重写静态方法
    
    
  • 定义测试类
    public class InterfaceDemo 
        public static void main(String[] args) 
            //无法调用
            // LiveAble l = new LiveAbleImpl();
            // l.show2();
            
            //接口名.静态方法(参数列表)
           LiveAble.show2();
         
    
    

接口私有方法的定义和使用

如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法 去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助。

私有方法分类

  • 普通私有方法

    只有默认方法可以调用。

  • 私有静态方法

    默认方法和静态方法可以调用。

代码演示

  • 私有方法
    • 定义接口

      public interface MyInterfacePrivateA 
      	//默认方法
          public default void methodDefault1() 
              System.out.println("默认方法1");
              methodCommon();
          
      
          //默认方法
          public default void methodDefault2() 
              System.out.println("默认方法2");
              methodCommon();
          
      
          //普通-私有方法
          private void methodCommon() 
              System.out.println("AAA");
              System.out.println("BBB");
              System.out.println("CCC");
          
      
      
      
  • 私有静态方法

    • 定义接口

      public interface MyInterfacePrivateB 
          //静态方法
          public static void methodStatic1() 
              System.out.println("静态方法1");
              methodStaticCommon();
          
      
          //静态方法
          public static void methodStatic2() 
              System.out.println("静态方法2");
              methodStaticCommon();
          
      
          //私有-静态方法
          private static void methodStaticCommon() 
              System.out.println("AAA");
              System.out.println("BBB");
              System.out.println("CCC");
          
      
      

    私有方法主要解决的问题是:

默认方法和static方法代码重复的问题,private方法可作为抽取共性

Lambda表达式

什么是Lambda

Lambda 表达式是 Java8 新增的重要特性,Lambda 使 Java 具有了类似函数式编程的风格,其实 Lambda 表达式也是一个 “语法糖”,其实质也是由编译器根据表达式推断最终生成原始语法的字节码方式。

面象对象思想:

做一件事情,找一个能解决这个事情的对象,调用这个对象的方法,完成事情

函数式编程思想:

只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程

函数式思想

函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”

而我们要学习的Lambda表达式就是函数式思想的体现

函数式接口

函数式接口在java中指的是:有且仅有一个抽象方法的接口

当然接口中可以有其他的方法(默认方法,静态方法,私有方法)
函数式接口的使用: 一般用作方法的参数和返回值类型

体验Lambda

  • 案例需求

    启动一个线程,在控制台输出一句话:多线程程序启动了

  • 实现步骤

    - 定义一个类MyRunnable实现Runnable接口,重写run()方法
    - 创建MyRunnable类的对象
    - 创建Thread类的对象,把MyRunnable的对象作为构造参数传递
    - 启动线程
    
  • 代码实现

    • 定义线程类
      public class MyRunnable implements Runnable 
      
          @Override
          public void run() 
              System.out.println("多线程程序启动了");
          
      
      
    • new Thread 方式
      //方式一
      MyRunnable my = new MyRunnable();
      Thread t = new Thread(my);
      t.start();
      
    • 匿名内部类方式
      //方式二
      new Thread(new Runnable() 
          @Override
          public void run() 
              System.out.println("多线程程序启动了");
          
      ).start();
      
    • Lambda实现
      //方式三
      new Thread( () -> 
          System.out.println("多线程程序启动了");
       ).start();
      

Lambda标准格式

  • 格式

    (形式参数) -> 代码块

  • 格式解析
    • 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可

    • ->:由英文中画线和大于符号组成,固定写法。代表指向动作

    • 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容

Lambda表达式练习

Lambda表达式使用前提

  • 有一个接口
  • 接口中有且仅有一个抽象方法
/**
 * @Auther: yanqi
 * @Desc: 函数式接口在java中指的是:有且仅有一个抽象方法的接口
 *        当然接口中可以有其他的方法(默认方法,静态方法,私有方法)
          **函数式接口的使用: 一般用作方法的参数和返回值类型**
 *
 *          @FunctionalInterface
 *          作用:可以检测接口是不是一个函数式接口
 *              是:编译成功
 *              否:编译失败(接口中没有抽象方法,抽象方法多于1个)
 */

@FunctionalInterface
public interface LambdaInter

    //定义一个抽象方法
    public abstract void method();

    // public abstract  void method2();//编译不通过,只能有一个抽象方法



抽象方法是无参无返回值

  • 实现步骤
    • 定义一个接口(Eatable),里面定义一个抽象方法:void eat();

    • 定义一个测试类(EatableDemo),在测试类中提供两个方法

      • 一个方法是:useEatable(Eatable e)

      • 一个方法是主方法,在主方法中调用useEatable方法

  • 代码实现
    //接口
    public interface Eatable 
        //抽象方法无参无返回值
        void eat();
    
    //实现类
    public class EatableImpl implements Eatable 
        @Override
        public void eat() 
            System.out.println("一天一苹果,医生远离我");
        
    
    
    /** 
     * 测试类
     * @Auther: yanqi
     * @Desc **函数式接口的使用: 一般用作方法的参数和返回值类型**
     */
    public class EatableDemo 
        public static void main(String[] args) 
            //方式一:匿名内部类
            useEatable(new Eatable() 
                @Override
                public void eat() 
                    System.out.println("方式一:匿名内部类");
                
            );
    
            //方式二:Lambda表达式
            //()表示eat()方法的参数列表,内部表示方法体
            useEatable(()->
                System.out.println("方式二:Lambda表达式");
            );
        
    
        //定义一个方法,参数用我们定义的函数式接口
        private static void useEatable(Eatable e) 
            e.eat();
        
    
    
    
    

抽象方法是有参无返回值

  • 实现步骤
    • 定义一个接口(Flyable),里面定义一个抽象方法:void fly(String s);

    • 定义一个测试类(FlyableDemo),在测试类中提供两个方法

      • 一个方法是:useFlyable(Flyable f)

      • 一个方法是主方法,在主方法中调用useFlyable方法

  • 代码实现
    public interface Flyable 
        //抽象方法是有参无返回值
        void fly(String s);
    
    
    public class FlyableDemo 
        public static void main(String[] args) 
       
            //方式一:匿名内部类
            useFlyable(new Flyable() 
                @Override
                public void fly(String s) 
                    System.out.println(s);
                    System.out.println("飞机自驾游");
                
            );
            System.out.println("--------");
    
            //方式二:Lambda表达式
            //useFlyable((String s) -> 
            useFlyable((s) ->  //类型也可以省略,lambda表达式会自己行判断类型   
                System.out.println(s);
                System.out.println("飞机自驾游");
            );
    
        
    
        private static void useFlyable(Flyable f) 
            f.fly("风和日丽,晴空万里");
        
    
    

抽象方法是有参有返回值

  • 操作步骤
    • 定义一个接口(Addable),里面定义一个抽象方法:int add(int x,int y);

    • 定义一个测试类(AddableDemo),在测试类中提供两个方法

      • 一个方法是:useAddable(Addable a)

      • 一个方法是主方法,在主方法中调用useAddable方法

  • 代码实现
    public interface Addable 
        // 抽象方法是有参有返回值
        int add(int x,int y);
    
    
    public class AddableDemo 
        public static void main(String[] args) 
            //方式一:匿名内部类
            useAddable(new Addable() 
                @Override
                public int add(int x, int y) 
                    return x+y;
                
            );
            
            //方式二:lambda
            useAddable((int x,int y) -> 
                return x + y;
            );
            //可以省略类型
            useAddable((x,y)->
               return x+y;
            );
            //如果代码块的语句只有一条,可以省略大括号和分号,和return关键字,不建议
            useAddable((x,y)->
                 x+y
            );
    
        
    
        private static void useAddable(Addable a) 
            int sum = a.add(10, 20);
            System.out.println(sum);
        
    
    

Lambda表达式的省略模式

省略规则

  • 参数类型可以省略。但是有多个参数的情况下,不能只省略一个
  • 如果参数有且仅有一个,那么小括号可以省略
  • 如果代码块的语句只有一条,可以省略大括号和分号,和return关键字

代码演示

public interface Addable 
    int add(int x, int y);


public interface Flyable 
    void fly(String s);


public class LambdaDemo 
    public static void main(String[] args) 
//        useAddable((int x,int y) -> 
//            return x + y;
//        );
        //参数的类型可以省略
        useAddable((x, y) -> 
            return x + y;
        );

//        useFlyable((String s) -> 
//            System.out.println(s);
//        );
        //如果参数有且仅有一个,那么小括号可以省略
//        useFlyable(s -> 
//            System.out.println(s);
//        );

        //如果代码块的语句只有一条,可以省略大括号和分号
        useFlyable(s -> System.out.println(s));

        //如果代码块的语句只有一条,可以省略大括号和分号,如果有return,return也要省略掉
        useAddable((x, y) -> x + y);
    

    private static void useFlyable(Flyable f) 
        f.fly("风和日丽,晴空万里");
    

    private static void useAddable(Addable a) 
        int sum = a.add(10, 20);
        System.out.println(sum);
    

Lambda表达式的注意事项

  • 使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法

  • 必须有上下文环境,才能推导出Lambda对应的接口

    • 根据局部变量的赋值得知Lambda对应的接口

      Runnable r = () -> System.out.println(“Lambda表达式”);

    • 根据调用方法的参数得知Lambda对应的接口

      new Thread(() -> System.out.println(“Lambda表达式”)).start();

lambda表达式主要用于替换以前广泛使用的内部匿名类,使代码更简洁

Stream流

它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

Stream(流)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

体验Stream流

  • 案例需求

    按照下面的要求完成集合的创建和遍历

    • 创建一个集合,存储多个字符串元素
    • 把集合中所有以"张"开头的元素存储到一个新的集合
    • 把"张"开头的集合中的长度为3的元素存储到一个新的集合
    • 遍历上一步得到的集合
  • 原始方式示例代码

    public class StreamDemo 
        public static void main(String[] args) 
            //1、创建一个集合,存储多个字符串元素
            ArrayList<String> list = new ArrayList<>();
            list.add("林青霞");
            list.add("张曼玉");
            list.add("王祖贤");
            list.add("柳岩");
            list.add("张敏");
            list.add("张无忌");
    
            //2、把集合中所有以"张"开头的元素存储到一个新的集合
            ArrayList<String> zhangList = new ArrayList<>();
            for(String s : list) 
                if(s.startsWith("张")) 
                    zhangList.add(s);
                
            
            System.out.println(zhangList);//[张曼玉, 张无忌]
    
            //3、把"张"开头的集合中的长度为3的元素存储到一个新的集合
            ArrayList<String> threeList = new ArrayList<>();
            for(String s : zhangList) 
                if(s.length() == 3) 
                    threeList.add(s);
                
            
            System.out.println(threeList);//张曼玉 张无忌
    
            //4、遍历上一步得到的集合
            for(String s : threeList) 
                System.out.println(s);
            
        
    
    
  • 使用Stream流示例代码
    public class StreamDemo 
        public static void main(String[] args) 
            //创建一个集合,存储多个字符串元素
            ArrayList<String> list = new ArrayList<String>();
    
            list.add("林青霞");
            list.add("张曼玉");
            list.add("王祖贤");
            list.add("柳岩");
            list.add("张敏");
            list.add("张无忌");
    
            //Stream流来改进  s表示的list集合的String类型
            list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::

    以上是关于day22-JDK新特性的主要内容,如果未能解决你的问题,请参考以下文章

    JAVA零基础小白入门上手教程之day22-JDK新特性

    .~day08_高级特性和新特性

    Day721. 外部函数接口 -Java8后最重要新特性

    Day709.JShell -Java8后最重要新特性

    java 多线程 day08 java5多线程新特性

    day17JDK5.0新特性与正则表达式