JDK8新特性

JDK8新特性
Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应
用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选
开发平台
课程内容的介绍

  1. 了解Java发展史
  2. Lambda表达式
  3. 接口的增强
  4. 函数式接口
  5. 方法引用
  6. Stream API
  7. Optional
  8. 新时间日期API
  9. 其他新特性
    一、Java发展历史
  10. Java的发展历史
    Sun公司在1991年成立了一个称为绿色计划( Green Project )的项目,由James Gosling(高斯林)博
    土领导,绿色计划
    的目的是开发一种能够在各种消费性电子产品(机顶盒、冰箱、收音机等)上运行的程序架构。这个项目的
    产品就是
    Java语言的前身: Oak(橡树)。Oak当时在消费品市场上并不算成功,但随着1995年互联网潮流的兴起,
    Oak迅速找到
    了最适合自己发展的市场定位。
    JDK Beta - 1995
    JDK 1.0 - 1996年1月 (真正第一个稳定的版本JDK 1.0.2,被称作 Java 1 )
    JDK 1.1 - 1997年2月
    J2SE 1.2 - 1998年12月
    J2ME(Java 2 Micro Edition,Java 2平台的微型版),应用于移动、无线及有限资源的环境。
    J2SE(Java 2 Standard Edition,Java 2平台的标准版),应用于桌面环境。
    J2EE(Java 2 Enterprise Edition,Java 2平台的企业版),应用于基于Java的应用服务器。
    J2SE 1.3 - 2000年5月
    J2SE 1.4 - 2002年2月
    J2SE 5.0 - 2004年9月
    Java SE 6 - 2006年12月
    Java SE 7 - 2011年7月
    Java SE 8(LTS) - 2014年3月
    Java SE 9 - 2017年9月
    Java SE 10(18.3) - 2018年3月
    Java SE 11(18.9 LTS) - 2018年9月
    Java SE 12(19.3) - 2019年3月
    Java SE 13(19.9) - 2019年9月
    Java SE 14(20.3) - 2020年3月
    Java SE 15(20.9) - 2020年9月
    我们可以看到Java SE的主要版本大约每两年发布一次,直到Java SE 6到Java SE 7开始花了五年时间,
    之后又花了三
    年时间到达Java SE 8。
    2.OpenJDK和OracleJDK
    2.1 Open JDK来源
    Java 由 Sun 公司发明,Open JDK是Sun在2006年末把Java开源而形成的项目。也就是说Open JDK
    是Java SE平台版
    的开源和免费实现,它由 SUN 和 Java 社区提供支持,2009年 Oracle 收购了 Sun 公司,自此 Java 的维
    护方之一的
    SUN 也变成了 Oracle。
    2.2 Open JDK 和 Oracle JDK的关系
    大多数 JDK 都是在 Open JDK 的基础上进一步编写实现的,比如 IBM J9, Oracle JDK 和 Azul Zulu,
    Azul Zing。
    Oracle JDK完全由 Oracle 公司开发,Oracle JDK是基于Open JDK源代码的商业版本。此外,它包含闭
    源组件。
    Oracle JDK根据二进制代码许可协议获得许可,在没有商业许可的情况下,在2019年1月之后发布的
    Oracle Java SE 8
    的公开更新将无法用于商业或生产用途。但是 Open JDK是完全开源的,可以自由使用。
    2.3 Open JDK 官网介绍
    Open JDK 官网: http://openjdk.java.net/ 。 JDK Enhancement Proposals(JDK增强建议)。通俗的讲JEP就是JDK的新特性
    小结
    Oracle JDK是基于Open JDK源代码的商业版本。我们要学习Java新技术可以去Open JDK 官网学习。
    二、Lambda表达式
  11. 需求分析
    创建一个新的线程,指定线程要执行的任务
    代码分析:
  12. Thread类需要一个Runnable接口作为参数,其中的抽象方法run方法是用来指定线程任务内容的
    核心
  13. 为了指定run方法体,不得不需要Runnable的实现类
  14. 为了省去定义一个Runnable 的实现类,不得不使用匿名内部类
    public static void main(String[] args) { // 开启一个新的线程 new Thread(new Runnable() { @Override public void run() { System.out.println("新线程中执行的代码 : "+Thread.currentThread().getName()); } }).start(); System.out.println(“主线程中的代码:” + Thread.currentThread().getName()); }
  15. 必须覆盖重写抽象的run方法,所有的方法名称,方法参数,方法返回值不得不都重写一遍,而且
    不能出错,
  16. 而实际上,我们只在乎方法体中的代码
    2.Lambda表达式初体验
    Lambda表达式是一个匿名函数,可以理解为一段可以传递的代码
    Lambda表达式的优点:简化了匿名内部类的使用,语法更加简单。
    匿名内部类语法冗余,体验了Lambda表达式后,发现Lambda表达式是简化匿名内部类的一种方式。
  17. Lambda的语法规则
    Lambda省去了面向对象的条条框框,Lambda的标准格式由3个部分组成:
    格式说明:
    (参数类型 参数名称):参数列表
    {代码体;} :方法体
    -> : 箭头,分割参数列表和方法体
    3.1 Lambda练习1
    练习无参无返回值的Lambda
    定义一个接口
    然后创建主方法使用
    new Thread(() -> { System.out.println(“新线程Lambda表达式…” +Thread.currentThread().getName()); }) .start(); (参数类型 参数名称) -> { 代码体; }public interface UserService { void show(); }public class Demo03Lambda { public static void main(String[] args) { goShow(new UserService() { @Override public void show() { System.out.println(“show 方法执行了…”); }
    输出:
    3.2 Lambda练习2
    完成一个有参且有返回值得Lambda表达式案例
    创建一个Person对象
    然后我们在List集合中保存多个Person对象,然后对这些对象做根据age排序操作
    }); System.out.println(“----------”); goShow(() -> { System.out.println(“Lambda show 方法执行了…”); }); }public static void goShow(UserService userService){ userService.show(); } }show 方法执行了… ---------- Lambda show 方法执行了… @Data @AllArgsConstructor @NoArgsConstructor public class Person { private String name; private Integer age; private Integer height; } public static void main(String[] args) { List list = new ArrayList<>(); list.add(new Person(“周杰伦”,33,175)); list.add(new Person(“刘德华”,43,185)); list.add(new Person(“周星驰”,38,177)); list.add(new Person(“郭富城”,23,170)); Collections.sort(list, new Comparator() { @Override public int compare(Person o1, Person o2) { return o1.getAge()-o2.getAge(); } }); for (Person person : list) { System.out.println(person);
    我们发现在sort方法的第二个参数是一个Comparator接口的匿名内部类,且执行的方法有参数和返回
    值,那么我们可以改写为Lambda表达式
    输出结果
  18. @FunctionalInterface注解
    } }public static void main(String[] args) { List list = new ArrayList<>(); list.add(new Person(“周杰伦”,33,175)); list.add(new Person(“刘德华”,43,185)); list.add(new Person(“周星驰”,38,177)); list.add(new Person(“郭富城”,23,170)); /Collections.sort(list, new Comparator() { @Override public int compare(Person o1, Person o2) { return o1.getAge()-o2.getAge(); } }); for (Person person : list) { System.out.println(person); }/ System.out.println(“------”); Collections.sort(list,(Person o1,Person o2) -> { return o1.getAge() - o2.getAge(); }); for (Person person : list) { System.out.println(person); } } Person(name=郭富城, age=23, height=170) Person(name=周杰伦, age=33, height=175) Person(name=周星驰, age=38, height=177) Person(name=刘德华, age=43, height=185) /*** @FunctionalInterface * 这是一个标志注解,被该注解修饰的接口只能声明一个抽象方法 */ @FunctionalInterface public interface UserService { void show(); }
  19. Lambda表达式的原理
    匿名内部类的本质是在编译时生成一个Class 文件。XXXXX$1.class
    还可以通过反编译工具来查看生成的代码 XJad 工具来查看
    那么Lambda表达式的原理是什么呢?我们也通过反编译工具来查看
    public class Demo01Lambda { public static void main(String[] args) { // 开启一个新的线程 new Thread(new Runnable() { @Override public void run() { System.out.println(“新线程中执行的代码 : “+Thread.currentThread().getName()); } }).start(); System.out.println(“主线程中的代码:” + Thread.currentThread().getName()); System.out.println(”---------------”); /new Thread(() -> { System.out.println(“新线程Lambda表达式…” +Thread.currentThread().getName()); }) .start();/ } }static class Demo01Lambda$1 implements Runnable { public void run() { System.out.println((new StringBuilder()).append(“新线程中执行的代码 : " ).append(Thread.currentThread().getName()).toString()); }Demo01LambdaKaTeX parse error: Expected 'EOF', got '}' at position 8: 1() {} }̲ 写的有Lambda表达式的c…mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …: 0: getstatic #̲5 // Field java…mainKaTeX parse error: Expected '}', got 'EOF' at end of input: …tic void lambdamainKaTeX parse error: Expected 'EOF', got '}' at position 50: …ow 方法执行了..."); }̲ } 为了更加直观的理解这个内…mainKaTeX parse error: Expected '}', got 'EOF' at end of input: …03Lambda.lambdamain$0(); } }); System.out.println(”----------"); }public static void goShow(UserService userService){
    小结:
    匿名内部类在编译的时候会产生一个class文件。
    Lambda表达式在程序运行的时候会形成一个类。
  20. 在类中新增了一个方法,这个方法的方法体就是Lambda表达式中的代码
  21. 还会形成一个匿名内部类,实现接口,重写抽象方法
  22. 在接口中重写方法会调用新生成的方法
    6.Lambda表达式的省略写法
    在lambda表达式的标准写法基础上,可以使用省略写法的规则为:
  23. 小括号内的参数类型可以省略
  24. 如果小括号内有且仅有一个参数,则小括号可以省略
  25. 如果大括号内有且仅有一个语句,可以同时省略大括号,return 关键字及语句分号。
    userService.show(); }private static void lambda$main$0(); System.out.println(“Lambda show 方法执行了…”); } }public class Demo05Lambda { public static void main(String[] args) { goStudent((String name,Integer age)->{ return name+age+" 6666 …“; }); // 省略写法 goStudent((name,age)-> name+age+” 6666 …“); System.out.println(”------“); goOrder((String name)->{ System.out.println(”—>" + name); return 666; }); // 省略写法 goOrder(name -> { System.out.println(“—>” + name); return 666; }); goOrder(name -> 666); }public static void goStudent(StudentService studentService){ studentService.show(“张三”,22); }public static void goOrder(OrderService orderService){ orderService.show(“李四”); }
    7.Lambda表达式的使用前提
    Lambda表达式的语法是非常简洁的,但是Lambda表达式不是随便使用的,使用时有几个条件要特别注
    意 1. 方法的参数或局部变量类型必须为接口才能使用Lambda
  26. 接口中有且仅有一个抽象方法(@FunctionalInterface)
    8.Lambda和匿名内部类的对比
    Lambda和匿名内部类的对比
  27. 所需类型不一样
    匿名内部类的类型可以是 类,抽象类,接口
    Lambda表达式需要的类型必须是接口
  28. 抽象方法的数量不一样
    匿名内部类所需的接口中的抽象方法的数量是随意的
    Lambda表达式所需的接口中只能有一个抽象方法
  29. 实现原理不一样
    匿名内部类是在编译后形成一个class
    Lambda表达式是在程序运行的时候动态生成class
    三、接口中新增的方法
  30. JDK8中接口的新增
    在JDK8中针对接口有做增强,在JDK8之前
    JDK8之后对接口做了增加,接口中可以有默认方法和静态方法
    }interface 接口名{ 静态常量; 抽象方法; }interface 接口名{ 静态常量; 抽象方法; 默认方法; 静态方法; }
    2.默认方法
    2.1 为什么要增加默认方法
    在JDK8以前接口中只能有抽象方法和静态常量,会存在以下的问题:
    如果接口中新增抽象方法,那么实现类都必须要抽象这个抽象方法,非常不利于接口的扩展的
    package com.bobo.jdk.inter; public class Demo01Interface { public static void main(String[] args) { A a = new B(); A c = new C(); } }interface A{ void test1(); // 接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展 void test2(); }class B implements A{ @Override public void test1() { }@Override public void test2() { } }class C implements A{ @Override public void test1() { }@Override public void test2() { } }
    2.2 接口默认方法的格式
    接口中默认方法的语法格式是
    interface 接口名{ 修饰符 default 返回值类型 方法名{ 方法体; } }package com.bobo.jdk.inter; public class Demo01Interface { public static void main(String[] args) { A a = new B(); a.test3(); A c = new C(); c.test3(); } }interface A{ void test1(); // 接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展 void test2(); /*** 接口中定义的默认方法 * @return */ public default String test3(){ System.out.println(“接口中的默认方法执行了…”); return “hello”; } }class B implements A{ @Override public void test1() { }@Override public void test2() { }@Override public String test3() { System.out.println(“B 实现类中重写了默认方法…”); return “ok …”; } }
    2.3 接口中默认方法的使用
    接口中的默认方法有两种使用方式
  31. 实现类直接调用接口的默认方法
  32. 实现类重写接口的默认方法
  33. 静态方法
    JDK8中为接口新增了静态方法,作用也是为了接口的扩展
    3.1 语法规则
    class C implements A{ @Override public void test1() { }@Override public void test2() { } }interface 接口名{ 修饰符 static 返回值类型 方法名{ 方法体; } }package com.bobo.jdk.inter; public class Demo01Interface { public static void main(String[] args) { A a = new B(); a.test3(); A c = new C(); c.test3(); A.test4(); } }interface A{ void test1(); // 接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展 void test2();
    /*** 接口中定义的默认方法 * @return / public default String test3(){ System.out.println(“接口中的默认方法执行了…”); return “hello”; }/** 接口中的静态方法 * @return */ public static String test4(){ System.out.println(“接口中的静态方法…”); return “Hello”; } }class B implements A{ @Override public void test1() { }@Override public void test2() { }@Override public String test3() { System.out.println(“B 实现类中重写了默认方法…”); return “ok …”; } }class C implements A{ @Override public void test1() { }@Override public void test2() { } }
    3.2 静态方法的使用
    接口中的静态方法在实现类中是不能被重写的,调用的话只能通过接口类型来实现: 接口名.静态方法名
    ();
  34. 两者的区别介绍
  35. 默认方法通过实例调用,静态方法通过接口名调用
  36. 默认方法可以被继承,实现类可以直接调用接口默认方法,也可以重写接口默认方法
  37. 静态方法不能被继承,实现类不能重写接口的静态方法,只能使用接口名调用
    四、函数式接口
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值