JDK

Java 19新機能

Java 19が公開されました。Java 19のLinux/RISC-V Port(JEP422)を除くとすべてPreviewかIncubatorとなっています。

  • レコードパターン(プレビュー)[JEP405]
  • Linux/RISC-Vポート[JEP422]
  • 外部関数と外部メモリAPI (プレビュー)[JEP424]
  • 仮想スレッド(プレビュー)[JEP425]
  • ベクターAPI(4次インキュベーター)[JEP426]
  • switch文パターンマッチ(3次プレビュー)[JEP427]
  • 構造化並列API(インキュベーター)[JEP428]

https://openjdk.org/projects/jdk/19/

JEP405: レコードパターン(プレビュー)

instanceof演算子の拡張みたいなものでしょうか。if ( obj instanceof A a)という書き方をして,objがクラスAのインスタンスであった場合はキャストされたオブジェクトが変数aに格納されるという記述ができました。

public class RecordPattern
{
    public static void main(String[] args)
    {
        Object obj = new String("Hello World");
        if(obj instanceof String str)
        {
            System.out.println(str);
        }
        else
        {
            System.out.println("It's not a instance of String");
        }
    }
}

Hello World

JEP424: 外部関数と外部メモリ(プレビュー)

java.lang.foreignパッケージに外部関数と外部メモリを扱うクラス等が用意されています。C言語の文字列長を検査するstrlen()をJavaから呼び出してみます。コンパイルには–enable-previewと -source 19という2つのオプションが必要です。

import java.lang.foreign.Linker;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.SymbolLookup;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;

public class ForeignFunction
{
    public static void main(String[] args) throws Throwable
    {
        Linker linker = Linker.nativeLinker();
        SymbolLookup stdlib = linker.defaultLookup();
        FunctionDescriptor functionDescriptor = FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);
        MethodHandle strlen = linker.downcallHandle(stdlib.lookup("strlen").get(), functionDescriptor);
        String javaStrings   = "Hello from Java 19";
        long len = -1L;
        try(MemorySession session = MemorySession.openConfined())
        {
            MemorySegment cString = MemorySegment.allocateNative(javaStrings.length() + 1, session);
            cString.setUtf8String(0, javaStrings);
            len = (long)strlen.invoke(cString);
        }
        System.out.printf("strlen()=%d\n", len);
    }
}

ノート:ForeignFunction.javaはJava SE 19のプレビュー機能を使用します。
ノート:詳細は、-Xlint:previewオプションを指定して再コンパイルしてください。
strlen()=18

JEP425: 仮想スレッド(プレビュー)

従来のプラットフォームによるスレッドに加えて,Java VMによる仮想スレッドが登場しています。性能が著しく向上しているとのことですが,パフォーマンスまでは確認できていません。java.util.concurrent.ExecutorsクラスにnewVirtualThreadPerTaskExecutor()というstaticメソッドが追加されており,これを使って仮想スレッドを生成することができます。

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.stream.IntStream;

public class VirtualTrhead
{
    public static void main(String[] args) throws Exception
    {
        try(ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor())
        {
            IntStream.range(0, 10).forEach(i -> { executor.submit(new ExampleTask(i)); });
        }
    }
    static class ExampleTask implements Callable<Integer>
    {
        private int number;
        public ExampleTask(int arg)
        {
            number = arg;
        }
        @Override
        public Integer call() throws Exception
        {
            IntStream.range(0, 10).forEach(i -> System.out.printf("Hello %d\n", number));
            return number;
        }
    }
}

JEP426: ベクターAPI(インキュベーター)

ベクトル計算が容易に記述できるようになります。ベクトルAとベクトルBが存在するとして,(A×A+B×B)×(-1)の計算を行う例です。配列を使った場合はループを用いて計算をくり返す必要があります。ベクターAPIでGPUを用いた最適化が行われるような環境では高いパフォーマンスを期待できるのでしょうか・・・。

次のようにコマンドを実行してコンパイルしています。

javac –enable-preview -source 19 –add-modules jdk.incubator.vector

import java.util.Arrays;
import jdk.incubator.vector.DoubleVector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorSpecies;

public class VectorAPI
{
    private static final VectorSpecies<Double> SPECIES = DoubleVector.SPECIES_PREFERRED;
    public static void main(String[] args)
    {
        VectorAPI instance = new VectorAPI();
        double[] array = new double[] { 1.0d, 2.0d, 3.0d };
        double[] result = new double[array.length];
        instance.calculate_by_vector(array, array, result);
        Arrays.stream(result).forEach(f -> System.out.print(f));
    }
    private void calculate_by_vector(double[] array1, double[] array2, double[] result)
    {
        for(int i = 0; i < array1.length; i+= SPECIES.length())
        {
            VectorMask<Double> mask = SPECIES.indexInRange(i, array1.length);
            DoubleVector vector1 = DoubleVector.fromArray(SPECIES, array1, i, mask);
            DoubleVector vector2 = DoubleVector.fromArray(SPECIES, array2, i, mask);
            DoubleVector resultVector = vector1.mul(vector1).add(vector2.mul(vector2)).neg();
            resultVector.intoArray(result, i, mask);
        }
    }
}

警告:実験的なモジュールを使用しています: jdk.incubator.vector
警告1個
WARNING: Using incubator modules: jdk.incubator.vector
-2.0 -8.0 -18.0

JEP427: switch文パターンマッチ(プレビュー)

switch文は更に機能拡張されるようです。データ型による分岐に加えてその値を評価する機能が追加されています。複雑になりすぎて使いこなせない,あるいは,バグが紛れ込みやすくなってしまわないか心配されます。

import java.util.ArrayList;
import java.util.List;

public class SwitchPatternMatch
{
    public static void main(String[] args)
    {
        List<Object> list = makeList();
        for(Object obj : list)
        {
            System.out.printf("%s\t", (obj == null) ? "null" : obj.getClass().getName());
            switch(obj)
            {
                case null -> System.out.println("[A] null");
                case Integer i when i < 5 -> System.out.printf("[B] (%d)\n", i);
                case Integer i -> System.out.printf("[C] (%d)\n", i);
                case String s -> System.out.printf("[D] (\"%s\")\n", s);
                default -> System.out.printf("[E] (%s) \n", obj.toString());
            }
        }
    }
    private static List<Object> makeList()
    {
        List<Object> list = new ArrayList<>();
        list.add(null);
        list.add(0);
        list.add(1);
        list.add(10);
        list.add(20d);
        list.add(new String("Hello"));
        list.add(Boolean.TRUE);
        list.add(list);
        return list;
    }
}

ノート:SwitchPatternMatch.javaはJava SE 19のプレビュー機能を使用します。
ノート:詳細は、-Xlint:previewオプションを指定して再コンパイルしてください。
null [A] null
java.lang.Integer [B] (0)
java.lang.Integer [B] (1)
java.lang.Integer [C] (10)
java.lang.Double [E] (20.0)
java.lang.String [D] (“Hello”)
java.lang.Boolean [E] (true)
java.util.ArrayList [E] ([null, 0, 1, 10, 20.0, Hello, true, (this Collection)])

JEP428: 構造化並列API(インキュベーター)

マルチスレッドで動作させる場合に子スレッドを効果的に管理する仕組みのようである。StructuredTaskScopeというクラスが導入されており,子スレッドのうち1つでも失敗していた場合は全体を失敗として例外をスローするなどが行えます。

import java.util.concurrent.Callable;
import jdk.incubator.concurrent.StructuredTaskScope;
import jdk.incubator.concurrent.StructuredTaskScope.ShutdownOnSuccess;
import jdk.incubator.concurrent.StructuredTaskScope.ShutdownOnFailure;

public class StructuredTaskAPI
{
    public static void main(String[] args) throws Exception
    {
        successExample();
        try
        {
            failExample();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    private static void successExample() throws InterruptedException
    {
        try(StructuredTaskScope.ShutdownOnSuccess<String> scope = new StructuredTaskScope.ShutdownOnSuccess<>())
        {
            scope.fork(() -> { return "Hello World";});
            scope.fork(() -> { return "Bye";});
            scope.join();
            String result = scope.result(e -> new RuntimeException("発生しないはず"));
            System.out.println(result);
        }
    }
    private static void failExample() throws Exception
    {
        try(StructuredTaskScope.ShutdownOnFailure scope = new StructuredTaskScope.ShutdownOnFailure())
        {
            scope.fork(new Callable<String>() {
                @Override
                public String call() throws InterruptedException
                { 
                    Thread.sleep(30); 
                    return "Hello World";
                }
            });
            scope.fork(new Callable<Integer>() {
                @Override
                public Integer call() throws InterruptedException
                {
                    throw new RuntimeException("ダミーのエラー");
                }
            });
            scope.join();
            scope.throwIfFailed();
        }
    }
}

警告:実験的なモジュールを使用しています: jdk.incubator.concurrent,jdk.incubator.vector
警告1個
WARNING: Using incubator modules: jdk.incubator.vector, jdk.incubator.concurrent
Hello World
java.util.concurrent.ExecutionException: java.lang.RuntimeException: ダミーのエラー
at jdk.incubator.concurrent/jdk.incubator.concurrent.StructuredTaskScope$ShutdownOnFailure.throwIfFailed(StructuredTaskScope.java:1125)
at StructuredTaskAPI.failExample(StructuredTaskAPI.java:51)
at StructuredTaskAPI.main(StructuredTaskAPI.java:13)
Caused by: java.lang.RuntimeException: ダミーのエラー
at StructuredTaskAPI$2.call(StructuredTaskAPI.java:47)
at StructuredTaskAPI$2.call(StructuredTaskAPI.java:43)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at java.base/java.lang.VirtualThread.run(VirtualThread.java:287)
at java.base/java.lang.VirtualThread$VThreadContinuation.lambda$new$0(VirtualThread.java:174)
at java.base/jdk.internal.vm.Continuation.enter0(Continuation.java:327)
at java.base/jdk.internal.vm.Continuation.enter(Continuation.java:320)

JDK

Java 18リリース

Java 18がリリースされました。新機能は以下のようなものがアナウンスされていますが,目立った機能追加はないようです。

https://openjdk.java.net/projects/jdk/18/

  • JEP-400 UTF-8がデフォルトに
  • JEP-408 シンプルウェブサーバ
  • JEP-413 Java APIドキュメントにおけるコードスニペット
  • JEP-416 メソッドハンドルを用いたコアリフレクションの再実装
  • JEP-417 ベクターAPI(3次インキュベーター)
  • JEP-418 インターネットアドレス解決SPI
  • JEP-419 外部関数と外部メモリAPI(2次プレビュー)
  • JEP-420 switchにおけるパターンマッチング(2次プレビュー)
  • JEP-421 削除のためのfinalize()非推奨

UTF-8がデフォルトに

他の言語では既に多くがUTF-8がデフォルトになっていますが,JavaにおいてもようやくUTF-8がデフォルトのエンコーディングになったようです。Javaでテキストファイルを扱う時には毎回エンコーディングを指定していました。今後はUTF-8を用いる場合は省略できるでしょう。標準入出力は対象外となっているので,コンソールの扱いには影響はなさそうです。

シンプルウェブサーバ

SDKに簡易なウェブサーバが同梱されるようになりました。jwebserverという新たなコマンドが導入されます。静的なファイルを提供するプロトタイピング,デバッグ,テスト用のサーバと説明されています。–helpオプションでヘルプを表示させることができます。

Java APIドキュメントにおけるコードスニペット

{@snippet …} によってJavaDocコメントにJavaコードを埋め込めるようになります。

メソッドハンドルを用いたコアリフレクションの再実装

java.lang.reflectパッケージのMethod, Constructor, Fieldの実装が見直されました。43%-57%高速化されたそうです。

ベクターAPI(3次インキュベーター)

SIMD命令により効率的にベクトル演算を行うことができるAPIのようです。

インターネットアドレス解決SPI

インターネット上のアドレスを解決するためのインタフェースを提供するAPIのようです。java.net.InetAddressというクラスが提供されています。

外部関数と外部メモリAPI(2次プレビュー)

JNIに替わる新たな外部関数を呼び出すAPIです。

switchにおけるパターンマッチング(2次プレビュー)

switch文が拡張されます。当初は数値のみという制約がありましたが,オブジェクトの型によって分岐できるよう拡張され,記述方法も変更されます。従来の書き方も可能なようです。次のような書き方ができます。

private void(Object arg) {
    switch(arg) {
        case String s -> System.out.println("String");
        case int[] a -> System.out.println("Integer Array");
}

削除のためのfinalize()非推奨

finalize()メソッドが非推奨になります。GCによりオブジェクトが破棄される直前に呼び出されるのですが,GCが行われるまで実行されず,そのタイミングが制御できないため使わない方がよいと言われていました。ついに削除されます。

JDK

Java 17 新機能(4)

JEP 412: 外部メモリと外部関数 (Incubator)

Javaランタイム外部のメモリにアクセスしたり,ネイティブ関数を呼び出すためのAPIを提供します。以前からJNIなどの方法でアクセスすることは可能でしたが,実装が大変である上にパフォーマンスにも課題がありました。より洗練されたAPIを提供しようという意図で開発されています。

  • 外部メモリの割り当て
  • 構造化された外部メモリの操作とアクセス
  • 外部リソース(リソーススコープ)のライフサイクル管理と外部関数の呼び出し

以下のプログラムではC言語の文字列の長さを返すsize_t strlen(const char *s)を呼び出します。コンパイル時には,–add-modules jdk.incubator.foreignオプションをつける必要があります。また,実行には–add-modules jdk.incubator.foreign オプションに加えて,–enable-native-access=ALL-UNNAMEDオプションもつける必要があります。

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.ValueLayout;
public class ForeignFunction01
{
    public static void main(String[] args) throws Throwable
    {
        strlen("Hello World!");
    }
    private static void strlen(String string) throws Throwable
    {
        MethodHandle strlen = CLinker.getInstance().downcallHandle(
            CLinker.systemLookup().lookup("strlen").get(),
            MethodType.methodType(long.class, MemoryAddress.class),
            FunctionDescriptor.of(CLinker.C_LONG_LONG, CLinker.C_POINTER)
        );
        MemorySegment str = CLinker.toCString(string, ResourceScope.newImplicitScope());
        long length = (long)strlen.invokeExact(str.address()); 
        System.out.printf("Length of string \"%s\" is %d\n", string, length);
    }
}

警告:実験的なモジュールを使用しています: jdk.incubator.foreign
警告1個
WARNING: Using incubator modules: jdk.incubator.foreign
Length of string “Hello World!” is 12

JEP 414: ベクトルAPI (Second Incubator)

ベクトル演算をサポートしているCPUに向けてベクトル演算をサポートするAPIを提供するものである。

JDK

Java 17 新機能(3)

JEP 407: RMIアクティベーションの削除

Java 15から「非推奨」とされていたRMIアクティベーション機能,具体的にはjava.rmi.activationパッケージが削除されています。

JEP 409: シールクラス

Java 15からプレビューとして含まれていたシールクラスが正式に導入されました。内容については過去の記事をご参照ください。

JEP 410: 実験的なAOTコンパイラ,JIT コンパイラの削除

実験的なコンパイラAOT(ahead-of-time)コンパイラとJIT(Just-in-time)コンパイラが削除されています。AOTコンパイラはJEP 295で導入されたものです。またJITコンパイラはJEP 317で導入されたものです。

JEP 411: 削除に向けたセキュリティマネジャーの非推奨

セキュリティマネジャーに関連するほとんどのクラスとメソッドが非推奨となっています。また実行時にセキュリティマネジャーをインストールしようとしたり,コマンドラインでセキュリティマネジャーを有効にしようとすると警告メッセージが出力されます。

SecurityManagerTest.java:5: 警告:[removal] java.langのSecurityManagerは推奨されておらず、削除用にマークされています
SecurityManager manager = new SecurityManager();

JDK

Java 17 新機能(2)

JEP 406: switch文でのパターンマッチング (プレビュー)

switch文が更に拡張されている。caseラベルにクラス名を指定することで,インスタンスの型に応じて条件分岐できるようになりました。次の例ではObject型,Parent型,ChildA型のオブジェクトとnullを渡して,条件分岐させています。

コンパイルには,–enable-previewオプションと –source 17オプションをつける必要があります。

public class Switch01
{
    public static void main(final String[] args)
    {
        Object[] array = new Object[]{ new Object(), new Parent(), new ChildA(), null };
        for(Object obj : array)
        {
            switch(obj)
            {
                case null:
                    System.out.println("null");
                    break;
                case ChildA c:
                    System.out.println("ChildA class");
                    break;
                case Parent p:
                    System.out.println("Parent class");
                    break;
                default:
                    System.out.println("Other class");
            }
        }
    }
}
class Parent{}
class ChildA extends Parent{}

Other class
Parent class
ChildA class
null

更には,switchラベルに続けてboolean型の条件を続けることができるよう拡張されました。次の例ではshape変数に格納されているオブジェクトがCircleクラスの場合で,かつ,getArea()の戻り値が100を超えている場合にLarge Circleというメッセージを表示します。

public class Switch02
{
    public static void main(final String[] args)
    {
        Shape[] array = new Shape[] { null, new Circle(1), new Circle(10), new Rectangle(5, 3) };
        for(Shape shape : array)
        {
            switch(shape)
            {
                case null ->
                    System.out.println("null");
                case Circle c && c.getArea() > 100 ->
                    System.out.println("Large Circle");
                case Rectangle r ->
                    System.out.println("Rectangle");
                default ->
                    System.out.println("other");
            }
        }
    }
}
/** 図形 */
abstract class Shape
{
    /** 
     面積を返す
     * @return 面積
    */
    abstract double getArea();
}
/** 円 */
class Circle extends Shape
{
    /** 半径 */
    private double radius;
    public Circle(final double radius)
    {
        this.radius = radius;
    }
    public double getArea()
    {
        return Math.PI * Math.pow(radius,2);
    }
}
/** 矩形 */
class Rectangle extends Shape
{
    /** 幅 */
    private double width;
    /** 高さ */
    private double height;
    public Rectangle(final double width, final double height)
    {
        this.width = width;
        this.height = height;
    }
    public double getArea()
    {
        return width * height;
    }
}

null
other
Large Circle
Rectangle

JDK

Java 17の新機能(1)

Java 17がリリースされました。今回リリースされたJava 17はLTS(Long Term Support)版です。主な変更点を紹介していきます。

JEP 306: 常時厳密性を維持する浮動小数点セマンティクス復活

浮動小数点数の計算でオーバーフロー等が起こる場合に,CPUによって計算結果が異なってしまう現象を避けるために,常にIEEEの規格に準拠した計算を行うようにするものである。この問題が発生するのは,SSE2命令セットをサポートしていないCPU(Pentium Ⅲ以前)のマシンということなので,影響を受ける環境は少ないと思われる。

JEP 356: 疑似乱数生成器の拡張

PRNGという新たな疑似乱数生成器を導入し,既存の乱数生成器も含めて統一的なインタフェースを提供する。java.util.random.RandomGeneratorというインタフェースが導入されている。さらにこれを継承したSplittableRandomGeneratorJumpableRandomGeneratorLeapableRandomGeneratorArbitrarilyJumpableRandomGeneratorStreamableGeneratorというインタフェースが提供されている。

JEP 382: 新macOSのレンダリングパイプライン

新しいmacOSのグラフィックAPIであるMetalに対応させたものである。

JEP 391: macOS/AArch64 Port

Appleがx64アーキテクチャからAArch64への移行を進めていることに対応して,AArch64へ対応するためのものである。

JEP 398: Applet API削除への非推奨

Java AppletのAPIが非推奨となりました。以下のクラス/インタフェースを使用するとコンパイラが警告を出すようになっている。

  • java.applet.Applet
  • java.applet.AppletStub
  • java.applet.AppletContext
  • java.applet.AudioClip
  • javax.swing.JApplet
  • java.beans.AppletInitializer

JEP 403: JDK内部のカプセル化を強化

--illegal-accessオプションによって可能であったJDK内部のAPIを利用することが不可能となっている。

JDK

OpenJDK 17をビルド

GitHubから間もなくリリースされるOpenJDK 17のソースコードをダウンロードして,ビルドしてみました。ビルド方法に書かれている通りに実行すればよいのですが,かなり多くのライブラリが必要なので,何度もconfigureをくり返すことになりました。

make
Building target 'default (exploded-image)' in configuration 'linux-x86_64-server-release'
Compiling 1 files for BUILD_TOOLS_HOTSPOT
Compiling 8 files for BUILD_TOOLS_LANGTOOLS
Parsing 2 properties into enum-like class for jdk.compiler
Compiling 13 properties into resource bundles for jdk.javadoc
Compiling 12 properties into resource bundles for jdk.jdeps
Creating hotspot/variant-server/tools/adlc/adlc from 13 file(s)
Compiling 7 properties into resource bundles for jdk.jshell
Compiling 16 properties into resource bundles for jdk.compiler
Compiling 2 files for BUILD_JVMTI_TOOLS
Compiling 127 files for BUILD_java.compiler.interim
Compiling 402 files for BUILD_jdk.compiler.interim
Compiling 229 files for BUILD_jdk.javadoc.interim
Creating support/modules_libs/java.base/server/libjvm.so from 1064 file(s)
Compiling 185 files for BUILD_TOOLS_JDK
Compiling 2 files for COMPILE_DEPEND
Compiling 11 properties into resource bundles for jdk.jartool
Compiling 71 files for COMPILE_CREATE_SYMBOLS
Compiling 11 properties into resource bundles for jdk.management.agent
Compiling 3 properties into resource bundles for jdk.jdi
Compiling 5 properties into resource bundles for jdk.jlink
Compiling 3 properties into resource bundles for jdk.jlink
Compiling 1 properties into resource bundles for jdk.jlink
Compiling 224 properties into resource bundles for jdk.localedata
Compiling 11 properties into resource bundles for java.base
Compiling 6 properties into resource bundles for java.base
Compiling 2 files for BUILD_BREAKITERATOR_BASE
Compiling 2 files for BUILD_BREAKITERATOR_LD
Compiling 11 properties into resource bundles for java.logging
Compiling 3071 files for java.base
Compiling 89 properties into resource bundles for java.desktop
Compiling 71 files for COMPILE_CREATE_SYMBOLS
Creating ct.sym classes
Compiling 127 files for java.compiler
Compiling 18 files for java.datatransfer
Compiling 1846 files for java.xml
Compiling 10 files for java.instrument
Compiling 35 files for java.logging
Compiling 330 files for java.management
Compiling 141 files for java.net.http
Compiling 15 files for java.scripting
Compiling 5 files for java.transaction.xa
Compiling 22 files for java.smartcardio
Compiling 272 files for java.xml.crypto
Compiling 61 files for jdk.internal.jvmstat
Compiling 120 files for jdk.charsets
Compiling 406 files for jdk.compiler
Compiling 35 files for jdk.crypto.ec
Compiling 68 files for jdk.dynalink
Compiling 3 files for jdk.internal.ed
Compiling 44 files for jdk.httpserver
Compiling 64 files for jdk.incubator.foreign
Compiling 50 files for jdk.incubator.vector
Compiling 100 files for jdk.internal.le
Compiling 51 files for jdk.internal.opt
Compiling 205 files for jdk.internal.vm.ci
Compiling 30 files for jdk.jartool
Compiling 229 files for jdk.javadoc
Compiling 24 files for jdk.management
Compiling 136 files for jdk.jdeps
Compiling 1 files for jdk.jdwp.agent
Compiling 240 files for jdk.jfr
Compiling 4 files for jdk.jsobject
Compiling 15 files for jdk.management.jfr
Compiling 1806 files for jdk.localedata
Compiling 9 files for jdk.net
Compiling 2 files for jdk.nio.mapmode
Compiling 11 files for jdk.random
Compiling 33 files for jdk.sctp
Compiling 9 files for jdk.unsupported
Compiling 94 files for jdk.xml.dom
Compiling 14 files for jdk.zipfs
Compiling 15 files for java.prefs
Compiling 30 files for java.security.sasl
Compiling 106 files for java.rmi
Compiling 77 files for java.sql
Compiling 15 files for jdk.attach
Compiling 75 files for jdk.crypto.cryptoki
Compiling 1 files for jdk.internal.vm.compiler
Compiling 1 files for jdk.internal.vm.compiler.management
Compiling 40 files for jdk.jcmd
Compiling 251 files for jdk.jdi
Compiling 84 files for jdk.jlink
Compiling 11 files for jdk.jstatd
Compiling 199 files for java.naming
Compiling 95 files for jdk.jshell
Compiling 2768 files for java.desktop
Compiling 16 files for jdk.naming.dns
Compiling 8 files for jdk.naming.rmi
Compiling 16 files for java.management.rmi
Compiling 220 files for java.security.jgss
Compiling 56 files for java.sql.rowset
Compiling 31 files for jdk.management.agent
Compiling 30 files for jdk.security.auth
Compiling 16 files for jdk.security.jgss
Compiling 1 files for java.se
Compiling 18 files for jdk.accessibility
Compiling 3 files for jdk.editpad
Compiling 956 files for jdk.hotspot.agent
Compiling 64 files for jdk.jconsole
Compiling 47 files for jdk.jpackage
Compiling 8 files for jdk.unsupported.desktop
Creating support/modules_libs/java.base/libverify.so from 1 file(s)
Creating support/modules_libs/java.base/libjava.so from 59 file(s)
Creating support/native/java.base/libfdlibm.a from 57 file(s)
Creating support/modules_libs/java.base/libzip.so from 5 file(s)
Creating support/modules_libs/java.base/libjimage.so from 6 file(s)
Creating support/modules_libs/java.base/libjli.so from 8 file(s)
Creating support/modules_libs/java.base/libnet.so from 21 file(s)
Creating support/modules_libs/java.base/libnio.so from 22 file(s)
Creating support/modules_libs/java.base/libjsig.so from 1 file(s)
Creating support/modules_libs/java.prefs/libprefs.so from 1 file(s)
Creating support/modules_libs/java.instrument/libinstrument.so from 12 file(s)
Creating support/modules_libs/java.management/libmanagement.so from 9 file(s)
Creating support/modules_libs/java.rmi/librmi.so from 1 file(s)
Creating support/modules_libs/java.desktop/libmlib_image.so from 50 file(s)
Creating support/modules_libs/java.desktop/libawt.so from 72 file(s)
Creating support/modules_libs/java.desktop/libawt_xawt.so from 51 file(s)
Creating support/modules_libs/java.desktop/liblcms.so from 27 file(s)
Creating support/modules_libs/java.desktop/libjavajpeg.so from 46 file(s)
Creating support/modules_libs/java.desktop/libawt_headless.so from 26 file(s)
Creating support/modules_libs/java.desktop/libfontmanager.so from 63 file(s)
Creating support/modules_libs/java.desktop/libjawt.so from 1 file(s)
Creating support/modules_libs/java.desktop/libsplashscreen.so from 67 file(s)
Creating support/modules_libs/java.desktop/libjsound.so from 18 file(s)
Creating support/modules_cmds/java.rmi/rmiregistry from 1 file(s)Creating support/modules_cmds/java.scripting/jrunscript from 1 file(s)

Creating support/modules_cmds/java.base/java from 1 file(s)
Creating support/modules_cmds/java.base/keytool from 1 file(s)
Creating support/modules_libs/java.base/jexec from 1 file(s)
Creating support/modules_libs/java.base/jspawnhelper from 1 file(s)
Creating support/modules_libs/java.security.jgss/libj2gss.so from 3 file(s)
Creating support/modules_libs/java.smartcardio/libj2pcsc.so from 2 file(s)
Creating support/modules_libs/jdk.attach/libattach.so from 1 file(s)
Creating support/modules_cmds/jdk.compiler/javac from 1 file(s)
Creating support/modules_cmds/jdk.compiler/serialver from 1 file(s)
Creating support/modules_libs/jdk.hotspot.agent/libsaproc.so from 10 file(s)
Creating support/modules_libs/jdk.crypto.cryptoki/libj2pkcs11.so from 14 file(s)
Creating support/modules_cmds/jdk.hotspot.agent/jhsdb from 1 file(s)
Creating support/modules_libs/jdk.incubator.foreign/libsyslookup.so from 1 file(s)
Creating support/modules_libs/jdk.incubator.vector/libsvml.so from 36 file(s)
Creating support/modules_cmds/jdk.jartool/jar from 1 file(s)
Creating support/modules_cmds/jdk.jartool/jarsigner from 1 file(s)
Creating support/modules_cmds/jdk.javadoc/javadoc from 1 file(s)
Creating support/modules_cmds/jdk.jcmd/jinfo from 1 file(s)
Creating support/modules_cmds/jdk.jcmd/jmap from 1 file(s)
Creating support/modules_cmds/jdk.jcmd/jps from 1 file(s)
Creating support/modules_cmds/jdk.jcmd/jstack from 1 file(s)
Creating support/modules_cmds/jdk.jcmd/jstat from 1 file(s)
Creating support/modules_cmds/jdk.jcmd/jcmd from 1 file(s)
Creating support/modules_libs/jdk.management.agent/libmanagement_agent.so from 1 file(s)
Creating support/modules_libs/jdk.management/libmanagement_ext.so from 8 file(s)
Creating support/modules_cmds/jdk.jconsole/jconsole from 1 file(s)
Creating support/modules_cmds/jdk.jdeps/javap from 1 file(s)
Creating support/modules_cmds/jdk.jdeps/jdeps from 1 file(s)
Creating support/modules_cmds/jdk.jdeps/jdeprscan from 1 file(s)
Creating support/modules_libs/jdk.jdwp.agent/libdt_socket.so from 2 file(s)
Creating support/modules_libs/jdk.jdwp.agent/libjdwp.so from 43 file(s)
Creating support/modules_cmds/jdk.jdi/jdb from 1 file(s)
Creating support/modules_cmds/jdk.jfr/jfr from 1 file(s)
Creating support/modules_cmds/jdk.jlink/jimage from 1 file(s)
Creating support/modules_cmds/jdk.jlink/jlink from 1 file(s)
Creating support/modules_cmds/jdk.jlink/jmod from 1 file(s)
Creating jdk/modules/jdk.jpackage/jdk/jpackage/internal/resources/jpackageapplauncher from 3 file(s)
Creating jdk/modules/jdk.jpackage/jdk/jpackage/internal/resources/libjpackageapplauncher.so from 17 file(s)
Creating support/modules_cmds/jdk.jpackage/jpackage from 1 file(s)
Creating support/modules_cmds/jdk.jshell/jshell from 1 file(s)
Creating support/modules_cmds/jdk.jstatd/jstatd from 1 file(s)
Creating support/modules_libs/jdk.net/libextnet.so from 1 file(s)
Creating support/modules_libs/jdk.sctp/libsctp.so from 2 file(s)
Creating support/modules_libs/jdk.security.auth/libjaas.so from 1 file(s)
Compiling 4 files for BUILD_JIGSAW_TOOLS
Optimizing the exploded image
Stopping sjavac server
Finished building target 'default (exploded-image)' in configuration 'linux-x86_64-server-release'

動作確認をすると,きちんとバージョン情報が表示されました。

# ./build/*/images/jdk/bin/java -version
openjdk version “17-internal” 2021-09-14
OpenJDK Runtime Environment (build 17-internal+0-adhoc.root.jdk17)
OpenJDK 64-Bit Server VM (build 17-internal+0-adhoc.root.jdk17, mixed mode, sharing)
JDK

Java 16新機能(4)

Stream APIにtoList()メソッドが実装され,StreamからListへの変換が容易に行えるようになりました。これまではStreamのcollectメソッドにCollectors.toList()を渡していました。今後はStreamオブジェクトに対して直接toList()メソッドを実行してList型に格納してくれるようになります。

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class StreamToList
{
	public static void main(String[] args)
	{
		IntStream stream = IntStream.range(1, 100);
		//List<Integer> list = stream.boxed().collect(Collectors.toList());
		List<Integer> list = stream.boxed().toList();
		for(int item : list)
		{
			System.out.printf("%d\t", item);
		}
		System.out.println("");
	}
}

警告:実験的なモジュールを使用しています: jdk.incubator.foreign
警告1個
WARNING: Using incubator modules: jdk.incubator.foreign
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

JDK

Java 16新機能(3)

Java 16からは値ベースのAPIクラス,つまり,プリミティブ型のラッパークラスであるInteger,Long, Float, Double, Booleanなどが非推奨となり,コンパイル時に警告が出されるようになりました。次のような非常に簡単なプログラムをコンパイルしてみると,この振る舞いを確認できます。

public class ValueBased
{
	public static void main(String[] args)
	{
		Integer i = new Integer(1);
		Double d = new Double("123.54");
	}
}

警告:実験的なモジュールを使用しています: jdk.incubator.foreign
ValueBased.java:5: 警告:[removal] IntegerのInteger(int)は推奨されておらず、削除用にマークされています
Integer i = new Integer(1);
^
ValueBased.java:6: 警告:[removal] DoubleのDouble(String)は推奨されておらず、削除用にマークされています
Double d = new Double(“123.54”);
^
警告3個

JDK

Java 16新機能(2)

Java 16では,JDK内部の隠蔽が強化されています。例えば,enumクラスのprotectedメソッドclone()をリフレクションを使って呼び出してみましょう。このメソッドの実装は単にCloneNotSupportedExceptionをスローするだけのものになっています。次のようなプログラムを書いて,JDK11とJDK16での挙動の違いを比較してみます。

JDK11で実行した場合は,CloneNotSupportedExceptionがスローされており,protectedメソッドであるclone()がリフレクションによって実行できていることがわかります。しかし,JDK 16で実行した場合はsetAccessible()メソッドを呼び出した段階で,InaccessibleObjectExceptionがスローされています。そのため,invokeメソッドによってclone()メソッドを呼び出すことができていないことがわかります。

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class StronglyEncapsulate
{
	enum EnumExample { A, B, C; }
	public static void main(final String[] args) throws Throwable
	{
		try
		{
			Method method = Enum.class.getDeclaredMethod("clone");
			method.setAccessible(true);
			String result = (String)method.invoke(EnumExample.A);
			System.out.println(result);
		}
		catch(InvocationTargetException e)
		{
			throw e.getCause();
		}
	}
}

JDK 11での実行結果

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by StronglyEncapsulate to method java.lang.Enum.clone()
WARNING: Please consider reporting this to the maintainers of StronglyEncapsulate
WARNING: Use –illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Exception in thread “main” java.lang.CloneNotSupportedException
at java.base/java.lang.Enum.clone(Enum.java:165)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at StronglyEncapsulate.main(StronglyEncapsulate.java:12)

JDK 16での実行結果

警告:実験的なモジュールを使用しています: jdk.incubator.foreign
警告1個
WARNING: Using incubator modules: jdk.incubator.foreign
Exception in thread “main” java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Object java.lang.Enum.clone() throws java.lang.CloneNotSupportedException accessible: module java.base does not “opens java.lang” to unnamed module @13221655
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
at StronglyEncapsulate.main(StronglyEncapsulate.java:11)