Java 10~16 新特性

主要特性

版本 特性
Java 10 1. var声明局部变量
Java 11 (LTS 1. 字符串补充工具方法
2. lambda 类型推断
Java 12 1. switch 箭头表达式
Java 13 1. switch 支持返回值,增加yield关键字
2. 多行字符串
Java 14 1. instanceof优化
2. NPE优化
3. record类型
Java 15 1. scale密封类
Java 16 1. 包装类构造方法警告
2. DateTimeFormatter增加匹配方式
3. InvocationHandler新增方法

Java 10

var 声明局部变量

/**
 * @author imyzt
 * @date 2023/12/16
 * @description Var
 */
public class VarDemo {
    public static void main(String[] args) {
        var str = "hello world";
        var num = 10;

        System.out.println(str);
        System.out.println(num);
    }
}

Java 11

字符串补充工具方法, lambda 类型推断

/**
 * @author imyzt
 * @date 2023/12/16
 * @description String 补充工具方法
 */
public class StrUtil {

    public static void main(String[] args) {
        //Unicode空白字符
        char c = '\u2000';
        String str = c + "abc" + c;
        // 去除普通空白字符
        System.out.println(str.trim());
        // 去除Unicode空白字符
        System.out.println(str.strip());
        // 去除前面的空白字符
        System.out.println(str.stripLeading());
        // 去除后面的空白字符
        System.out.println(str.stripTrailing());
        // abc 
        //abc
        //abc 
        // abc

        // 判空
        System.out.println(" ".isBlank());
        // 支持直接定义常量使用format
        System.out.println("%s_%s".formatted("a", "b"));
        // 重复字符串
        System.out.println("abc".repeat(3));
        //true
        //a_b
        //abcabcabc

        // lambda 类型推断
        // java11前
        MyFunc s1 = (String a, Integer b) -> a + b;
        MyFunc s2 = (a, b) -> a + b;
        // java11后, 支持类型推断(作用不大)
        MyFunc s3 = (var a, var b) -> a + b;
    }
}

@FunctionalInterface
interface MyFunc {
    String foo(String a, Integer b);
}

Java 12

switch 箭头表达式

/**
 * @author imyzt
 * @date 2023/12/16
 * @description switch
 */
public class SwitchFuture {

    public static void main(String[] args) {

        int month = LocalDate.now().getMonthValue();

        // java12 前 switch
        switch (month) {
            case 3:
            case 4:
            case 5:
                System.out.println("spring");
                break;
            case 6:
            case 7:
            case 8:
                System.out.println("summer");
                break;
            case 9:
            case 10:
            case 11:
                System.out.println("fall");
                break;
            case 12:
            case 1:
            case 2:
                System.out.println("winter");
                break;
            default:
                System.out.println("err");
        }

        // java12 之后的switch
        switch (month) {
            case 3,4,5 -> System.out.println("spring");
            case 6,7,8 -> System.out.println("summer");
            case 9,10,11 -> System.out.println("fall");
            case 12,1,2 -> System.out.println("winter");
            default -> System.out.println("err");

        }
    }
}

Java 13

switch 箭头表达式支持返回值,多行字符串,增加yield关键字作为switch多行时的返回值

import java.time.LocalDate;

/**
 * @author imyzt
 * @date 2023/12/16
 * @description switch 返回值
 */
public class SwitchFuture {

    public static void main(String[] args) {

        int month = LocalDate.now().getMonthValue();
        // java13 之后的switch
        String str = switch (month) {
            case 3, 4, 5 -> "spring";
            case 6, 7, 8 -> "summer";
            case 9, 10, 11 -> "fall";
            case 12, 1, 2 -> "winter";
            default -> {
                System.out.println("err");
                yield "err";
            }
        };
        System.out.println(str);
        // winter

        String strline = """
                第一行
                第二行
                第三行""";
        System.out.println(strline);
        //第一行
        //第二行
        //第三行
    }
}

Java 14

instanceof 优化

/**
 * @author imyzt
 * @date 2023/12/16
 * @description instanceof 优化
 */
public class InstanceofFuture {

    public static void main(String[] args) {

        // Java 14之前
        Object o = "str";
        if (o instanceof String) {
            String str = (String) o;
            System.out.println(str);
        }

        // Java 14之后
        if (o instanceof String str) {
            System.out.println(str);
        }
    }
}

NPE优化,在链式调用时, 如果有空指针, 可以明确是哪个变量空指针

/**
 * @author imyzt
 * @date 2023/12/16
 * @description 友好的NPE提示
 */
public class NpeFuture {

    public static void main(String[] args) {
        C c = new C();
        // 在链式调用时, 如果有空指针, 可以明确是哪个变量空指针
        String name = c.b.a.name;
        System.out.println(name);
        // Cannot read field "a" because "c.b" is null
    }
}
class A {
    public String name;
}

class B {
    public A a;
}

class C {
    public B b;
}

record模式

/**
 * @author imyzt
 * @date 2023/12/16
 * @description record模式
 */
public class RecordFuture {

    public static void main(String[] args) {
        Student student = new Student("yzt", 25);
        System.out.println(student);
        // Student[name=yzt, age=25]

        student.study();
        // good good study!
    }
}

record Student(String name, Integer age) {
    public void study() {
        System.out.println("good good study!");
    }
}

Java 15

scale密封类

  1. 需要使用sealed声明, 使用permits指定
  2. 继承密封类,必须指定自己为final(Dog),或选择继续将自己指定为密封类(Cat)
/**
 * @author imyzt
 * @date 2023/12/16
 * @description scale, permits
 */
public class ScaleFuture {
}

/**
 * 只希望Dog和Cat能继承, 需要使用sealed声明, 使用permits指定
 */
sealed class Animal permits Dog, Cat {
    
}

/**
 * 继承密封类,必须指定自己为final(Dog), 或继续将自己指定为密封类(Cat)
 */
final class Dog extends Animal {
    
}

/**
 * 将自己指定为密封类, 并且通过permits指定只有Cat2能够继承
 */
sealed class Cat extends Animal permits Cat2 {
    
}

final class Cat2 extends Cat {
    
}

Java 16

包装类型的构造方法被标记过期

/**
 * @author imyzt
 * @date 2023/12/17
 * @description Integer
 */
public class IntegerFuture {

    public static void main(String[] args) {
        // 'Integer(int)' is deprecated and marked for removal
        Integer i = new Integer(2);
        System.out.println(i);

        // 不建议这样编写,因为数字在常量池中, 会和其他毫不相干的地方使用同一个锁对象
        synchronized (i) {
            System.out.println(1);
        }

        // time format
        // All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. The following pattern letters are defined:
        System.out.println(DateTimeFormatter.ofPattern("B").format(LocalDateTime.now()));

        //2
        //1
        //凌晨
    }
}

DateTimeFormatter

官方文档

Symbol Meaning Presentation Examples
G era text AD; Anno Domini; A
u year year 2004; 04
y year-of-era year 2004; 04
D day-of-year number 189
M/L month-of-year number/text 7; 07; Jul; July; J
d day-of-month number 10
g modified-julian-day number 2451334
Q/q quarter-of-year number/text 3; 03; Q3; 3rd quarter
Y week-based-year year 1996; 96
w week-of-week-based-year number 27
W week-of-month number 4
E day-of-week text Tue; Tuesday; T
e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
F day-of-week-in-month number 3
a am-pm-of-day text PM
B period-of-day text in the morning
h clock-hour-of-am-pm (1-12) number 12
K hour-of-am-pm (0-11) number 0
k clock-hour-of-day (1-24) number 24
H hour-of-day (0-23) number 0
m minute-of-hour number 30
s second-of-minute number 55
S fraction-of-second fraction 978
A milli-of-day number 1234
n nano-of-second number 987654321
N nano-of-day number 1234000000
V time-zone ID zone-id America/Los_Angeles; Z; -08:30
v generic time-zone name zone-name Pacific Time; PT
z time-zone name zone-name Pacific Standard Time; PST
O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00
X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15
x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15
Z zone-offset offset-Z +0000; -0800; -08:00
p pad next pad modifier 1
' escape for text delimiter
'' single quote literal '
[ optional section start
] optional section end
# reserved for future use
{ reserved for future use
} reserved for future use

InvocationHandler新增方法

该接口补充了新方法 java.lang.reflect.InvocationHandler#invokeDefault,可以调用父接口中的default方法。

@CallerSensitive
public static Object invokeDefault(Object proxy, Method method, Object... args)
        throws Throwable {
    Objects.requireNonNull(proxy);
    Objects.requireNonNull(method);
    return Proxy.invokeDefault(proxy, method, args, Reflection.getCallerClass());
}