准备给之前 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);
那为何不建议使用呢,主要有三个缺点:
- 语义模糊。别人(我)可能看不懂
- 创建了不必要的类型。匿名类是一个新类
- 可能造成内存泄漏。匿名类实例持有外部类实例的引用,如果匿名类实例作为函数返回值暴露给其它对象,在它的生命周期结束前,外部类对象也不会被释放
有没有替代写法
通常这种写法被用来初始化容器,例如
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");
更多细节分析见参考链接。
参考链接
如有问题请在下方留言,文章转载请注明出处,详细交流请加下方群组!请大佬不要屏蔽文中广告,因为它将帮我分担服务器开支,如果能帮忙点击我将万分感谢。
完全看不懂 留下了没技术的泪水#(狂汗)
哈哈,这不难,知道就是知道,不知道就是不知道