MENU

Double Curly Braces Initialization in Java

2021 年 08 月 26 日 • 阅读: 5470 • 后端

准备给之前 Python 写的 QQ 机器人加点功能,发现升级后的依赖库变动很大,加上之前有些 Bug,瞬间不想用了,用上游框架重写吧。上游项目基于 Kotlin,我不熟悉,但提供 Java API,克隆示例代码,OK,可以运行。正准备往前推进,突然发现 有段代码 的语法我竟然看不懂,心想 Java 用了挺长时间不至于吧。

Bot bot = BotFactory.INSTANCE.newBot(123456, "test", new BotConfiguration() {{
    fileBasedDeviceInfo();
    setProtocol(MiraiProtocol.ANDROID_PAD);
}});

想了两分钟没明白 new BotConfiguration() {{...}} 为何要用双层花括号,只能求助搜索引擎。一搜发现讨论这个话题的文章大概每年有一两篇,不多也不少,并且基本被人分析透了,所以我写这篇文章又是没有意义的重复。不管了,谁叫咱菜呢。

它是什么

这其实就是匿名类套了个初始化块,说出来一下就懂了。

class A {
    // 初始化块
    {
        System.out.println("Instance init A");
    }

    A() {
        System.out.println("Constructor A");
    }
}

只不过 new BotConfiguration() {{...}} 创建的类除了初始化块,自身没有任何属性和方法。

为什么不建议使用

首先说为什么有人使用。就像文章开头的代码,如果按常规写法会多出几行初始化代码,而采用双括号写法看上去更简洁。

BotConfiguration config = new BotConfiguration();
config.fileBasedDeviceInfo();
config.setProtocol(MiraiProtocol.ANDROID_PAD);

Bot bot = BotFactory.INSTANCE.newBot(123456, "test", config);

那为何不建议使用呢,主要有三个缺点:

  1. 语义模糊。别人(我)可能看不懂
  2. 创建了不必要的类型。匿名类是一个新类
  3. 可能造成内存泄漏。匿名类实例持有外部类实例的引用,如果匿名类实例作为函数返回值暴露给其它对象,在它的生命周期结束前,外部类对象也不会被释放

有没有替代写法

通常这种写法被用来初始化容器,例如

List<String> list = new ArrayList<>() {{
    add("Java");
    add("Redis");
}};

现在可以使用 Java 8 Stream API

List<String> list = Stream.of("Java", "Redis").collect(Collectors.toList());

或者 Arrays, Collections 等工具类方法

List<String> list = Arrays.asList("Java", "Redis");

也可以使用 Java 9 的容器工厂

List<String> list = List.of("Java", "Redis");

更多细节分析见参考链接。

参考链接

TG 大佬群 QQ 大佬群

返回文章列表 文章二维码
本页链接的二维码
打赏二维码
添加新评论

Loading captcha...

已有 2 条评论
  1. 完全看不懂 留下了没技术的泪水#(狂汗)

    1. LOGI LOGI   Windows 10 x64 Edition  Google Chrome 93.0.4577.63

      @叶小明的博客哈哈,这不难,知道就是知道,不知道就是不知道