Java8版本接口增加了两类成员:
Java9版本接口又新增了一类成员:
为什么JDK1.9要允许接口定义私有方法呢?因为我们说接口是规范,规范时需要公开让大家遵守的
私有方法:因为有了默认方法和静态方法这样具有具体实现的方法,那么就可能出现多个方法由共同的代码可以抽取,而这些共同的代码抽取出来的方法又只希望在接口内部使用,所以就增加了私有方法
public class TestAnonymous {
public static void main(String[] args) {
String[] arr = {"hello","Java"};
Arrays.sort(arr,new Comparator<>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
}
}
Java 8的语言等级编译会报错:“'<>' cannot be used with anonymous classes。”
Java 9及以上版本才能编译和运行正常。
/**
* Java 9 中,用资源语句编写try将更容易,我们可以在try子句中使用已经初始化过的资源
* IO流对象1声明和初始化;
* IO流对象2声明和初始化;
* try(IO流对象1;IO流对象2){
* 可能出现异常的代码
* }catch(异常类型 对象名){
* 异常处理方案
* }
*
* jvm会自动刷新和关闭流对象
*/
public static void test3()throws Exception{
FileInputStream fis = new FileInputStream("io\\1.jpg");
FileOutputStream fos = new FileOutputStream("io\\2.jpg");
try(fis;fos){
byte[] bytes = new byte[1024];
int len;
while((len = fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
JDK10,出现了一个最为重要的特性,就是局部变量类型推断
,定义局部变量时,不用先确定具体的数据类型了,可以直接根据具体数据推断出所属的数据类型。
public class TestVariable {
public static void main(String[] args) {
var a = 1;
System.out.println("a = " + a);
var s = "hello";
System.out.println("s = " + s);
var d = Math.random();
System.out.println("d = " + d);
var list = Arrays.asList("hello","world");
for (var o : list) {
System.out.println(o);
}
}
}
switch表达式在Java 12中作为预览语言出现,在Java 13中进行了二次预览,得到了再次改进,最终在Java 14中确定下来。另外,在Java17中预览了switch模式匹配。
传统的switch语句在使用中有以下几个问题。
(1)匹配是自上而下的,如果忘记写break,那么后面的case语句不论匹配与否都会执行。
(2)所有的case语句共用一个块范围,在不同的case语句定义的变量名不能重复。
(3)不能在一个case语句中写多个执行结果一致的条件,即每个case语句后只能写一个常量值。
(4)整个switch语句不能作为表达式返回值。
1、Java12的switch表达式
@Test
public void test122(){
int month = 3;
String monthName = switch(month) {
case 3,4,5 -> "春季";
case 6,7,8 -> "夏季";
case 9,10,11 -> "秋季";
case 12,1,2 -> "冬季";
// default -> "error";
default -> throw new IllegalArgumentException("月份有误!");
};
System.out.println("monthName = " + monthName);
}
2、Java13的switch表达式
引入了yield语句,用于返回值。这意味着,switch表达式(返回值)应该使用yield语句,switch语句(不返回值)应该使用break语句。
@Test
public void test1(){
int week = 2;
String weekName = switch(week) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> {
System.out.println("Weekend!");
yield "Sunday";
}
default -> {
System.out.println("Week number is between 1 and 7.");
yield "Error";
}
};
System.out.println("weekName = " + weekName);
}
3、Java17的switch表达式
允许switch表达式和语句可以针对多个模式进行测试,每个模式都有特定的操作
不使用模式匹配:
public static String formatterIf(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
使用模式匹配:
public static String formatterSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
1、Java13文本块
文本块就是指多行字符串,例如一段格式化后的XML、JSON等。而有了文本块以后,用户不需要转义,Java能自动搞定。因此,文本块将提高Java程序的可读性和可写性。
会被自动转义,如有一段以下字符串:
<html>
<body>
<p>Hello, world</p>
</body>
</html>
将其复制到Java的字符串中,会展示成以下内容:
"\n" +
" \n" +
" Hello, world
\n" +
" \n" +
"\n";
虽然被自动进行了转义,但是这样的字符串看起来不是很直观,在JDK 13中,就可以使用以下语法了:
"""
Hello, world
""";
使用“”“作为文本块的开始符和结束符,在其中就可以放置多行的字符串,不需要进行任何转义。
(1)文本块由零个或多个字符组成,由开始和结束分隔符括起来。
(2)允许开发人员使用“\n”“\f”和“\r”来进行字符串的垂直格式化,使用“\b”“\t”进行水平格式化。
String html = """
\n
\n
Hello, world
\n
\n
\n
""";
(3)在文本块中自由使用双引号是合法的。
String story = """
Elly said,"Maybe I was a bird in another life."
Noah said,"If you're a bird , I'm a bird."
""";
2、Java14文本块
Java 14给文本块引入了两个新的转义序列。一是可以使用新的\s转义序列来表示一个空格;二是可以使用反斜杠“\”来避免在行尾插入换行字符
之前我们调用一个对象中的方法,我们会先判断类型,如果调用子类特有方法,我们需要向下转型
public static void old(Animal animal){
if (animal instanceof Bird) {
Bird bird = (Bird) animal;
bird.fly();
} else if (animal instanceof Fish) {
Fish fish = (Fish) animal;
fish.swim();
}
}
从JDK14开始,我们不需要单独强转,直接省略强转的过程
public static void now(Animal animal) {
if (animal instanceof Bird bird) {
bird.fly();
} else if (animal instanceof Fish fish){
fish.swim();
}
}
record是一种全新的类型,它本质上是一个 final类,同时所有的属性都是 final修饰,它会自动编译出get、hashCode 、比较所有属性值的equals、toString 等方法,减少了代码编写量。使用 Record 可以更方便的创建一个常量类。
1.注意:
public class TestRecord {
public static void main(String[] args) {
Triangle t = new Triangle(3, 4, 5);
System.out.println(t);
System.out.println("面积:" + t.area());
System.out.println("周长:" + t.perimeter());
System.out.println("边长:" + t.a() + "," + t.b() + "," + t.c());
Triangle t2 = new Triangle(3, 4, 5);
System.out.println(t.equals(t2));
}
}
record Triangle(double a, double b, double c) {
public double area() {
if (a > 0 && b > 0 && c > 0 && a + b > c && b + c > a && a + c > b) {
double p = (a + b + c) / 2;
return Math.sqrt(p * (p - a) * (p - b) * (p - c));
}
throw new IllegalArgumentException("不是合法的三角形");
}
public double perimeter() {
return a + b + c;
}
}
密封类
的思想,就是final修饰的类,该类不允许被继承,从JDK15开始,针对密封类
进行了升级。密封的类和接口限制其他可能继承或实现它们的其他类或接口。
【修饰符】 sealed class 密封类 【extends 父类】【implements 父接口】 permits 子类{
}
【修饰符】 sealed interface 接口 【extends 父接口们】 permits 实现类{
}
sealed修饰的类
sealed class Graphic /*extends Object implements Serializable*/ permits Circle,Rectangle, Triangle {
}
final class Triangle extends Graphic{
}
non-sealed class Circle extends Graphic{
}
sealed class Rectangle extends Graphic permits Square{
}
final class Square extends Rectangle{
}
sealed修饰的接口
public class TestSealedInterface {
}
sealed interface Flyable /*extends Serializable*/ permits Bird {
}
non-sealed class Bird implements Flyable{
}