プロジェクト

全般

プロフィール

高徹Java読書会BOFの宿題

高橋 徹 さんが約1ヶ月前に追加

Java読書会BOF主催のJava読書会での宿題への取り組み


返答 (1)

高徹 Javaコードアンチパターン 第4回宿題 - 高橋 徹 さんが約1ヶ月前に追加

List.copyOf() の実装内容はどうなっている?

nullが要素に含まれるListに対してcopyOfメソッドを呼ぶとエラーとなるほか、一度copyOfで取得したオブジェクトにcopyOfを呼び出すと再度はコピーしないとなっています。

OpenJDK 25の src.zip を調査対象としました。

  • List#copyOf は次のとおり、ImmutableCollections.listCopyに委譲
    return ImmutableCollections.listCopy(coll);
  • ImmutableCollections#listCopy は次のとおり、少し謎解きが必要なコードです。
        if (coll instanceof List12 || (coll instanceof ListN<?> c && !c.allowNulls)) {
                return (List<E>)coll;
            } else if (coll.isEmpty()) { // implicit nullcheck of coll
                return List.of();
            } else {
                return (List<E>)List.of(coll.toArray());
            }
    
まず、初回のcopyOfについては、List.of(coll.toArray()); を呼んでいます。copyOfで渡したListを配列に変換して呼び出しています。初回のcopyOfで、List12またはListN型のインスタンスが生成されるので(後述)、2回目以降はコピーせず同じインスタンスを返しています。
  • List#of(E... elements)
            switch (elements.length) { // implicit null check of elements
                case 0:
                    @SuppressWarnings("unchecked")
                    var list = (List<E>) ImmutableCollections.EMPTY_LIST;
                    return list;
                case 1:
                    return new ImmutableCollections.List12<>(elements[0]);
                case 2:
                    return new ImmutableCollections.List12<>(elements[0], elements[1]);
                default:
                    return ImmutableCollections.listFromArray(elements);
            }
    
引数の要素数に応じた最適化コードとなっており、ImmutableCollectionsのネストクラスである、List12またはListN型のインスタンスを生成しています。
要素数 生成するインスタンスの型
0 ListN
1 または 2 List12
3以上 ListN
  • List12
    要素を1つ、または2つ保持するリストで、要素を Objects.requireNonNull で検査しています。
  • ListN
    ImmutableCollections#listFromArray()メソッドで ListNを生成します。要素をそれぞれ Objects.requireNonNull で検査して詰めています。
           E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
            for (int i = 0; i < input.length; i++) {
                tmp[i] = Objects.requireNonNull(input[i]);
            }
    
IntelliJ IDEAでnull許容性アノテーションを自動的に推測

インターネット非接続で上述の表示ができました(WiFiをオフしてIntelliJ IDEA再起動しての表示)。

無限再帰発生時のStackOverflowErrorのスタックトレースの内容

実行すると次のようにStackOverflowErrorのスタックトレースが表示されるので
無限再帰と分かります。

Exception in thread "main" java.lang.StackOverflowError
    at ch5.ButtonWrapper.onPressed(ButtonWrapper.java:22)
    at ch5.ButtonWrapper.onPressed(ButtonWrapper.java:22)
    at ch5.ButtonWrapper.onPressed(ButtonWrapper.java:22)
    at ch5.ButtonWrapper.onPressed(ButtonWrapper.java:22)
        :
        (1000行ほど続く)
Character.isDigit()の仕様は?

Character.isDigit のJavadoc API記述では、

getType(codePoint)により示される汎用カテゴリ型がDECIMAL_DIGIT_NUMBERの場合、文字は数字になります。

とあります。DECIMAL_DIGIT_NUMBER の説明では

Unicode仕様の汎用カテゴリ「Nd」。

とあります。

OpenJDK 25(Java SE 25)は、Unicode 16.0.0をサポートしています。
Unicode 16.0.0において、文字の種類(Nd:Decimal Digit Number)について触れている文書
https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-4/

各文字のプロパティは、次のデータ(Unicode Character Database)に記載されています。
https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt

ここで、Ndとなっている文字が対象となります。2026-06-20時点のUnicodeData.txtでは770文字が該当します。

    (1-1/1)