Java版本新特性
Java8
Lambda表达式
所作的一切操作都是以是函数式接口为前提
函数式接口
定义:一个接口里面只有一个抽象方法那么这个接口就是函数式接口
例:
public interface Runnable{
public abstract void run();
}
发展历程
定义一个接口 interface ILike
- 一个实现类去实现接口
class Like implement ILike
- 静态内部类去实现接口 类:
static class Like implement ILike
- 局部内部类去实现接口 方法:
class Like implement ILike
- 匿名内部类去实现接口
对象名 = new ILike(){ ... }
- 使用 Lambda
对象名 = () -> { ... }
格式
对象名 = () -> { ... };
对象名 = (int i) -> { ... };
对象名 = (i) -> { ... };
对象名 = i -> { ... };
对象名 = i -> ...;
7行:前提是有且只有一个参数
,才能省略小括号
9行:前提是有且只有一行内容
(;
之前),才能省略大括号
Optional类
用途:更好的处理空指针异常
API
of(T value)
:创建一个包含非空值的 Optional 对象。如果传入的值为 null,则会抛出 NullPointerException。ofNullable(T value)
:创建一个 Optional 对象,可以包含空值。如果传入的值为 null,则返回一个空的 Optional 对象。empty()
:创建一个空的 Optional 对象,不包含任何值。isPresent()
:如果 Optional 对象包含非空值,则返回 true;否则返回 false。ifPresent(Consumer<? super T> consumer)
:如果 Optional 对象包含非空值,则执行传入的操作。get()
:如果 Optional 对象包含非空值,则返回该值;否则抛出 NoSuchElementException 异常。orElse(T other)
:如果 Optional 对象包含非空值,则返回该值;否则返回传入的默认值。orElseGet(Supplier<? extends T> supplier)
:如果 Optional 对象包含非空值,则返回该值;否则返回由 Supplier 提供的值。orElseThrow(Supplier<? extends X> exceptionSupplier)
:如果 Optional 对象包含非空值,则返回该值;否则抛出由 Supplier 提供的异常。map(Function<? super T,? extends U> mapper)
:对 Optional 对象中的值进行转换,并返回一个新的 Optional 对象。flatMap(Function<? super T,Optional<U>> mapper)
:对 Optional 对象中的值进行转换,并返回一个新的 Optional 对象,可以避免嵌套的 Optional。
Java9
模块机制
模块机制提供了另一个级别的Java代码的可见性、可访问性的控制
它做了包与包之间的隔离,按需导入
module com.example.myapp {
requires java.base;
requires com.example.mylibrary;
exports com.example.myapp;
}
在上面的代码中,我们定义了一个名为com.example.myapp的模块。它声明了对java.base模块的依赖,以及对com.example.mylibrary模块的依赖。还通过exports语句将com.example.myapp包导出,以使其他模块可以访问该包中的类
......
JShell
让其使用命令行的交互式编程,支持一条一条命令进行操作,配置好环境变量之后输入jshell即可开始
接口中private
在Java8中接口支持添加default关键字来添加默认实现,在Java9中接口可以存在私有方法
public interface Main {
default void fun1() {
// 默认实现
System.out.println(3.1415926);
}
private void fun2() {
// 私有方法
System.out.println(3.1415926);
}
}
在接口中定义私有方法,一般是默认实现和静态方法使用
私有方法必须提供方法体
集合类工厂方法
// 普通创建的map
Map<String, String> map = new HashMap<>();
map.put("k1", "v1");
map.put("k2", "v2");
// 快速创建
Map<String, String> map2 = Map.of("k1", "v1", "k2", "v2");
List.of(...);
Set.of(...);
相应的其他的集合方法也有相对应的 of
注意:使用快速添加的内容不可更改
Java10
局部变量推断
// 老版正常写法
String s = "hello";
// 新版写法
var a = "hello";
var b = 1;
var c = true;
这个 var
关键字会根据后面跟得值来推断这是一个什么样的类型,在编译完成之后会编译成正常的类型,关键字后面必须跟值
// 这是编译后的内容
String s = "hello";
String a = "hello";
int b = true;
boolean c = true;
Java11
Lambda表达式的形参局部变量语法
Consumer<String> consumer = (var s) -> {
var split = s.split("-");
System.out.println(split[0]);
System.out.println(split[1]);
};
consumer.accept("hello-world");
Spring类方法增强
String s = "";
System.out.printf("是否是空字符串:%s", s.isEmpty());
s = " ";
System.out.printf("是否全部是空格:%s", s.isBlank());
isBlank()
判断其内容中是都全是空格是的话为true,什么也没有的一个空串也是true
String s = "ABC";
String repeat = s.repeat(3);
System.out.println(repeat);
repeat()
循环字符串,如:“ABC”循环三次后为“ABCABCABC”
String s = "AB\nCD";
Stream<String> lines = s.lines();
lines.forEach(System.out::println);
lines()
根据\n换行符进行分割字符串
String s = " A B C D ";
// 去除首尾空格
String strip = s.strip();
// 去除首空格
String stripLeading = s.stripLeading();
// 去除尾空格
String stripTrailing = s.stripTrailing();
strip()
、stripLeading()
、stripTrailing()
这三个API快速去除空格
新HttpClien API
此HttpClien不是apache的是JDK自带的
// 创建一个客户端
HttpClient client = HttpClient.newHttpClient();
// 创建一个请求
HttpRequest request = HttpRequest.newBuilder(new URI("https://nav.ximuliunian.top/json/image.json")).GET().build();
// 发送请求并接收响应
HttpResponse<String> send = client.send(request, HttpResponse.BodyHandlers.ofString());
// 打印响应体
System.out.println(send.body());
Java12 ~ 16
switch
原版
Scanner scanner = new Scanner(System.in);
switch (scanner.nextInt()) {
case 1:
System.out.println("1");
break;
case 2:
System.out.println("2");
break;
default:
System.out.println("default");
}
箭头表达式
Scanner scanner = new Scanner(System.in);
switch (scanner.nextInt()) {
// 多行使用以下写法
case 1 -> {
System.out.println("1");
}
// 只有单行可以使用下面的写法
case 2 -> System.out.println("2");
default -> {
System.out.println("default");
}
}
yield返回值
yield能让switch作为表达式,能够返回值
Scanner scanner = new Scanner(System.in);
String s = switch (scanner.nextInt()) {
case 1 -> {
System.out.println("1");
yield "1";
}
// 只有单行直接返回
case 2 -> "2";
default -> {
System.out.println("default");
yield "default";
}
};
在switch中
case X:
和case X->
只能使用两种其中的一种格式,不能混用
文本块
String data = """
hello world
这是一个文本块
我可以这样编写使用
""";
新 instanceof 语法
public class Student {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof Student) {
Student student = (Student) o;
return student.name.equals(name) && student.age == age;
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
以上为老版本的 instanceof
内容,语法优化是不需要强转类型直接使用
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof Student student) {
return student.name.equals(name) && student.age == age;
}
return false;
}
针对空指针异常改进
public static void main(String[] args) {
// 传入空值
fun("hello", null);
}
public static void fun(String a, String b) {
int length = a.length() + b.length();
System.out.println("总长度:" + length);
}
根据以上方案肯定会爆出空指针异常
// 以往异常虽然告诉你空指针但是没告诉你具体是a空指针还是b
Exception in thread "main" java.lang.NullPointerException
at top.xmln.data.Main.fun(Main.java:13)
at top.xmln.data.Main.main(Main.java:9)
// 改进后的方案 - 直接说明是b空了
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "b" is null
at top.xmln.data.Main.fun(Main.java:13)
at top.xmln.data.Main.main(Main.java:9)
记录类型 — Record
继接口、类、枚举之后的又一个类型:记录
简介
Java14中预览的新特性叫做Record,在Java中,Record是一种特殊类型的Java类。可用来创建不可变类,语法简短
特点:
- 带有全部参数的构造方法
- public访问器
- toString()、hsahCode()、equals()
- 无get\set方法
- final类,不能继承Record,Record位隐士的final类,除此之外与普通类一样
- 不可变类,通过构造创建Record
- final属性不可修改
- 不能声明实例属性,能声明static成员
代码
public record LuHu(String name, String color, Double price) {
// ...
}
以上就是一个简单的record,下面是测试方法
public class RecordTest {
public static void main(String[] args) {
// 实例化
LuHu luHu = new LuHu("路虎", "red", 10086.0);
// 调用属性
String name = luHu.name();
String color = luHu.color();
Double price = luHu.price();
// 输出
System.out.println("name = " + name + ", color = " + color + ", price = " + price);
}
}
实例 & 静态
public record LuHu(String name, String color, Double price) {
// 定义实例方法
public void print() {
System.out.println("name = " + name + ", color = " + color + ", price = " + price);
}
// 定义静态方法
public static String colorToUpperCase(String color) {
return Optional.ofNullable(color).orElse("color is empty").toUpperCase();
}
}
构造方法
自定义构造 & 规范构造(推荐)
public LuHu(String name, String color, Double price) {
this.name = name;
this.color = color;
this.price = price;
}
紧凑构造
public LuHu {
if (name == null) {
throw new IllegalArgumentException("name is empty");
}
// ...
}
实现接口
接口
public interface Car {
void run();
}
实现
public record LuHu(String name, String color, Double price) implements Car {
@Override
public void run() {
StringJoiner stringJoiner = new StringJoiner("-", "[", "]");
stringJoiner.add(name);
stringJoiner.add(color);
stringJoiner.add(price.toString());
System.out.println(stringJoiner);
}
}
Local Record
Record可以作为局部对象使用
public class RecordTest {
public static void main(String[] args) {
record BaoMa(String name, String color, Double price) implements Car {
@Override
public void run() {
StringJoiner stringJoiner = new StringJoiner("-", "[", "]");
stringJoiner.add(name);
stringJoiner.add(color);
stringJoiner.add(price.toString());
System.out.println(stringJoiner);
}
}
BaoMa baoMa = new BaoMa("宝马", "红色", 500000.0);
baoMa.run();
}
}
嵌套Record
多个Record可以组合定义,一个Record能够包含其他的Record
public class RecordTest {
public static void main(String[] args) {
record CarOwner(String name, LuHu luHu) {
}
LuHu luHu = new LuHu("路虎", "白色", 10000.0);
CarOwner carOwner = new CarOwner("张三", luHu);
}
}
instanceof能够与Record一起使用,编译器知道记录组件的确切数量和类型
Java17
密封类型
在Java中可以通过继承来实现类的复用、扩展和增强,但是有些时候不想类被继承,这是可以使用final
关键字来达到不被继承的目的,但是弊端就是我自己也不能继承,这时候有希望我自己写的类能够继承别人的类无法继承,这个场景就需要使用密封类型:sealed
public sealed class Main permits A, B, C {
// ...
}
sealed关键字表示当前类是一个密封类型,后面的permits是表示哪个类可以继承我
要求:
- 可以基于普通类、接口、抽象类,也可以是继承自其他接口的子类或者其他接口类等
- 必须要有permits,不能是匿名内部类或者lambda表达式
- sealed卸载final位置,且不能和final、non-sealed(非密封的)同时出现
- 继承的子类必须显示为final、sealed或者是non-sealed类型