godot-start/blog/4. 千呼万唤的协程来了 java 19,新特性预览附...

156 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 千呼万唤的协程来了 java 19新特性预览附上example示例
- Java 19 已于 2022 年 9 月 20 日发布。您可以在此处下载 [Java 19](https://jdk.java.net/19/) 或者我们直接在idea下载Jdk 19。
![img.png](image/4/1.png)
- 对我来说最令人兴奋的新特性是虚拟线程协程它在Project Loom中已经开发了好几年现在终于作为预览版包含在 JDK 中。
- 协程是现代web并发的神器这是 Java 19 中另一个令人兴奋的孵化器新特性。这个版本的协程可以用了预期在下个版本将彻底release。
- 对于需要访问非 Java 代码(例如 C 标准库的人来说还有一个好消息Foreign Function & Memory API在经过五轮孵化后已进入预览阶段。
### 协程(预览)
- 对我来说Java 19 中最令人兴奋的创新是“虚拟线程”。虚拟线程已经在Project Loom中开发了几年目前只能使用自编译的 JDK 进行测试。
- 使用 Thread.startVirtualThread(),此方法创建一个新的虚拟线程来执行给定的 Runnable 任务。
```
Runnable runnable = () -> System.out.println("Virtual Thread");
Thread.startVirtualThread(runnable);
//or
Thread.startVirtualThread(() -> {
//Code to execute in virtual thread
System.out.println("Virtual Thread");
});
```
- 使用 Thread.Builder
```
Runnable runnable = () -> System.out.println("Virtual Thread");
Thread virtualThread = Thread.ofVirtual().start(runnable);
```
```
Thread.Builder builder = Thread.ofPlatform().name("Platform-Thread");
Thread t1 = builder.start(() -> {...});
Thread t2 = builder.start(() -> {...});
```
### 外部函数和内存 API预览版
- Foreign Function & Memory API 允许直接从Java 访问本机内存即Java 堆外的内存和访问本机代码例如C 库)。
```
public class FFMTest {
public static void main(String[] args) throws Throwable {
// 1. Get a lookup object for commonly used libraries
SymbolLookup stdlib = Linker.nativeLinker().defaultLookup();
// 2. Get a handle to the "strlen" function in the C standard library
MethodHandle strlen = Linker.nativeLinker().downcallHandle(
stdlib.lookup("strlen").orElseThrow(),
FunctionDescriptor.of(JAVA_LONG, ADDRESS));
// 3. Convert Java String to C string and store it in off-heap memory
MemorySegment str = implicitAllocator().allocateUtf8String("Happy Coding!");
// 4. Invoke the foreign function
long len = (long) strlen.invoke(str);
System.out.println("len = " + len);
}
}
```
### 开关的模式匹配(第三次预览)
- 在 Java 19 中JDK Enhancement Proposal 427更改了所谓的“受保护模式”的语法在上面的示例中为“ String s && s.length() > 5”。取而代之的是&&,我们现在必须使用 new
关键字when。
```
switch (obj) {
case String s when s.length() > 5 -> System.out.println(s.toUpperCase());
case String s -> System.out.println(s.toLowerCase());
case Integer i -> System.out.println(i * i);
default -> {}
}
```
### 记录模式(预览)
- 我最好用一个例子来解释什么是记录模式。假设我们定义了以下记录:
```
public record Position(int x, int y) {}
```
### System.out 和 System.err 的新系统属性
如果您使用 Java 19 运行现有应用程序,您可能会在控制台上看到问号而不是特殊字符。
这是因为,从 Java 19 开始操作系统的默认编码用于打印到System.outSystem.err例如 Windows 上的“Cp1252”。要将输出更改为 UTF-8您必须在调用应用程序时添加以下 VM 选项:
```
-Dstdout.encoding=utf8 -Dstderr.encoding=utf8
```
如果不想每次启动程序时都这样做,还可以通过定义以下环境变量来全局设置这些设置(是的,它以下划线开头):
```
_JAVA_OPTIONS="-Dstdout.encoding=utf8 -Dstderr.encoding=utf8"
```
### 创建预分配 HashMap 的新方法
直觉上人们会认为这HashMap为 120 个映射提供了空间。
这是因为HashMap使用默认加载因子 0.75 进行初始化。这意味着一旦 HashMap 已满 75%,它就会被重建(“重新散列”)两倍的大小。 这确保了元素在HashMap's 桶中尽可能均匀地分布,并且尽可能少的桶包含多个元素。
```
Map<String, Integer> map = new HashMap<>(120);
```
因此HashMap容量为 120 的初始化只能容纳 120 × 0.75 = 90 个映射。
要创建HashMap120 个映射您必须通过将映射数量除以负载因子来计算容量120 ÷ 0.75 = 160。
因此HashMap必须按如下方式创建 120 个映射:
```
// for 120 mappings: 120 / 0.75 = 160
Map<String, Integer> map = new HashMap<>(160);
```
Java 19 让我们更容易——我们现在可以编写以下代码:
```
Map<String, Integer> map = HashMap.newHashMap(120);
```
如果我们查看新方法的源代码,我们会发现它们的作用与我们之前所做的相同:
```
public static <K, V> HashMap<K, V> newHashMap(int numMappings) {
return new HashMap<>(calculateHashMapCapacity(numMappings));
}
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static int calculateHashMapCapacity(int numMappings) {
return (int) Math.ceil(numMappings / (double) DEFAULT_LOAD_FACTOR);
}
```