大人,时代变了!使用 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 添加了更多有用的方法
In 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"
为集合添加了更多易于使用的工厂方法
In 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);
In 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);
In 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,来体验更高效的开发呢?
(完)
var
关键字貌似是 Java 10 加入的emmm,
String.isBlank()
应该是 Java 11 加入的私密马赛,不是故意找茬qwq
没错的,很多都不是J16添加的,我这里只是说相对J8添加了的内容啦~
荷兰✌🏻