Java 11 新增 API 初探

Java 11 发布也有一段时间了。大家关注比较密切的,主要是 ZGC、黑匣、低开销堆采样等等新特性,还有就是 Oracle JDK 商用开始收费了。作为一个开发者,除了这些以外,我还比较在意 JDK 提供的接口发生了哪些变化。下面就来简单的罗列一下,相比 Java 10,新的 JDK 在 API 上有哪些变化。

集合

java.util.Collection

新增了一个默认方法

default <T> T[] toArray(IntFunction<T[]> generator) {
    return toArray(generator.apply(0));
}

个人认为,该方法几乎是集合转数组的不二之选,预计后续会逐步废弃旧的 toArray 方法。

Collection<String> strs = ...;
String[] arr = strs.toArray(String[]::new);

字符串

java.lang.String

新增了几个处理空白字符串的方法。对 demo 类的小项目可以一用,成熟的项目大多都有 StringUtils 之类的第三方工具类来处理了,总的来说意义不大。

// 去除前后空格
public String strip()
// 去除前面的空格
public String stripLeading()
// 去除后面的空格
public String stripTrailing()
// 是否为空字符串或只包含空白字符,显然不能判断 null
public boolean isBlank()

另外还有两个新方法

// 按照换行符分割字符串并返回流
public Stream<String> lines()
// 构造一个重复 n 次的字符串
public String repeat(int count)

repeat(int) 暂时想不到实际应用的场景,在传统的 StringUtils 中也有提供。lines() 方法是对 split 方法的一个高频特例(以换行符分割)封装,同时返回 Stream 比数组更加友好。

java.lang.StringBuilder && StringBuffer

StringBuilder 和 StringBuffer 现在实现了 Comparable 接口,与此同时,CharSequence 接口也新增了一个 compare 的静态方法,比较两个字符串字典序。

文件和流

java.io.FileReader

新增了两个构造方法,允许指定文件的字符集

java.nio.file.Files

新增了 4 个静态工具方法,用于直接向文件中读写 String

public static String readString(Path path) throws IOException
public static String readString(Path path, Charset cs) throws IOException
public static Path writeString(Path path, CharSequence csq, OpenOption... options) throws IOException
public static Path writeString(Path path, CharSequence csq, Charset cs, OpenOption... options) throws IOException

这里有一个小细节值得注意。 readString 本质上是调用原有的 readAllBytes 方法获得 byte 数组,然后用 byte 数组生成 String。但是生成 String 的时候并没有用我们常规的 new String(byte[]),而是使用了 JavaLangAccess.newStringNoRepl 方法。这是一个内部方法,作用是新建一个 String 对象,并且方法的调用者会放弃 byte 数组的拥有关系并传递给被调用者(应该是类似传递指针的操作),所以在创建 String 的过程中不会发生数组拷贝,在性能和 gc 上会有一定的优势(具体还没有测试过)。同样的,writeString 也调用了 JavaLangAccess.getBytesNoRepl 来避免额外的拷贝。

这几个方法在进行小文件读写时还是比较推荐使用的,一方面更简洁,另一方面性能也不会差。

java.io.InputStream

新增了两个方法

/**
 * 创建一个空的流,重复调用 close() 也没有副作用。在没有
 * close 的情况下,调用通常的读方法相当于读到普通流的末尾。
 */
public static InputStream nullInputStream()
public byte[] readNBytes(int len) throws IOException

nullInputStream() 用法暂时不明,看起来像是作为一个占位符,类似 Optional 一样,减少非空的判断,使代码更加简洁。

readNByte(int) 方法则提供了一个更加人性化的调用方式,不用传入 byte[] 数组,好处一是使代码更简洁,二是对 lambda 表达式更友好。

InputStream is = getInputStream();
// 旧接口
byte[] arr1 = new byte[4];
is.read(arr1);
// 新接口
byte[] arr2 = is.readNByte(4);
// 应用于 lambda 表达式
List<Integer> lenList = Arrays.asList(1, 2, 3, 4);
lenList.map(is::readNBytes);

java.io.OutputStream && Reader && Writer

与 InputStream 类似,分别新增了一个创建空的占位对象的静态方法。

java.nio.file.Path

将原本在 Paths 类下的两个静态工具方法移到了 Path 接口中,原 Paths 类下的方法考虑到兼容性还继续保留,但官方提示未来可能会废弃 Paths 类。我们在编码时可以考虑逐步进行迁移。

NIO

java.nio.xBuffer

所有 xBuffer 类都新增了一个 public int mismatch(xBuffer that) 方法,用于比较两个 Buffer 是否一致,如果一致返回 -1,不一致时返回第一位不一致的索引。涉及以下 Buffer 类

  • ByteBuffer
  • CharBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer

jdk.nio.Channels

Channels 是新增的工具类(区别于 java.nio.Channels),提供了一个静态方法用于创建 Channel

public static SelectableChannel readWriteSelectableChannel(FileDescriptor fd, SelectableChannelCloser closer)

其中 SelectableChannelCloser 接口有 2 个方法,定义关闭和释放 Channel 的操作。

void implCloseChannel(SelectableChannel sc) throws IOException
void implReleaseChannel(SelectableChannel sc) throws IOException

个人猜测,由于 java.nio.Channels 主要提供的是 Channel 和流相关的操作,为了区别开所以分在了不同包下。但是从工程的角度来看,JDK 提供两个同名的类会使开发者难以理解,不是一种好的实现方式,推测未来可能进行重构。

java.nio.channels.Selector

新增了 3 个方法,允许传入 Consumer 直接操作 SelectionKey

public int select(Consumer<SelectionKey> action, long timeout) throws IOException
public int select(Consumer<SelectionKey> action) throws IOException
public int selectNow(Consumer<SelectionKey> action) throws IOException

java.lang.Class

Class 类新增了三个方法,用于获取嵌套类关系

// 获取宿主类。非嵌套类的宿主类是它本身。
public Class<?> getNestHost()
// 判断该类是否是某个类的嵌套类
public boolean isNestmateOf(Class<?> c)
// 返回某个类的嵌套类数组。第 1 个固定是宿主类,之后的是该宿主类的嵌套成员,但不保证顺序,同时也会包含自身
public Class<?>[] getNestMembers()

这个改动主要和 JEP 181: Nest-Based Access Control 有关。JEP 181 是 JVM 底层机制改动,对 Java 语法而言,类的可见性并没有改变,在此不展开讨论,暂时也没有想到使用场景。

另外有一点值得注意,lambda 表达式的类型和匿名内部类的宿主类是不一样的。

public class Test {
    public static void main(String[] args) {
        
        // class org.boreas.demo.jdk11.Test$$Lambda$14/0x0000000800066840
        System.out.println(((Function<Object, Object>) o -> null).getClass().getNestHost());
        // class org.boreas.demo.jdk11.Test
        System.out.println(new Function<>() {
            @Override
            public Object apply(Object o) {
                return null;
            }
        }.getClass().getNestHost());
    }

    public class NestClass {}
}

net

jdk.net.ExtendedSocketOptions

新增三个标准的 Keep-Alive 参数配置

TCP_KEEPIDLE: 链路空闲秒数,当 n 秒内未传数据时开始发心跳
TCP_KEEPINTERVAL: probe 重传间隔秒数,当未获得 ack 时再次发送 probe 的秒数
TCP_KEEPCOUNT: 最大重试次数,连续 n 次未获得 ack 后认为连接失效

java.net.http

这部分(JEP 321)主要是代码结构的优化。将 Java 9 引入的 HttpClient、WebSocket 由 jdk.incubator.http 包移动至 java.net.http 包下,并将相关内部类移入 jdk.internal.net.http 包下。

杂项

java.lang.Character.UnicodeBlock

UnicodeBlock 新增了 29 个常量,用于支持 Unicode 10,细节不表。

java.util.zip.Deflater && InFlater

分别新增了三个方法,允许使用 ByteBuffer 作为输入输出数据(此前只能使用 byte 数组),算是在性能上提供了一定优化的余地。

java.util.function.Predicate

新增了一个静态方法创建反向条件校验。实现是旧的 negate() 方法,目的也是为了优化在 lambda 表达式中的调用。

static <T> Predicate<T> not(Predicate<? super T> target)

java.util.concurrent.TimeUnit

新增一个方法用于时间单位换算

public long convert(Duration duration)

值得注意的是,该方法对纳秒做了优化,不会抛出数据类型溢出的异常

java.lang.ref.Refernce

禁用了 clone() 方法,调用时会抛出 CloneNoteSupportedException

java.lang.Thread

移除了 destroy() 方法

另外,Swing, TLS 1.3 相关的内容在此就不一一列举了。

以上。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home...
    光剑书架上的书阅读 3,869评论 2 8
  • 废话不多说,自己进入今天的主题 1、面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: - 抽象:...
    传奇内服号阅读 2,343评论 1 31
  • 有人喜欢踏上陌生城市的土地,有人喜欢约会陌生的朋友,甚至有人喜欢打开快递包裹的瞬间,因为新奇感是生活的必需品...
    大厝悟藏阅读 175评论 0 1
  • 我们像一只迁徙的鸟 降落,俯冲,腾飞 将脸埋入土地 扭曲双翅 光着脚丫 试探天空与土地
    一拂晓一阅读 149评论 0 0
  • 文 /Thinker何 “你那时候跟胜到底是怎么回事啊?” 老哥这次终于没忍住。 毕业这么多年,跟老哥联系很少却...
    Thinker何阅读 635评论 6 5