乐趣区

关于java:卷不动了300-秒快速了解-Java-9-16-新特性助你脱离内卷

点赞再看,养成好习惯

JAVA 这几年的更新切实是太太太……快了,JAVA 8 都还没用多久,16 都曾经公布了。自从 JAVA 8 公布了 Lambda 和 Stream 之后,JAVA 就像打了鸡血一样,半年一个版本的公布,生产队的驴也没这么勤快。

导致咱们当初齐全跟不上 JAVA 公布的节奏,我司目前还停留在 JAVA 8,甚至局部老零碎还在应用 JAVA 7,基本不能轻易的降级。

不过尽管临时用不上最新版本的 JAVA,但理解每个新版本的次要个性还是很重要的,不然哪天真跟着降级了,那还不得一脸懵逼。

本文就带你疾速理解 JAVA 9 – 16 的次要新个性,早学完早上班!

JAVA 9(2017 年 9 月)

接口里能够增加公有接口

JAVA 8 对接口减少了默认办法的反对,在 JAVA 9 中对该性能又来了一次降级,当初能够在接口里定义公有办法,而后在默认办法里调用接口的公有办法。

这样一来,既能够重用公有办法里的代码,又能够不公开代码

public interface TestInterface {default void wrapMethod(){innerMethod();
    }
    private void innerMethod(){System.out.println("");
    }
}

匿名外部类也反对钻石(diamond)运算符

JAVA 5 就引入了泛型(generic),到了 JAVA 7 开始反对钻石(diamond)运算符:<>,能够主动推断泛型的类型:

List<Integer> numbers = new ArrayList<>();

然而这个主动推断类型的钻石运算符可不反对匿名外部类,在 JAVA 9 中也对匿名外部类做了反对:

List<Integer> numbers = new ArrayList<>() {...}

加强的 try-with-resources

JAVA 7 中减少了 try-with-resources 的反对,能够主动敞开资源:

try (BufferedReader bufferReader = new BufferedReader(...)) {return bufferReader.readLine();
}

但须要申明多个资源变量时,代码看着就有点恶心了,须要在 try 中写多个变量的创立过程:

try (BufferedReader bufferReader0 = new BufferedReader(...);
    BufferedReader bufferReader1 = new BufferedReader(...)) {return bufferReader0.readLine();
}

JAVA 9 中对这个性能进行了加强,能够援用 try 代码块之外的变量来主动敞开:

BufferedReader bufferReader0 = new BufferedReader(...);
BufferedReader bufferReader1 = new BufferedReader(...);
try (bufferReader0; bufferReader1) {System.out.println(br1.readLine() + br2.readLine());
}

JAVA 10(2018 年 3 月)

局部变量的主动类型推断(var)

JAVA 10 带来了一个很有意思的语法 – var,它能够主动推断局部变量的类型,当前再也不必写类型了,也不必靠 lombok 的 var 注解加强了

var message = "Hello, Java 10";

不过这个只是语法糖,编译后变量还是有类型的,应用时还是思考下可维护性的问题,不然写多了可就成 JavaScript 格调了

JAVA 11(2018 年 9 月)

Lambda 中的主动类型推断(var)

JAVA 11 中对 Lambda 语法也反对了 var 这个主动类型推断的变量,通过 var 变量还能够减少额定的注解:

List<String> languages = Arrays.asList("Java", "Groovy");
String language = sampleList.stream()
  .map((@Nonnull var x) -> x.toUpperCase())
  .collect(Collectors.joining(","));

assertThat(language).isEqualTo("Java, Groovy");

javac + java 命令一把梭

以前编译一个 java 文件时,须要先 javac 编译为 class,而后再用 java 执行,当初能够一把梭了:

$ java HelloWorld.java
Hello Java 11!

Java Flight Recorder 登陆 OpenJDK

Java Flight Recorder 是个灰常好用的调试诊断工具,不过之前是在 Oracle JDK 中,也跟着 JDK 11 开源了,OpenJDK 这下也能够用这个性能,真香!

JAVA 12(2019 年 3 月)

更简洁的 switch 语法

在之前的 JAVA 版本中,switch 语法还是比拟啰嗦的,如果多个值走一个逻辑须要写多个 case

DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
String typeOfDay = "";
switch (dayOfWeek) {
    case MONDAY:
    case TUESDAY:
    case WEDNESDAY:
    case THURSDAY:
    case FRIDAY:
        typeOfDay = "Working Day";
        break;
    case SATURDAY:
    case SUNDAY:
        typeOfDay = "Day Off";
}

到了 JAVA 12,这个事件就变得很简略了,几行搞定,而且!还反对返回值:

typeOfDay = switch (dayOfWeek) {
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Working Day";
    case SATURDAY, SUNDAY -> "Day Off";
};

instanceof + 类型强转一步到位

之前解决动静类型碰上要强转时,须要先 instanceof 判断一下,而后再强转为该类型解决:

Object obj = "Hello Java 12!";
if (obj instanceof String) {String s = (String) obj;
    int length = s.length();}

当初 instanceof 反对间接类型转换了,不须要再来一次额定的强转:

Object obj = "Hello Java 12!";
if (obj instanceof String str) {int length = str.length();
}

JAVA 13(2019 年 9 月)

switch 语法再加强

JAVA 12 中尽管加强了 swtich 语法,但并不能在 -> 之后写简单的逻辑,JAVA 12 带来了 swtich更完满的体验,就像 lambda 一样,能够写逻辑,而后再返回:

typeOfDay = switch (dayOfWeek) {
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
        // do sth...
        yield "Working Day";
    }
    case SATURDAY, SUNDAY -> "Day Off";
};

文本块(Text Block)的反对

你是否还在为大段带换行符的字符串报文所困扰,换行吧一堆换行符,不换行吧看着又好受:

String json = "{\"id\":\"1697301681936888\",\"nickname\":\" 空无 \",\"homepage\":\"https://juejin.cn/user/1697301681936888\"}";

JAVA 13 中帮你解决了这个恶心的问题,减少了文本块的反对,当初能够开心的换行拼字符串了,就像用模板一样:

String json = """{"id":"1697301681936888","nickname":" 空无 ","homepage":"https://juejin.cn/user/1697301681936888"}""";

JAVA 14(2020 年 3 月)

新增的 record 类型,干掉简单的 POJO 类

个别咱们创立一个 POJO 类,须要定义属性列表,构造函数,getter/setter,比拟麻烦。JAVA 14 为咱们带来了一个便捷的创立类的形式 – record

public record UserDTO(String id,String nickname,String homepage) { };

public static void main(String[] args ){UserDTO user = new UserDTO("1697301681936888","空无","https://juejin.cn/user/1697301681936888");
    System.out.println(user.id);
    System.out.println(user.nickname);
    System.out.println(user.id);
}

IDEA 也早已反对了这个性能,创立类的时候间接就能够选:

不过这个只是一个语法糖,编译后还是一个 Class,和一般的 Class 区别不大

更直观的 NullPointerException 提醒

NullPointerException 算是 JAVA 里最常见的一个异样了,但这玩意提醒切实不敌对,遇到一些长一点的链式表达式时,没方法分辨到底是哪个对象为空。

比方上面这个例子中,到底是 innerMap 为空呢,还是 effected 为空呢?

Map<String,Map<String,Boolean>> wrapMap = new HashMap<>();
wrapMap.put("innerMap",new HashMap<>());

boolean effected = wrapMap.get("innerMap").get("effected");

// StackTrace:
Exception in thread "main" java.lang.NullPointerException
    at org.example.App.main(App.java:50)

JAVA 14 也 get 到了 JAVAER 们的痛点,优化了 NullPointerException 的提醒,让你不在困惑,一眼就能定位到底“空”在哪!

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Boolean.booleanValue()" because the return value of "java.util.Map.get(Object)" is null
    at org.example.App.main(App.java:50)

当初的 StackTrace 就很直观了,间接通知你 effected 变量为空,再也不必困惑!

平安的堆外内存读写接口,别再玩 Unsafe 的骚操作了

在之前的版本中,JAVA 如果想操作堆外内存(DirectBuffer),还得 Unsafe 各种 copy/get/offset。当初间接减少了一套平安的堆外内存拜访接口,能够轻松的拜访堆外内存,再也不必搞 Unsafe 的骚操作了。

// 调配 200B 堆外内存
MemorySegment memorySegment = MemorySegment.allocateNative(200);

// 用 ByteBuffer 调配,而后包装为 MemorySegment
MemorySegment memorySegment = MemorySegment.ofByteBuffer(ByteBuffer.allocateDirect(200));

// MMAP 当然也能够
MemorySegment memorySegment = MemorySegment.mapFromPath(Path.of("/tmp/memory.txt"), 200, FileChannel.MapMode.READ_WRITE);

// 获取堆外内存地址
MemoryAddress address = MemorySegment.allocateNative(100).baseAddress();

// 组合拳,堆外调配,堆外赋值
long value = 10;
MemoryAddress memoryAddress = MemorySegment.allocateNative(8).baseAddress();
// 获取句柄
VarHandle varHandle = MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder());
varHandle.set(memoryAddress, value);

// 开释就这么简略,想想 DirectByteBuffer 的开释……多奇怪
memorySegment.close();

不理解 Unsafe 操作堆外内存形式的同学,能够参考我的另一篇文章《JDK 中为了性能大量应用的 Unsafe 类,你会用吗?》

新增的 jpackage 打包工具,间接打包二进制程序,再也不必装 JRE 了

之前如果想构建一个可执行的程序,还须要借助三方工具,将 JRE 一起打包,或者让客户电脑也装一个 JRE 才能够运行咱们的 JAVA 程序。

当初 JAVA 间接内置了 jpackage 打包工具,帮忙你一键打包二进制程序包,终于不必乱折腾了

JAVA 15(2020 年 9 月)

ZGC 和 Shenandoah 两款垃圾回收器正式登陆

在 JAVA 15 中,ZGC 和 Shenandoah 再也不是试验性能,正式登陆了(不过 G1 依然是默认的)。如果你降级到 JAVA 15 当前的版本,就赶快试试吧,性能更强,提早更低

关闭(Sealed)类

JAVA 的继承目前只能抉择容许继承和不容许继承(final 润饰),当初新增了一个关闭(Sealed)类的个性,能够指定某些类才能够继承:

public sealed interface Service permits Car, Truck {int getMaxServiceIntervalInMonths();

    default int getMaxDistanceBetweenServicesInKilometers() {return 100000;}

}

JAVA 16(2021 年 3 月)

JAVA 16 在 用户可见的中央 变动并不多,根本都是 14/15 的实验性内容,到了 16 正式公布,这里就不反复介绍了。

总结

以上介绍的各种新个性,有些个性在历史版本中还属于试验性功能,不过依照 JAVA 目前这个驴一样的更新频率,很可能下个版本就是稳定版了。

看看工夫,300 秒到了吗?

​> 原创不易,禁止未受权的转载。如果我的文章对您有帮忙,就请点赞 / 珍藏 / 关注激励反对一下吧❤❤❤❤❤❤

退出移动版