Java新特性(9-19)

记录一下9-19版本中的常见的一些和开发相关的新特性

Jdk9

接口私有方法
/**
* 接口可以定义私有方法了
*/
public interface privateInterface {

    private void method(){
        System.out.printf("this is private");
    }
}
try-with-resource

可以将要关闭的流定义在括号外面了

public class closeIO {

    public static void main(String[] args) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream("");
        FileOutputStream fos = new FileOutputStream("");
        // 变量可以定义在外面
        try (fis; fos) {

        } catch (Exception e) {

        }

        // 不能使用下划线作为变量名了
//        String _ = "";
    }
}
@Deprecated注解

注解添加了since(代表从哪个版本开始废弃),forRemoval(代表将来会被废弃),比如下面Object的finalize方法再9被标记为废弃

@Deprecated(since="9", forRemoval=true)
protected void finalize() throws Throwable { }
String实现变更

用byte数组代替char数组来保存数据,当字符集为拉丁文的时候,一个字节就可以代表一个字符,这个时候使用字节数组会节省内存

/**
* 直接数组
*/
@Stable
private final byte[] value;

/**
 * 使用拉丁还是UTF16编码(一般中文为2个字节)
 * LATIN1
 * UTF16
 */
private final byte coder;

@Native static final byte LATIN1 = 0;
@Native static final byte UTF16  = 1;

// 是否开启压缩,默认开启
static final boolean COMPACT_STRINGS;

static {
    COMPACT_STRINGS = true;
}
public String(char[] value) {
    this(value, 0, value.length, null);
}

String(char[] value, int off, int len, Void sig) {
    if (len == 0) {
        this.value = "".value;
        this.coder = "".coder;
        return;
    }
    // 默认是开启压缩的
    if (COMPACT_STRINGS) {
        // 生成压缩的字节数组
        byte[] val = StringUTF16.compress(value, off, len);
        if (val != null) {
            this.value = val;
            this.coder = LATIN1;
            return;
        }
    }
    // 压缩失败,代表是UTF16格式的
    this.coder = UTF16;
    this.value = StringUTF16.toBytes(value, off, len);
}

// StringUTF16.compress
public static byte[] compress(char[] val, int off, int len) {
    byte[] ret = new byte[len];
    // 如果长度相同
    if (compress(val, off, ret, 0, len) == len) {
        return ret;
    }
    return null;
}

// StringUTF16.compress -> compress
public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
    for (int i = 0; i < len; i++) {
        char c = src[srcOff];
        // 11111111 大于代表不是拉丁格式的,不能进行压缩
        if (c > 0xFF) {
            len = 0;
            break;
        }
        dst[dstOff] = (byte)c;
        srcOff++;
        dstOff++;
    }
    return len;
}

// StringUTF16.toBytes
public static byte[] toBytes(char[] value, int off, int len) {
    // 创建一个 len << 1,即2倍大小的数组
    byte[] val = newBytesFor(len);
    for (int i = 0; i < len; i++) {
        putChar(val, i, value[off]);
        off++;
    }
    return val;
}

static void putChar(byte[] val, int index, int c) {
    assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
    // index当然也要翻倍
    index <<= 1;
    // 高八位
    val[index++] = (byte)(c >> HI_BYTE_SHIFT);
    // 低八位
    val[index]   = (byte)(c >> LO_BYTE_SHIFT);
}

static {
    // 高低位是根据大小端来判断的,大端是高字节保存在低地址,小端反过来
    // 主要是网络和硬件的大小端不一致的处理
    if (isBigEndian()) {
        HI_BYTE_SHIFT = 8;
        LO_BYTE_SHIFT = 0;
    } else {
        HI_BYTE_SHIFT = 0;
        LO_BYTE_SHIFT = 8;
    }
}
模块化

很容易想到Maven或者gradle,不多这两个工具对应的最小粒度是jar;在jdk9中新增了module,之前更多的是package的层级,增加module是为了更好的管理代码,比如在jdk8中的rt.jar其实有很多在web中用不到的东西(awt,applet这些),在jdk9中模块化后在jmods目录下面的java.base.jmod中就找不到了
image.pngimage.png
class是字段和方法的集合,package是class的集合,而module是package的集合。
类比maven,创建一个controller、service的module
image.png

package com.module.service;

public class HelloService {

    public String hello(){
        return "hello";
    }
}
package com.module.controller;

import com.module.service.HelloService;

public class HelloController {

    private HelloService helloService = new HelloService();

    public String hello(){
        return helloService.hello();
    }

    public static void main(String[] args) {
        HelloController controller = new HelloController();
        System.out.println(controller.hello());
    }
}

因为是两个不同的module,HelloController需要引用HelloService,就需要通过类似maven的pom文件表示依赖关系,build后才能使用;在两个module下创建module-info.java来描述引用关系
moduleService将com.module.service包暴露出去

module moduleService {
    exports com.module.service;
}

moduleController描述引用

module moduleController {
    requires moduleService;
}

在moduleService模块下,其实还有util包,因为没有exports出去,所以moduleController使用不到
当前案例只是当了解入门,以后有使用的时候再深入看其他的关键字和使用

jshell

简单的代码可以直接用jshell来进行处理
image.png

集合工厂方法

集合类可以通过 of 方法来进行初始化创建,以map为例

public static void main(String[] args) {
    // 9之前,创建并初始化,方式1
    Map<String,Integer> mapInit1 = new HashMap<>(){{
       put("ABC",123);
       put("DEF",123);
       put("GHI",123);
    }};
    // 方式2
    Map<String,Integer> mapInit2 = new HashMap<>();
    mapInit2.put("ABC",123);
    // 9,of初始化
    Map<String, Integer> mapInit3 = Map.of("ABC", 123, "DEF", 123);
    mapInit3.put("GHI",123);
}

生成的是AbstractImmutableMap的子类,是不可变更的

static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
    return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
}
Stream

Stream新增了一些方法

public static void main(String[] args) {
    // ofNullable类似Optional
    Stream
            .ofNullable(null)
            .forEach(System.out::println);

    //
    Stream
            // iterate 第二个参数增加断言,和for循环类似
            .iterate(0, i -> i < 20, i -> i + 1)
            // 当i小于17的时候获取
            .takeWhile(i -> i < 17)
            // 当i小于15的时候丢弃
            .dropWhile(i -> i < 15)
            // 最后打印结果是15 16
            .forEach(System.out::println);
}
Optional

optional中新增的一些方法

public static void main(String[] args) {
    // ifPresentOrElse 当元素为空时可以执行else操作了
    Optional.ofNullable(null)
            .ifPresentOrElse(e -> {
                System.out.println("当前元素是:" + e);
            }, () -> {
                System.out.println("当前元素为空");
            });

    // or 当元素为空的时候,使用or里面的
    String str = null;
    Optional.ofNullable(str)
            .or(() -> Optional.of("ABC"))
            .ifPresent(System.out::println);
}

Jdk10

局部变量推断

类似js这种脚本语言,可以用var来定义变量了;不过局限于局部变量、增强for循环的索引、普通for循环的本地变量;像是方法形参、返回值类型、构造方法形参这种还是不行的

public static void main(String[] args) {
    var str = "ABC";
    var i = 10;
    var l = 10000L;
    var c = 'c';
}

Jdk11

编译运行

之前都是需要javac编译,再java运行;现在可以直接java运行

String

展示部分String新的API

public static void main(String[] args) {
    char space = '\u2000';
    String str1 = "ABD";
    str1 = space + str1 + space;
    // 无法去掉Unicode的空格
    System.out.println(str1.trim());
    // 使用 strip 方法
    System.out.println(str1.strip());

    String emptyStr = " ";
    System.out.println(emptyStr.isEmpty());
    // 使用 isBlank 来判断空格字符串
    System.out.println(emptyStr.isBlank());

    String repeatStr = "ABC";
    // 重复字符串
    System.out.println(repeatStr.repeat(3));
}
lambda表达式中的局部变量推断
public class Lambda {

    public static void main(String[] args) {
        // 使用var代替
        Inter inter = (var a, var b) -> {
            return a + b;
        };
    }
}

public interface Inter {
    String method(Integer a, String b);
}

Jdk12

switch增强

12的版本是预览版,在14的时候正式使用

public static void main(String[] args) {
    int num = 3;
    switch (num) {
        case 1, 2, 3 -> System.out.println(1);
        case 4, 5, 6 -> System.out.println(2);
        default -> System.out.println(3);
    }
}

Jdk13

switch 返回值
public static void main(String[] args) {
    int num = 3;
    int result = switch (num) {
        case 1, 2, 3 -> 1;
        case 4, 5, 6 -> 2;
        default -> 3;
    };
}
文本块
public static void main(String[] args) {
    String str = """
            这是字符串
                        换行
                    换行
            """;
}

Jdk14

instanceof 赋值
public static void main(String[] args) {
    Object obj = 1;
    // 当obj为Integer类型的时候,强转赋值到变量 i
    if(obj instanceof Integer i){
        System.out.println(i);
    }
}
空指针提示

image.png
还可以通过 -XX:+ShowCodeDetailsInExceptionMessages 的方式来查看

record类型

通常我们会定义一些只有get、set方法的javabean,就可以使用record类型来替换

public record Person(String name, String addr) {
public String info() {
    return name() + addr();
}

public static void main(String[] args) {
    Person person = new Person("小红","桥洞下");
    System.out.println(person.info());
}
}

Jdk15

密封类 sealed class

通过sealed class我们可以指定那些之类可以继承

// 通过sealed指定只能被Father类继承
public sealed class GrandFather permits Father{
}

// Father类还希望能被Son继承的话,也需要设置为sealed
sealed class Father extends GrandFather permits Son{
    
}

// son没有其他继承关系,需要指定为final
final class Son extends Father{
    
}
CharSequence

新增了isEmpty方法,判断是否为空

TreeMap

新增如下方法,这些方法其他map应该是早就有了的

  1. putIfAbsent
  2. computeIfAbsent
  3. computeIfPresent
  4. compute
  5. merge
环境变量

15之后安装jdk不需要再手动配置环境变量了

Jdk16

date格式

可以通过如下的parttern打印出当前是上午还是下午

System.out.println(DateTimeFormatter.ofPattern("B").format(LocalDateTime.now()));
invocationHandler的default方法增强

通过 InvocationHandler.invokeDefault 可以增强default方法了

public class InvocationHandlerTest {

public static void main(String[] args) {
    Hello helloProxy = (Hello)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
            new Class[]{Hello.class}, ((proxy, method, args1) -> {
                if (method.isDefault()) {
                    // invokeDefault
                    return InvocationHandler.invokeDefault(proxy, method, args1) + "world";
                }
                return null;
            }));
    System.out.println(helloProxy.hello());
}
}

interface Hello {
    default String hello() {
        return "hello";
    }
}

Jdk 17

switch 多态

现在可以用switch来代替 if instanceof的方式来调用方法了

public class SwitchTest {

    public static void main(String[] args) {
        A t = new C();

        switch (t){
            case B b -> b.b();
            case C c -> c.c();
            case null -> System.out.println("null");
            default -> System.out.println("default");
        }
    }
}

class A {

}

class B extends A {
    public void b() {
        System.out.println("b");
    }
}

class C extends A {
    public void c() {
        System.out.println("c");
    }
}
增强型伪随机数发生器
  • RandomGenerator
  • RandomGeneratorFactory

Jdk18

默认使用UTF-8编码
jwebserver

通过该命令可以启动一个简易的web服务器

被移除的方法
  • Object的finalize
  • Thread的stop
@snippet注解

可以在文档注解中对代码进行注释

/**
 * {@snippet :
 *      System.out.println("begin") 打印begin
 * }
 * @return
 */
public String test(){
    System.out.println("begin");
    return "";
}

Jdk19

虚拟线程

java现在也有虚拟线程了,相较之之前的平台线程,消耗要小得多,也不需要线程池来进行管理,适合IO密集型任务,详细使用后面深入研究

public static void main(String[] args) throws InterruptedException {
    Runnable task = ()->{
        System.out.println("task run:"+Thread.currentThread().getName());
    };

    // 方式1
    Thread.startVirtualThread(task);

    // 方式2
    Thread virtual = Thread.ofVirtual().name("virtual").unstarted(task);
    virtual.start();

    // 方式3
    Executors.newVirtualThreadPerTaskExecutor().submit(task);

    Thread.sleep(5000);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值