Java

だいたいコピペです

2023-03-24 java20

言語機能 / switch式のパターンマッチング強化 / 2nd preview

// 型によるマッチング
Object obj = 123L;
String formatted = switch (obj) {
    case Integer i -> String.format("int %d", i);
    case Long l    -> String.format("long %d", l);
    case Double d  -> String.format("double %f", d);
    case String s  -> String.format("String %s", s);
    default        -> obj.toString();
};

// ガード節
static void test(Object obj) {
    switch (obj) {
        case String s when s.length() == 1 -> ...
        case String s                      -> ...
        ...
    }
}

// null もできる
String s = null;
switch (s) {
   case "test" -> "テスト";
   case null -> "ぬるぽ";
   default -> "hello";
}

言語機能 / レコード パターン / 4th preview

static void printSum(Object obj) {
    if (obj instanceof Point p) {
        int x = p.x();
        int y = p.y();
        System.out.println(x+y);
    }
}

record Point(int x, int y) {}

void printSum(Object obj) {
    if (obj instanceof Point(int x, int y)) {
        System.out.println(x+y);
    }
}

API / Scoped Values (new! / Incubator)

// 同一スレッド内で値を共有したいとき
// これまでは ThreadLocal を使っていたが
// これは遅かったらしい
final ThreadLocal<String> STR = new ThreadLocal<>();

void start() {
  STR.set("test");
  proc1();
}

void proc1() {
  System.out.println(STR.get());
  proc2();
}

void proc2() {
  System.out.println(STR.get());
}

// これは早いらしい、よくわからないが
final ScopedValue<String> STR = new ScopedValue<>();

void start() {
    // where内でセットした値が run内部の STR 変数にセットされるような感じぽい
  ScopedValue.where(STR, "test")
    .run(() -> proc1());
}

void proc1() {
  System.out.println(STR.get());
  proc2();
}

void proc2() {
  System.out.println(STR.get());
}

API / Virtual Threads / 2nd Preview

// Java19から変化なし
// これまでのスレッドは java.lang.Thread で OSのスレッドを使っていた
// これは重く、呼び出しなどのボトルネックで作って捨てるような小さい処理ではあまり早くならなかった
// そのため、JDKによって提供されるスレッドの軽量実装を作ったのだった(Goのゴルーチンみたいなね)

// Thread.Builder
// Thread.ofVirtual()
// Thread.ofPlatform()
// が追加されたんだってよ
Thread t = Thread.ofPlatform().unstarted(() -> System.out.println("hello")); // VirtualThread[#000000]/new
t.start(); // hello

Thread t2 = Thread.ofVirtual().unstarted(() -> System.out.println("hello")); //VirtualThread[#000001]/new
t.start(); // hello
// 1件の処理時間が短く、数が多い処理は virtual threadが有利らしいっす

API / Structured Concurrency (2nd Incubator)

異なるスレッドで実行される複数のタスクを1つの作業単位として扱うことでエラーハンドリングやキャンセル処理などを簡素化でき、プログラムの信頼性や可観測性を強化できます。 らしい。複数のタスクをのうち、いずれかで例外が出たときに、一部だけでも成功していれば良しとする。とか、一部がNGだったら他も中断しちゃうとか。なんかそんな雰囲気を感じる。

Response handle() throws ExecutionException, InterruptedException {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        Future<String>  user  = scope.fork(() -> findUser());
        Future<Integer> order = scope.fork(() -> fetchOrder());

        scope.join();           // Join both forks
        scope.throwIfFailed();  // ... and propagate errors

        // Here, both forks have succeeded, so compose their results
        return new Response(user.resultNow(), order.resultNow());
    }
}

API / Foreign Function & Memory API (2nd Preview)

わからん、ヒープ外のメモリを直接扱うAPIらしいっす。

// 1. Find foreign function on the C library path
Linker linker          = Linker.nativeLinker();
SymbolLookup stdlib    = linker.defaultLookup();
MethodHandle radixsort = linker.downcallHandle(stdlib.find("radixsort"), ...);
// 2. Allocate on-heap memory to store four strings
String[] javaStrings = { "mouse", "cat", "dog", "car" };
// 3. Use try-with-resources to manage the lifetime of off-heap memory
try (Arena offHeap = Arena.openConfined()) {
    // 4. Allocate a region of off-heap memory to store four pointers
    MemorySegment pointers = offHeap.allocateArray(ValueLayout.ADDRESS, javaStrings.length);
    // 5. Copy the strings from on-heap to off-heap
    for (int i = 0; i < javaStrings.length; i++) {
        MemorySegment cString = offHeap.allocateUtf8String(javaStrings[i]);
        pointers.setAtIndex(ValueLayout.ADDRESS, i, cString);
    }
    // 6. Sort the off-heap data by calling the foreign function
    radixsort.invoke(pointers, javaStrings.length, MemorySegment.NULL, '\0');
    // 7. Copy the (reordered) strings from off-heap to on-heap
    for (int i = 0; i < javaStrings.length; i++) {
        MemorySegment cString = pointers.getAtIndex(ValueLayout.ADDRESS, i);
        javaStrings[i] = cString.getUtf8String(0);
    }
} // 8. All off-heap memory is deallocated here
assert Arrays.equals(javaStrings, new String[] {"car", "cat", "dog", "mouse"});  // true

API / Vector API (6th Incubator)

わからんが、普通に数学的なベクタとかなんかそんな感じのやつじゃない?(適当)

import jdk.Incubator.vector.*;
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;

void vectorComputation(float[] a, float[] b, float[] c) {

    for (int i = 0; i < a.length; i += SPECIES.length()) { // SPECIES.length() = 256bit / 32bit -> 8
        VectorMask<Float> m = SPECIES.indexInRange(i, a.length); // 端数がマスクされる
                                                                 // a.lengthが11でiが8のとき最初の3つしか要素がないので [TTT.....]
        // FloatVector va, vb, vc;
        FloatVector va = FloatVector.fromArray(SPECIES, a, i, m);
        FloatVector vb = FloatVector.fromArray(SPECIES, b, i, m);
        FloatVector vc = va.mul(va).
                    add(vb.mul(vb)).
                    neg();
        vc.intoArray(c, i, m);
    }
}