以下内容为B站动力节点的JAVA基础课程2024全部内容,课程链接如下:https://www.bilibili.com/video/BV1p7421N7XT/,该笔记根据课程资料整理,顺序按照课程PPT截图整理,附有部分个人的问题和重点整理,如有侵权请联系下架,后续会持续更新整理课程中的重难点,课程中有很多重点和细节部分值得反复思考、消化,个人觉得是很不错的JAVA课程
- Lambda表达式的概述
- Lambda表达式的使用
- Lambda表达式的方法引用
- Lambda表达式的在集合中的使用
Lambda表达式的引入
针对以上对List集合的的“降序”排序操作,除了使用匿名内部类来实现外,还可以使用Lambda表达式来实现,使用Lambda表达式的代码非常优雅,并且还非常的简洁,代码如下:
函数式编程思想的概述
- 面向对象的思想
- 做一件事情,找一个能解决这个事情的对象,然后调用对象的方法,最终完成事情。
- 函数式编程思想
- 只要能获得结果,谁去做的,怎么做的都不重要,重视的是结果,不重视实现过程。
在函数式编程语言中,函数被当成一等公民对待。在将函数当成一等公民的编程语言中,Lambda表达式的类型是函数,但是Lambda表达式却是一个对象,而不是函数,它们必须依附于一类特别的对象类型,也就是所谓的函数式接口。
简单点说,JDK1.8中的Lambda表达式就是一个函数式接口的实例,这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以使用Lambda表达式来表示。
如何去理解函数式接口
能够使用Lambda表达式的一个重要依据是必须有相应的函数式接口,所谓的函数式接口,指的就是“一个接口中有且只能有一个抽象方法”。也就是说,如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口。
如果我们在接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,也就是该接口中有且只能定义一个抽象方法,如果该接口中定义了多个或0个抽象方法,则程序编译时就会报错。
【示例】定义一个函数式接口
Lambda和匿名内部类
- 所需类型不同
- 匿名内部类:可以是接口,抽象类,具体类。
- Lambda表达式:只能是接口。
- 使用限制不同
- 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类。
- 如果接口中有多个抽象方法,则就只能使用匿名内部类,而不能使用Lambda表达式。
- 实现原理不同
- 匿名内部类:编译之后,会生成一个单独的.class字节码文件。
- Lambda表达式:编译之后,没有生成一个单独的.class字节码文件。
Lambda表达式的语法
Lambda表达式本质就是一个匿名函数,在函数的语法中包含返回值类型、方法名、形参列表和方法体等,而在Lambda表达式中我们只需要关心形参列表和方法体即可。
在Java语言中,Lambda表达式的语法为“(形参列表) -> {方法体}”,其中“->”为 lambda操作符或箭头操作符,“形参列表”为对应接口实现类中重写方法的形参列表,“方法体”为对应接口实现类中重写方法的方法体。
接下来,我们就以匿名内部类为例,从而将匿名内部类演化为Lambda表达式,代码如下:
在以上的匿名内部类中,黄色背景颜色标注的代码都属于不可变的固定代码,而红色背景颜色标注的代码,属于可变的并且是完成该功能的核心代码。因此,将此处的匿名内部类转化为Lambda表达式,我们只需保留红色部分的形参列表和方法体即可,对应的Lambda表达式代码实现如下:
在以上代码中,黄色背景颜色标注的就是重写于Comparator接口中抽象方法的形参列表,而红色背景颜色标注的就是重写方法对应方法体的代码实现。因此Lambda本质上就是去掉了一堆没有意义的代码,只留下核心的代码逻辑,从而让代码看起来更加的简洁且优雅。
Lambda表达式的使用
Lambda表达式的基本使用
接下来,我们以自定义的函数式接口为例,先从匿名对象的实现过程,慢慢演变为Lambda表达式的实现过程。另外,使用Lambda表达式的时候,则必须有上下文环境,才能推导出Lambda对应的接口类型。
无返回值函数式接口
情况一:无返回值无参数
情况二:无返回值一个参数
情况三:无返回值多个参数
有返回值函数接口
情况一:有返回值无参数
情况二:有返回值一个参数
情况三:有返回值多个参数
Lambda表达式的语法精简
- 形参类型可以省略,如果需要省略,则每个形参的类型都要省略。
- 如果形参列表中只存在一个形参,那么形参类型和小括号都可以省略。
- 如果方法体当中只有一行语句,那么方法体的大括号也可以省略。
- 如果方法体中只有一条return语句,那么大括号可以省略,且必须去掉return关键字。
接下来,我们就对以下的Lambda表达式代码进行精简,从而写出更加优雅的代码。
四个基本的函数式接口
以上的函数式接口都在java.util.function包中,通常函数接口出现的地方都可以使用Lambda表达式,所以不必记忆函数接口的名字,这些函数式接口及子接口在后续学习中很常用。
方法引用的概述
实例方法引用
语法:对象 :: 实例方法
特点:在Lambda表达式的方法体中,通过“对象”来调用指定的某个“实例方法”。
要求:函数式接口中抽象方法的返回值类型和形参列表 与 内部通过对象调用某个实例方法的返回值类型和形参列表 保持一致。
【示例】实例化Consumer接口的实现类对象,并在重写的accept()方法中输出形参的值
【示例】实例化Supplier接口的实现类对象,并在重写方法中返回Teacher对象的姓名
静态方法引用
语法:类 :: 静态方法
特点:在Lambda表达式的方法体中,通过“类名”来调用指定的某个“静态方法”。
要求:函数式接口中抽象方法的返回值类型和形参列表 与 内部通过类名调用某个静态方法的返回值类型和形参列表保持一致。
【示例】实例化Function接口的实现类对象,并在重写的方法中返回小数取整的结果
特殊方法引用
语法:类名 :: 实例方法
特点:在Lambda表达式的方法体中,通过方法的第一个形参来调用指定的某个“实例方法”。
要求:把函数式接口中抽象方法的第一个形参作为方法的调用者对象,并且从第二个形参开始(或无参)可以对应到被调用实例方法的参数列表中,并且返回值类型保持一致。
【示例】使用Comparator比较器,来判断两个小数的大小
需求:实例化Function接口的实现类对象,然后获得传入Teacher对象的姓名。
构造方法引用
语法:类名 :: new
特点:在Lambda表达式的方法体中,返回指定“类名”来创建出来的对象。
要求:创建对象所调用构造方法形参列表 和 函数式接口中的方法的形参列表 保持一致,并且方法的返回值类型和创建对象的类型保持一致。
【示例】实例化Supplier接口的实现类对象,然后调用重写方法返回Teacher对象
【示例】实例化Function接口的实现类对象,然后调用重写方法返回Teacher对象
数组引用
语法:数组类型 :: new
特点:在Lambda表达式的方法体中,创建并返回指定类型的“数组”。
要求:重写的方法有且只有一个整数型的参数,并且该参数就是用于设置数组的空间长度,并且重写方法的返回值类型和创建数组的类型保持一致。
【示例】实例化Function接口的实现类对象,并在重写方法中返回指定长度的int类型数组
为了能够让Lambda和Java的集合类集更好的一起使用,集合当中也新增了部分方法,以便与Lambda表达式对接,要用Lambda操作集合就一定要看懂源码。
forEach()方法
在Collection集合和Map集合中,都提供了forEach()方法用于遍历集合。
在Collection集合中,提供的forEach()方法的形参为Consumer接口(消费型接口),通过该方法再配合Lambda表达式就可以遍历List和Set集合中的元素。
【示例】遍历List集合中的元素
【示例】遍历Set集合中的元素
removeIf()方法
【示例】删除Set集合中的某个元素
- Stream API的概述
- 创建Stream的方式
- Stream的中间操作
- Stream的终止操作
什么是StreamAPI呢? (JAVA 流式编程)
Stream和Collection的区别
Collection:是静态的内存数据结构,强调的是数据。
Stream API:是跟集合相关的计算操作,强调的是计算。
总结:Collection面向的是内存,存储在内存中;StreamAPI面向的是CPU,通过CPU来计算。
Stream API的操作步骤
- 第一步:创建Stream
- 通过数据源(如:集合、数组等)来获取一个Stream对象 。
- 第二步:中间操作
- 对数据源的数据进行处理,该操作会返回一个Stream对象,因此可以进行链式操作。
- 第三步:终止操作
- 执行终止操作时,则才会真正执行中间操作,并且并返回一个计算完毕后的结果。
Stream API的重要特点
- Stream自己不会存储元素,只能对元素进行计算。
- Stream不会改变数据对象,反而可能会返回一个持有结果的新Stream。
- Stream上的操作属于延迟执行,只有等到用户真正需要结果的时候才会执行。
- Stream一旦执行了终止操作,则就不能再调用其它中间操作或终止操作了。
通过Collection接口提供的方法
通过Collection接口提供的stream()方法来创建Stream流。
通过Arrays类提供的方法
通过Arrays类提供的stream()静态方法来创建Stream流。
注意:Stream、IntStream、LongStream和DoubleStream都继承于BaseStream接口。
使用Stream接口提供的方法
通过Stream接口提供的of(T… values)静态方法来创建Stream流。
顺序流和并行流的理解
在前面获得Stream对象的方式,我们都称之为“顺序流”,顺序流对Stream元素的处理是单线程的,即一个一个元素进行处理,处理数据的效率较低。
如果Stream流中的数据处理没有顺序要求,并且还希望可以并行处理Stream的元素,那么就可以使用“并行流”来实现,从而提高处理数据的效率。
一个普通Stream转换为可以并行处理的Stream非常简单,只需要用调用Stream提供的parallel()方法进行转换即可,这样就可以并行的处理Stream的元素。那么,我们不需要编写任何多线程代码就可以享受到并行处理带来的执行效率的提升。
【示例】把顺序流转化为并行流
筛选(filter)
映射(map)
除重(distinct)
排序(sorted)
合并(concat)
截断和跳过
跳过(skip),指的就是跳过n个元素开始操作,此处使用Stream接口提供的“Stream skip(long n);”方法来实现。
截断(limit),指的是截取n个元素的操作,此处使用Stream接口提供的“Stream limit(long maxSize);”方法来实现。
【示例】从指定位置开始截取n个元素
触发终止操作时才会真正执行中间操作,终止操作执行完毕会返回计算的结果,并且终止操作执行完毕那么操作的Stream就失效,也就是不能再执行中间操作或终止操作啦。
遍历(forEach)
匹配(match)
匹配(match),就是判断Stream中是否存在某些元素,Stream接口提供的匹配方法如下:
- boolean allMatch(Predicate<? super T> predicate); 检查是否匹配所有的元素
- boolean anyMatch(Predicate<? super T> predicate); 检查是否至少匹配一个元素
- boolean noneMatch(Predicate<? super T> predicate); 检查是否一个元素都不匹配
- Optional findFirst(); 获得第一个元素
归约(reduce)
归约(reduce),将所有元素按照指定的规则合并成一个结果。在Stream接口中,常用的归约方法如下:
- Optional reduce(BinaryOperator accumulator);
- T reduce(T identity, BinaryOperator accumulator);
【示例】归约操作的案例
reduce操作可以实现从一组元素中生成一个值,而max()、min()、count()等方法都属于reduce操作,将它们单独设为方法只是因为常用,在Stream接口中这些方法如下:
long count(); 获得元素的个数
Optional max(Comparator<? super T> comparator); 获得最大的元素
Optional min(Comparator<? super T> comparator); 获得最小的元素
【示例】获得最大、最小和元素的个数
收集(collect)
归集(toList/toSet/toMap)
【示例】获得年龄大于20岁的女同学,然后返回按照年龄进行升序排序后的List集合
统计(counting/averaging)
Collectors提供了一系列用于数据统计的静态方法:
- 计数:counting
- 平均值:averagingInt、averagingLong、averagingDouble
- 最值:maxBy、minBy
- 求和:summingInt、summingLong、summingDouble
- 统计以上所有:summarizingInt、summarizingLong、summarizingDouble
【示例】对学生的年龄进行统计
分组(groupingBy)
接合(joining)
- 新特性的概述
- 新语法的结构
- API层面的变化
纵观Java这几年的版本变化,在Java被收入Oracle之后,Java以小步快跑的迭代方式,在功能更新上迈出了更加轻快的步伐。基于时间发布的版本,可以让Java研发团队及时获得开发人员的反馈,因此可以看到最近的Java版本,有很多语法层面简化的特性。同时,Java在支持容器化场景,提供低延迟的GC方面(ZGC等)也取得了巨大的进步。
注意一个新特性的出现通常会经过以下阶段:
- 孵化器(Incubator)阶段:这是新特性最早的开发和试验阶段,此时新特性只能作为一个单独的模块或库出现,而不会包含在Java SE中。在这个阶段,特性的设计可能会有些不稳定,而且会经常调整和变更。
- 预览(Preview)阶段:在经过了孵化器阶段的验证和修改后,新特性进入了预览阶段,这是一种在Java SE内部实现的,开发人员可以使用并对其提供反馈的渠道。此时特性可能被包含在Java SE版本中,但是它默认是未开启的,需要通过特定的命令行参数或其他方式进行启用。
- 正式版(GA)阶段:在经过了预览阶段的反复测试和修复后,新特性最终会在Java SE的稳定版本中发布。此时,特性被默认开启,成为Java SE的一部分,并可以在各个Java应用程序中使用。
需要注意的是,上述阶段并非一成不变,并不是所有JEP(Java Enhancement Proposal:Java增强方案)都需要经过孵化器阶段和预览阶段,这取决于特定的提案和规划。但是,Java SE领导小组通常会遵循这些阶段的流程,以确保新特性可以经过充分的评估和测试,以便能够稳定和可靠地使用在Java应用程序中。
在以下的内容中,我们对Java9到Java21新特性做一个简单的概述。
Java9新特性
Java9经过4次推迟,历经曲折的Java9最终在2017年9月21日发布,提供了超过150项新功能特性。
- JEP 261: Module System
- JDK 9 开始引入的一种全新的模块化编程方式。JPMS 的目的是为了更好地支持大型应用程序的开发和维护,同时也可以使 Java 程序在更为动态、可移植和安全的环境下运行。
- JEP 222: jshell: The Java Shell (Read-Eval-Print Loop)
- 一种交互式的 Java Shell,可以在命令行上快速地进行 Java 代码的编写、验证和执行,从而提高开发者的生产力。
- JEP 213: Milling Project Coin(细化工程改进,该计划旨在引入小型语言特性来提高代码的简洁性和可读性)
- 在Java 9中,@SafeVarargs注解可以用于一个私有实例方法上。在Java 7和Java 8中,@SafeVarargs注解只能用于静态方法、final实例方法和构造函数。
- 在Java 9中,可以将效果等同于final变量作为try-with-resources语句块中的资源来使用。在Java 7/8中,try-with-resources语句块中的资源必须是显式的final或事实上的final(即变量在初始化后未被修改),否则编译器会报错。这个限制限制了Java程序员使用try-with-resources语句块的能力,特别是在涉及lambda表达式、匿名类或其他读取外部变量的代码段时。
- Java 9允许在匿名类实例化时使用钻石操作符(<>)来简化代码,但参数类型必须是具体的、可推导的类型。
- 从Java9开始,不能使用一个单一的“_”作为标识符了。
- 从Java9开始,接口中支持定义私有方法。
- JEP 224: HTML5 Javadoc
- 从Java9开始,javadoc开始支持HTML5的语法。
- JEP 254: Compact Strings
- 一种新的字符串表示方式,称为紧凑型字符串,以提高Java应用程序的性能和内存利用率。通过String源码得知:char[] 变成了 byte[]。
- JEP 269: Convenience Factory Methods for Collections
- 更加方便的创建只读集合:List.of(“abc”, “def”, “xyz”);
- JEP 269:对Stream API进行了增强
- 其中最显著的是引入了四个新的方法,分别是 , , 和
- JEP 110:一个新的HTTP客户端API,名为HttpClient,它是一种基于异步和事件驱动的方式,更加高效和灵活的HTTP客户端。
Java10新特性
2018年3月21日,Oracle官方宣布JAVA10正式发布。JAVA10一共定义了109个新特性,其中包含JEP,对开发人员来说,真正的新特性也就一个,还有一些新的API和JVM规范以及JAVA语言规范上的改动。
- JEP 286:局部变量类型推断
- JEP 296:将 JDK 森林合并到单个存储库中
- JEP 304:垃圾收集器接口
- JEP 307:G1 的并行完整 GC
- JEP 310:应用程序类数据共享
- JEP 312:线程局部握手
- JEP 313:删除本机头生成工具 (javah)
- JEP 314:附加 Unicode 语言标签扩展
- JEP 316:替代内存设备上的堆分配
- JEP 317:基于 Java 的实验性 JIT 编译器
- JEP 319:根证书
- JEP 322:基于时间的发布版本控制
Java11新特性
2018年9月26日,Oracle官方发布JAVA11。这是JAVA大版本周期变化后的第一个长期支持版本,官方支持到2026年。
- JEP 181:基于 Nest 的访问控制
- JEP 309:动态类文件常量
- JEP 315:改进 Aarch64 内部函数
- JEP 318:Epsilon:无操作垃圾收集器
- JEP 320:删除 Java EE 和 CORBA 模块
- JEP 321:HTTP 客户端(标准)
- JEP 323:本地变量语法LAMBDA参数
- JEP 324:与Curve25519密钥协商和Curve448
- JEP 327:Unicode的10
- JEP 328:飞行记录器
- JEP 329:ChaCha20和Poly1305加密算法
- JEP 330:启动单文件源代码程序
- JEP 331:低开销堆纹
- JEP 332:传输层安全性 (TLS) 1.3
- JEP 333:ZGC:可扩展的低延迟垃圾收集器(实验性)
- JEP 335:弃用 Nashorn JavaScript 引擎
- JEP 336:弃用 Pack200 工具和 API
Java12新特性
2019年3月19日,java12正式发布。
- JEP 189:Shenandoah:一个低暂停时间的垃圾收集器(实验性)
- JEP 230:微基准套件
- JEP 325:switch表达式(预览)
- JEP 334:JVM 常量 API
- JEP 340:一个 AArch64 端口
- JEP 341:默认 CDS 档案
- JEP 344:G1 支持可中断的 Mixed GC
- JEP 346:及时从 G1 返回未使用的已提交内存
Java13新特性
- JEP 350:动态 CDS 档案
- JEP 351:ZGC:取消提交未使用的内存
- JEP 353:重新实现旧的 Socket API
- JEP 354:开关表达式(预览)
- JEP 355:文本块(预览)
Java14新特性
- JEP 305:instanceof 的模式匹配(预览)
- JEP 343:包装工具(孵化器)
- JEP 345:G1 的 NUMA 感知内存分配
- JEP 349:JFR 事件流
- JEP 352:非易失性映射字节缓冲区
- JEP 358:有用的空指针异常
- JEP 359:记录(预览)
- JEP 361: switch表达式(标准)
- JEP 362:弃用 Solaris 和 SPARC 端口
- JEP 363:删除并发标记清除 (CMS) 垃圾收集器
- JEP 364:macOS 上的 ZGC
- JEP 365:Windows 上的 ZGC
- JEP 366:弃用 ParallelScavenge + SerialOld GC 组合
- JEP 367:删除 Pack200 工具和 API
- JEP 368:文本块(第二次预览)
- JEP 370:外部内存访问 API(孵化器)
Java15新特性
- JEP 339:爱德华兹曲线数字签名算法 (EdDSA)
- JEP 360:密封类(预览)
- JEP 371:隐藏类
- JEP 372:删除 Nashorn JavaScript 引擎
- JEP 373:重新实现旧版 DatagramSocket API
- JEP 374:禁用和弃用偏向锁定
- JEP 375:instanceof 的模式匹配(第二次预览,无改动)
- JEP 377:ZGC:可扩展的低延迟垃圾收集器(确定正式版)
- JEP 378:文本块(确定正式版)
- JEP 379:Shenandoah:一个低暂停时间的垃圾收集器(确定正式版)
- JEP 381:删除 Solaris 和 SPARC 端口
- JEP 383:外内存访问API(第二孵化器)
- JEP 384:记录(第二次预览)
- JEP 385:弃用 RMI 激活以进行删除
Java16新特性
- JEP 338:Vector API(孵化器)
- JEP 347:启用 C++14 语言功能
- JEP 357:从 Mercurial 迁移到 Git
- JEP 369:迁移到 GitHub
- JEP 376:ZGC:并发线程栈处理
- JEP 380:Unix 域套接字通道
- JEP 386:Alpine Linux 端口
- JEP 387:弹性元空间
- JEP 388:Windows/AArch64 端口
- JEP 389:外链 API(孵化器)
- JEP 390:基于值的类的警告
- JEP 392:打包工具
- JEP 393:外内存访问API(第三孵化器)
- JEP 394:instanceof 的模式匹配
- JEP 395:记录
- JEP 396:默认情况下强封装JDK内部
- JEP 397:密封类(第二次预览)
Java17新特性
2021年9月14日,java17正式发布(LTS)。长期支持版,支持到2029年。Oracle 宣布,从JDK17开始,后面的JDK都全部免费提供。
- JEP 306:恢复始终严格的浮点语义
- JEP 356:增强型伪随机数发生器
- JEP 382:新的 macOS 渲染管线
- JEP 391:macOS/AArch64 端口
- JEP 398:弃用 Applet API 以进行删除
- JEP 403:强封装JDK内部
- JEP 406:switch模式匹配(预览)
- JEP 407:删除 RMI 激活
- JEP 409:密封类(正式确定)
- JEP 410:删除实验性 AOT 和 JIT 编译器
- JEP 411:弃用安全管理器以进行删除
- JEP 412:外部函数和内存 API(孵化器)
- JEP 414:Vector API(第二孵化器)
- JEP 415:上下文特定的反序列化过滤器
Java18新特性
2022年3月22日发布。非长期支持版本。
- JEP 400:从JDK18开始,UTF-8是Java SE API的默认字符集。
- JEP 408:从JDK18开始,引入了jwebserver这样一个简单的WEB服务器,它是一个命令工具。
- JEP 416:使用方法句柄重新实现核心反射
- JEP 418:互联网地址解析SPI
- JEP 413:Java API文档中的代码段(javadoc注释中使用括起来的代码段会原模原样的生成到帮助文档中)
- JEP 417:Vector API(第三孵化器)
- JEP 419:Foreign Function & Memory API(第二孵化器)
- JEP 420:switch 的模式匹配(第二次预览)
- JEP 421:Object中的finalize()方法被移除
Java19新特性
2022年9月20日发布。非长期支持的版本。直到 2023 年 3 月它将被 JDK 20 取代。
- JEP 425:虚拟线程(预览版)
- 一种新的线程模型,即虚拟线程;“虚拟线程” 指的是一种轻量级线程,可以通过 JVM 进行管理和调度,而不需要操作系统进行支持
- JEP 428:结构化并发(孵化器)
- 一组新的API和规范,用于优化并简化Java程序的并发编程
- JEP 405:Record模式 (预览版)
- JEP 427:switch语句中的模式匹配(第三次预览版)
- "switch语句中的模式匹配"表示该特性是针对 switch 语句的改进,可以使用模式匹配的方式处理 switch 语句中的分支
- JEP 424:外部函数和内存API(预览版)
- “外部函数”指的是在Java程序中调用非Java语言编写的函数,比如C/C++函数
- “内存API”指的是在Java程序中直接操作内存的API
- JEP 426:向量API(第四版孵化器)
- 一组专用于向量化处理的API,允许在Java程序中轻松高效地执行向量化计算
Java20新特性
2023年3月21日发布。非长期支持版本。直到 2023 年 9月它将被 JDK 21 取代。
- JEP 432: Record模式(第二次预览版)
- JEP 433: switch的模式匹配 (第四次预览版)
- JEP 434: 外部函数和内存API(第二次预览版)
- JEP 438: 向量API (第五版孵化器)
- JEP 429: Scoped Values (Incubator)
- JEP 436: 虚拟线程(第二次预览版)
- JEP 437: 结构化并发(第二版孵化器)
Java21新特性
2023年9月19日发布。长期支持版本。
- JEP 440:Record模式(正式确定)
- JEP 441:switch的模式匹配(正式确定)
- JEP 430:String Templates (Preview)
- JEP 443:Unnamed Patterns and Variables (Preview)
- JEP 445:Unnamed Classes and Instance Main Methods (Preview)
- JEP 444:Virtual Threads(正式确定)
- JEP 431:Sequenced Collections(正式确定)
- JEP 452:Key Encapsulation Mechanism API
- JEP 442:Foreign Function & Memory API (Third Preview)
- JEP 453:Structured Concurrency (Preview)
- JEP 446:Scoped Values (Preview)
- JEP 448:Vector API (Sixth Incubator)
- JEP 439:Generational ZGC
- JEP 451:Prepare to Disallow the Dynamic Loading of Agents
jShell命令
jShell命令是Java9引进的新特性,像Python和Scala之类的语言早就有交互式编程环境REPL (read-evaluate-print-loop),以交互式的方式对语句和表达式进行求值。开发者只需要输入一些代码,就可以在编译前获得对程序的反馈。而之前的Java 版本要想执行代码,必须创建文件、声明类、提供测试方法方可实现。
我们打开DOS命令窗口,然后输入jshell,就能进入交互式编程环境REPL,如下图所示:
通过jShell命令,我们能够定义一些变量,并执行相关的运算操作,如下图所示:
通过jShell命令,我们能够定义方法,并执行调用方法的操作,如下图所示:
想要查看JShell提供的所有指令,则直接输入“/help”即可,如下图所示:
想要查看书写的所有代码,则直接输入“/list”指令即可,如下图所示:
想要查看定义的所有变量,则直接输入“/vars”指令即可,如下图所示:
想要查看定义的所有方法,则直接输入“/methods”指令即可,如下图所示:
想要将输入的历史代码片段保存到文件中,就需要使用“ /save”指令,如下图所示:
try-with-resources
众所周知,所有被打开的系统资源,比如流、文件、Socket连接等,都需要被开发者手动关闭,否则随着程序的不断运行,资源泄露将会累积成重大的生产事故。
在Java7以前,我们想要关闭资源就必须的finally代码块中完成。
【示例】Java7之前资源的关闭的方式
Java7及以后关闭资源的正确姿势:try-with-resource,该语法格式为:
使用try-with-resource来自动关闭资源,则需要关闭资源的对象对应的类就必须实现java.lang.AutoCloseable接口,该接口中提供了一个close()的抽象方法,而自动关闭资源默认调用的就是实现于java.lang.AutoCloseable接口中的close()方法。
因为FileInputStream类和FileOutputStream类都属于java.lang.AutoCloseable接口的实现类,因此此处文件拷贝的操作就可以使用try-with-resource来自动关闭资源。
【示例】Java7之后资源的关闭的方式
通过try-with-resource来关闭放资源,即使资源很多,代码也可以写的很简洁,如果用Java7之前的方式去关闭资源,那么资源越多,用finally关闭资源时嵌套也就越多。
在Java9之后,为了避免在try后面的小括号中去实例化很多需要关闭资源的对象(复杂),则就可以把需要关闭资源的多个对象在try之前实例化,然后在try后面的小括号中引用需要关闭资源的对象即可,从而提高了代码的可读性。
【示例】Java9之后的使用方式
在以上代码中,表达式中引用了fis和fos,那么在fis和fos就自动变为常量啦,也就意味着在try代码块中不能修改fis和fos的指向,从而保证打开的资源肯定能够关闭。
局部变量类型判断
instanceof的模式匹配
【示例】重写equals(),判断成员变量是否相等
switch表达式
目前switch表达式的问题:
- 匹配自上而下,若无break,后面的case语句都会执行
- 不同的case语句定义的变量名不能相同
- 不能在一个case后面写多个值
- 整个switch不能作为表达式的返回值
文本块
在Java语言中,通常需要使用String类型表达HTML,XML,SQL或JSON等格式的字符串,在进行字符串赋值时需要进行转义和连接操作,然后才能编译该代码,这种表达方式难以阅读并且难以维护。
在Java12版本中,新增了文本块(预览)。文本块就是指多行字符串,例如一段格式化后的xml、json等。而有了文本块以后,用户不需要转义,Java能自动搞定。因此,文本块将提高Java程序的可读性和可写性。
【示例】演示文本块的使用
Record
早在2019年2月份,Java语言架构师Brian Goetz就吐槽了Java语言,他和很多程序员一样抱怨“Java太啰嗦”或有太多的“繁文缛节”,他提到:开发人员想要创建纯数据载体类,通常都必须编写大量低价值、重复的、容易出错的代码。例如:构造方法、getter/setter、equals()、hashCode()以及toString()等。
以至于很多人选择使用IDE的功能来自动生成这些代码。还有一些开发会选择使用一些第三方类库,如Lombok等来生成这些方法,从而会导致了令人吃惊的表现和糟糕的可调试性。
那么,Brian Goetz大神提到的纯数据载体到底指的是什么呢?我们举了一个简单的例子:
Record类的特点:
状态声明中的每个属性,都是默认采用了private和final修饰,则属性值就不可修改
在Record类中,默认已经重写了Object类提供的equals(),hashcode(),toString()方法
在Record类中,默认提供全参的构造方法,并且提供的getter方法名和属性名保持一致。
Record类采用了final修饰,并且显示的继承于java.lang.Record类,因此就不能继承别的父类。
【示例】将以上的Tiger类转化为Record类
在以上的Record类中,Tiger类默认采用了final修饰,并且显示的继承于java.lang.Record抽象类,因此Tiger类就不能继承于别的父类。在Tiger类中,提供了name和age两个私有常量,并且还提供了一个public修饰的全参构造方法,提供的getter方法的名字和属性名保持一致,但是并没有提供setter方法。并且,在Tiger类中还重写了Object类提供的equals(),hashcode(),toString()方法。
在Record类中,我们还可以新增静态属性、无参构造方法、成员方法和静态方法,但是创建对象时不能调用无参构造方法,而是通过全参构造方法创建对象的时候,默认就会调用Record类中的无参构造方法。
【示例】在Record类中添加的内容
密封类
Java中的密封类是一种新的类修饰符,它可以修饰类和接口,可以控制哪些类可以扩展或实现该类或接口。下面是密封类的一些主要用途:
- 维护类层次结构的封闭性
密封类的一个主要用途是确保类层次结构的封闭性。这意味着,如果您想保护一组类,而不希望其他类继承或实现它们,可以使用密封类来实现这一目标。这对于确保代码的安全性和稳定性非常有用。
- 预防代码的意外扩展
密封类可以防止其他程序员意外地扩展一个类。在进行类设计时,您可能希望自己或其他程序员只能在特定的类中实现或继承指定的类。在这种情况下,您可以将类标记为“密封”,强制限制其他程序员可以实现或继承的类的范围。
- 增强代码的可读性和可维护性
在Java15版本中,新增了密封类和密封接口(预览)。
使用sealed关键字修饰的类,我们就称之为密封类。密封类必须是一个父类,我们可以使用permits关键字来指定哪些子类可以继承于密封类,并且密封类的子类必须使用sealed、final或non-sealed来修饰。
【示例】密封类的演示
sealed与record:
因为Record类默认采用了final关键字修饰,因此Record类就可以作为密封接口的实现类。
【示例】密封接口和Record类
String存储结构改变
在Java8及其之前,String底层采用char类型数组来存储字符;在Java9及其以后,String底层采用byte类型的数组来存储字符。将char[]转化为byte[],其目的就是为了节约存储空间。
String 新增的方法
在Java11版本中,对String类新增了一些方法,新增的方法如下:
在Java12版本中,对String类新增了一些方法,新增的方法如下:
接口支持私有方法
标识符命名的变化
在Java8及其之前,标识符可以独立使用“_”来命名。
但是,在Java9中规定“_”不能独立命名标识符了,如果使用就会报错:
简化编译运行程序
执行java命令进行运行,如下图所示:
创建不可变集合
Arrays.asList与List.of的区别:
List.of:不能向集合中添加或删除元素,也不能修改集合中的元素。
Arrays.asList:不能向集合中添加或删除元素,但是可以修改集合中的元素。
【示例】Arrays.asList与List.of的区别
Optional API
创建Optional对象
使用Optional类提供的of()和ofNullable() 静态方法来创建包含值的Optioanal实例。
如果将null当作参数传进去of()会抛出空指针异常,如果将null当作参数传进去 ofNullable() 就不会抛出空指针异常。
因此当对象可能存在或者不存在,应该使用 ofNullable()方法来创建Optional实例。
【示例】创建一个Optional实例
Optional类的方法
想要获得Optional实例中包含的值,那么就可以使用以下两个方法来实现。
【示例】演示orElse(T other)方法
Optional的使用案例
需求:有一场商业表演,原计划让“刘亦菲”来表演,如果“刘亦菲”不能参加,则就换“佟丽娅”来表演,该需求的实现代码如下:
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/java-jiao-cheng/10013.html