大人,时代变了!使用 Java 16 或 Kotlin 更好的进行插件或模组开发 - Minecraft(我的世界)中文论坛 - Powered by Discuz!.html
Minecraft(我的世界)中文论坛
标题: 大人,时代变了!使用 Java 16 或 Kotlin 更好的进行插件或模组开发 [打印本页]作者: 贺兰兰 时间: 2021-7-27 22:37
标题: 大人,时代变了!使用 Java 16 或 Kotlin 更好的进行插件或模组开发
本帖最后由 贺兰兰 于 2021-7-31 10:57 编辑
大人,时代变了!使用 Java 16 或 Kotlin 更好的进行插件或模组开发
声明:本文章中 Java 8 至 Java 16 以来变化的内容整理自 这个网站,您可以访问该网站以了解更多新版本 Java 的更改
简洁起见,对于某些不重要,或者对开发意义不大的更新,本文并未列出
前言
从很久很久以前,Minecraft 的社区开发者们就开始使用包含了全新的 Stream 库和 Lambda 语句的 Java 8 进行插件或者模组开发,时至今日,Java 8 已成为开发者、服主、玩家使用最多的 Java 版本 —— 或许仍将持续下去,至少对那些忠于旧版本的人们来说。但对于勇于探索新生的冒险者们来说,他们不得不开始正视一个新的拦路虎,亦或者说一种新的机遇 —— 那就是 Java 16。
从 Java Edition 1.17(正确的来说,是 21w19a)开始,Minecraft 需要 Java 16 或更新版本才能运行。对于这个最新更改,人们别无选择,只能慢慢接受 —— 对于玩家和服主来说,可能只是卸载一个旧版本,安装一个新版本的事情。但对于开发者来说,很显然我们需要知道更多。
本文的存在就是这个意义,我们将介绍从 Java 8 开始到 Java 16 重要的开发内容更新,并附带这些更新在以 Java 8 为运行时的 Kotlin 是如何处理的,以帮助开发者们能够更快的适应和享受新的 Java 或者 Kotlin 带来的更高的开发效率。
什么样的开发者适合切换到 Java 16
对于 Minecraft 开发者而言,由于兼容性,很显然并不是所有的开发者都能够切换到 Java 16 进行开发。以普遍理性而言,这些开发者应当可以切换到 Java 16 进行开发:
- 所有面向 Minecraft 1.17 或更高版本进行开发的模组/插件开发者
- 面向 Minecraft 1.13+ 的 Bukkit 插件开发者
为什么使用 Kotlin
Kotlin(JVM) 作为一个基于 JVM 平台的开发语言,为开发者们提供了更加舒适的开发方式,收到了很多开发者的追捧。对于 Kotlin 来说,由于其可以基于 Java 8 运行,因此在大多数情况下无需进行更多更改,只需要在模组或插件内包含一个 Kotlin 的标准库,便可以享受 Kotlin 带来的便捷开发。
本文关于 Kotlin 的示例基于 Java 8 运行时,这意味着,某些 JVM 平台更新可能已经在 Kotlin 同样可用,比如 Kotlin 已经添加了对 JVM 中 Record Class 的支持,但我们并不使用这些版本的代码,而将仍旧选择基于 Java 8 运行时时的解决方案 —— 当然,基于更高版本 Java 运行时的 Kotlin 仍旧可以支持这些代码。
请注意,本文章的主题并不是 Kotlin,因此 Kotlin 内容仅作为对比,并非主要内容。
正文:Java 16 到底带来了什么更改?
使用 var 更简洁的创建局部变量
In Java 8
- final List<String> list = new ArrayList<>();
In Java 16
- final var list = new ArrayList<String>();
注意,var 仅支持局部变量,而不支持全局变量。
In Kotlin
- val list = arrayListOf<String>()
使用 Record Class 更方便的创建数据传输对象
In Java 8
- public class Point{
- private int x;
- private int y;
- public Point(int x, int y){
- this.x = x;
- this.y = y;
- }
- public x(){
- return x;
- }
- public y(){
- return y;
- }
- }
- Point point = new Point(1, 2);
- point.x(); // returns 1
- point.y(); // returns 2
In Java 16
- record Point(int x, int y) { }
- var point = new Point(1, 2);
- point.x(); // returns 1
- point.y(); // returns 2
In Kotlin
- // With additional toString, hashCode function,like @Data in Lombok
- data class Point(val x : Integer,val y : Integer)
- var point = Point(1, 2)
- point.x // return 1
- point.y // return 2
增强的 switch
In Java 8
- int numLetters;
- switch (day) {
- case MONDAY, FRIDAY, SUNDAY:
- numLetters = 6;
- break;
- case TUESDAY:
- numLetters = 7;
- break;
- default:
- String s = day.toString();
- numLetters = s.length();
- }
In Java 16
- int numLetters = switch (day) {
- case MONDAY, FRIDAY, SUNDAY -> 6;
- case TUESDAY -> 7;
- default -> {
- String s = day.toString();
- int result = s.length();
- yield result;
- }
- };
In Kotlin
- var numLetters = when (day){
- MONDAY, FRIDAY, SUNDAY -> 6
- TUESDAY -> 7
- else ->{
- var s = day.toString()
- var result = s.length
- result
- }
- }
使用密封类以限定继承的子类
In Java 8
- // No solution
In Java 16
- public abstract sealed class Shape
- permits Circle, Rectangle {...}
- public class Circle extends Shape {...} // OK
- public class Rectangle extends Shape {...} // OK
- public class Triangle extends Shape {...} // Compile error
- // No need for default case if all permitted types are covered
- double area = switch (shape) {
- case Circle c -> Math.pow(c.radius(), 2) * Math.PI
- case Rectangle r -> r.a() * r.b()
- };
In Kotlin
- package pkg.a
- sealed class Shape
- class Circle : Shape() {...} // OK
- class Rectangle : Shape() {...} // OK
- package pkg.b
- class Triangle : Shape() {...} // Compile error
- // No need for default case if all permitted types are covered
- var area = when (shape) {
- is Circle -> Math.pow(shape.radius(), 2) * Math.PI
- is Rectangle -> shape.a() * shape.b()
- }
文本块
In Java 8
- String html = "<html>\n" +
- " <body>\n" +
- " <p>Hello, world</p>\n" +
- " </body>\n" +
- "</html>\n";
In Java 16
- String html = """
- <html>
- <body>
- <p>Hello, world</p>
- </body>
- </html>
- """;
In Kotlin
- var html = """
- <html>
- <body>
- <p>Hello, world</p>
- </body>
- </html>
- """
当变量为 null 时提供更加详细友好的 NullPointerException 描述
In Java 8
- a.b.c.i = 99;
- ---
- Exception in thread "main" java.lang.NullPointerException
In Java 16
- a.b.c.i = 99;
- ---
- Exception in thread "main" java.lang.NullPointerException:
- Cannot read field "c" because "a.b" is null
模式匹配 instanceof 以省略必要的显式类型转换
In Java 8
- if (obj instanceof String) {
- String s = (String) obj;
- if(s.length() > 5){
- System.out.println("obj is a String with more than 5 characters: " + s.toUpperCase());
- }
- }
In Java 16
- if (obj instanceof String s && s.length() > 5) {
- System.out.println("obj is a String with more than 5 characters: " + s.toUpperCase());
- }
In Kotlin
- if (obj is String && obj.length > 5) {
- println("obj is a String with more than 5 characters: " + obj.uppercase(Locale.getDefault()))
- }
接口中允许私有方法
In Java 8
- // Not allowed
In Java 16
- public interface some {
- private void doSomething(){
- // do something
- }
- }
In Kotlin
- interface some {
- private fun doSomething() {
- // do something
- }
- }
更方便的将 Stream 收集为 List
In Java 8
- List<String> result =
- Stream.of("one", "two", "three")
- .filter(s -> s.length() == 3)
- .collect(Collectors.toList());
In Java 16
- List<String> result =
- Stream.of("one", "two", "three").stream()
- .filter(s -> s.length() == 3)
- .toList();
In Kotlin
- var result =
- Stream.of("one", "two", "three")
- .filter(s -> s.length() == 3)
- .toList()
为 String 添加了更多有用的方法
Java 16
- " ".isBlank(); // will return true
- Stream<String> lines = "1\n2\n3\n4".lines(); // will return Stream ["1", "2", "3", "4"]
- "a".repeat(4); // will return "aaaa"
- "\u2000 hello \u2000".strip(); // will return "hello"
为集合添加了更多易于使用的工厂方法
Java 8
- Set<Integer> mySet = new HashSet<>();
- mySet.add(1);
- mySet.add(2);
- mySet.add(3);
- List<Integer> myList = new ArrayList<>();
- myList.add(1);
- myList.add(2);
- myList.add(3);
- Map<String, Integer> myMap = new HashMap<>();
- myMap.put("one",1);
- myMap.put("two",2);
Java 16
- Set<Integer> mySet = Set.of(1, 2, 3);
- List<Integer> myList = List.of(1, 2, 3);
- Map<String, Integer> myMap = Map.of("one", 1, "two", 2);
Kotlin
- var mySet = setOf(1, 2, 3)
- var myList = listOf(1, 2, 3)
- var myMap = mapOf("one" to 1, "two" to 2)
除此之外,支持更多平台,支持 TLS 1.3,全新的 jlink 工具,HTML5 标准的 Javadoc,更强大的 ZGC 等特性都将可以在全新的 Java 16 中体验到。
值得一提的是,Java 8 中内置的 JavaScript 解析器 Nashron ,jjs 工具,Java EE,Unsafe::defineAnonymousClass(),基本数据类型的包装对象的构造函数都在 Java 16 中被移除或是废弃。
最后。为什么不现在就切换到 Java 16,来体验更高效的开发呢?
(完)
[groupid=1511]Server CT[/groupid]
作者: shuaishuai520 时间: 2021-7-27 22:38
wc,太详细了,楼主给你顶一个
作者: 逍遥先生. 时间: 2021-7-27 22:41
这就支持
作者: 紅葉 时间: 2021-7-27 22:45
建议各位都拥抱新时代的潮流,使用Java16或kotlin
作者: 小六子鸭. 时间: 2021-7-27 23:16
本帖最后由 小六子鸭. 于 2021-7-28 18:16 编辑
前些天还在赶忙着学kotlin呢 这就看到贺兰大大的文章了
作者: Bowser 时间: 2021-7-27 23:27
Nashorn被删了,然而forge又把Nashorn加回来了(笑)
作者: Glom_ 时间: 2021-7-30 01:44
Great.

作者: 结冰的离季 时间: 2021-7-30 21:15
kotlin +1 使用kotlin 何不再试试 Gradle Kotlin DSL 来构建
这里是gradle Groovy语言转 gradle Kotlin 的官方迁移教程:链接
以下是我参考文档+自己摸索写的Gradle Kotlin 脚本
build.gradle.kts
- plugins {
- java
- id("org.jetbrains.kotlin.jvm") version "1.4.0"
- id("com.github.johnrengelman.shadow") version "6.1.0" //使用shadow将依赖打包进jar包
- // kotlin("jvm") version "1.0.0"
- }
- group = "top.iseason.kotlin" //声明包名
- version = "1.0.5" //插件版本
- val mainClass = "DeEnchantmentPlugin" //插件主类
- val author = "Iseason" //作者
- val jarOutputFile = "E:\\mc\\1.17.1 servers\\plugins" //jar导出路径
- repositories { //仓库
- mavenCentral()
- maven {
- url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
- }
- maven {
- url = uri("https://repo.codemc.org/repository/maven-public/")
- }
- }
- dependencies { //依赖
- api("org.spigotmc:spigot-api:1.16.4-R0.1-SNAPSHOT")
- implementation("org.jetbrains.kotlin:kotlin-stdlib:1.4.31")
- implementation("io.github.bananapuncher714:nbteditor:7.17.0")
- }
- (tasks.getByName("processResources") as ProcessResources).apply {
- val p = "${project.group}.${rootProject.name.toLowerCase()}"
- include("config.yml") //包含config.yml文件
- //包含plugin.yml并修改文件内容,这里我用于同步插件信息
- //plugin.yml里面的例子: name: ${name} \n main: ${main}
- include("plugin.yml").expand(
- "name" to rootProject.name.apply { this.toLowerCase() },
- "main" to "$p.$mainClass",
- "version" to project.version,
- "author" to author
- )
- }
- //添加ShadowJar任务,将依赖打包,stdlib是kotlin依赖,nbteditor是我自己使用的nbt编辑依赖
- tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
- dependencies {
- include(dependency("io.github.bananapuncher714:nbteditor:7.17.0"))
- include(dependency("org.jetbrains.kotlin:kotlin-stdlib:1.4.31"))
- }
- destinationDirectory.set(file(jarOutputFile))
- }
- //编译完成后的任务
- val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
- compileKotlin.kotlinOptions.jvmTarget = "1.8"
- java.sourceCompatibility = JavaVersion.VERSION_1_8
- java.targetCompatibility = JavaVersion.VERSION_1_8
- //设置jar包输出路径
- tasks.jar {
- this.destinationDirectory.set(file(jarOutputFile))
- }
作者: Dasffafa 时间: 2021-7-31 08:56
本帖最后由 Dasffafa 于 2021-8-1 20:12 编辑
Java16看起来很棒啊,考虑切换了编辑:放弃了这个想法,因为Java16不是长期支持版本,今年九月,长期支持版本Java17就要面世了,到时候我会换Java17
作者: 黎雨轩 时间: 2021-10-17 21:22
所以1.16版本成了Forge团队的LTS


作者: WorriKe 时间: 2022-1-4 23:02
Kotlin加一 真希望能换掉顽固的Java 8...
作者: WorriKe 时间: 2022-1-4 23:29
结冰的离季 发表于 2021-7-30 21:15
kotlin +1 使用kotlin 何不再试试 Gradle Kotlin DSL 来构建
这里是gradle Groovy语言转 gradle Kotlin 的 ...
太感谢了 正好在研究KTS😘
作者: AustinPaul 时间: 2022-1-7 16:04
这个简洁,必须支持。
作者: 心伤丶泪 时间: 2022-2-7 11:23
java16 适合低版本? java原来好像是可以适用于部分软件程序的
作者: teddyxlandlee 时间: 2022-2-9 14:06
最近发现 Kotlin 1.6.10 编译器针对 Java 8+ 做了亿些优化,高兴了一下午
作者: teddyxlandlee 时间: 2022-2-9 14:15
本帖最后由 teddyxlandlee 于 2022-2-9 14:20 编辑
结冰的离季 发表于 2021-7-30 21:15
kotlin +1 使用kotlin 何不再试试 Gradle Kotlin DSL 来构建
这里是gradle Groovy语言转 gradle Kotlin 的 ...
现在一般都不用shadow吧,即使用shadow也要relocate一下,防止跟其它Mod冲突
一般用的是 loom 提供的 dependencies -> include
- dependencies {
- // ...
- include (implementation ("com.google.guava:guava:31.0.1-jre")
- modImplementation ("net.fabricmc:fabric-language-kotlin:1.7.0+kotlin.1.6.10") // 这是 Fabric 给的 Fabric Language Kotlin 模组,自带 LanguageAdapter 和 kotlin-stdlib-jdk8、kotlin-reflect 等基本库。这里不 include 的原因是这玩意在 CurseForge 上有,很多 Mod 也在用,体积也不小,不必 include,只需作为前置让玩家自行下载即可
- }
你们在用 Forge/Bukkit 啊,没事了
但记得relocate一下
学学人家 Lucky Block 作者是怎么做的
中文论坛 - Powered by Discuz!_files/wRqSftdyTsonZxu.png)
作者: 456413 时间: 2022-2-10 10:52
java16定义语法逐渐向javascript靠拢。。。难道java逐渐从强类型转向弱类型语言了?[哭笑][哭笑][哭笑]
作者: 贺兰兰 时间: 2022-2-10 12:05
456413 发表于 2022-2-10 10:52
java16定义语法逐渐向javascript靠拢。。。难道java逐渐从强类型转向弱类型语言了?[哭笑][哭笑][哭笑] ...
?
欢迎光临 Minecraft(我的世界)中文论坛 (https://www.mcbbs.net/) | Powered by Discuz! X3.5 |