nullの10億ドルの過ちから未来へ Spring Boot 4とJSpecifyが描くnull安全設計

1.4K Views

November 15, 25

スライド概要

2025年11月15日開催のJJUG CCC 2025 Fallで使用した資料です

profile-image

ウェルスナビ株式会社 技術広報チームの公式アカウントです。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

nullの10億ドルの過ちから未来へ Spring Boot 4とJSpecifyが描くnull安全設計 2025.11.15 尾形 涼介 藤原 将貴 JJUG CCC 2025 FALL

2.

⾃⼰紹介 尾形 涼介 (Ogata Ryosuke) ウェルスナビ株式会社 ロボアド開発グループ サービス機能開発チーム ウェルスナビでは ● 2024年ウェルスナビ株式会社に新卒として⼊社 ● サービスサイト‧APIの開発に従事 やっちまった ひとこと ● 名前も⾎液型もO型です 2 @2025 WealthNavi Inc.

3.

⾃⼰紹介 藤原 将貴 (Fujiwara Masataka) ウェルスナビ株式会社 ロボアド開発グループ サービス機能開発チーム ウェルスナビでは ● アプリのREST APIの開発 ● 最近はフロントの開発もしてます(Thymeleaf) ひとこと ● java8からいち早く脱却したい 3 @2025 WealthNavi Inc.

4.

アジェンダ 社内で進むSpring Bootアップデートと新たなnull安全性 Javaとnullの歴史:設計思想と進化の軌跡 JSpecifyの概要および使い⽅ NullAwayの概要および使い⽅ 導⼊すべきか、⾒送るべきか © WealthNavi Inc. All Rights Reserved. 4

5.

プロダクト紹介 全⾃動の資産運⽤サービス ウェルスナビ 「⻑期‧積⽴‧分散」でリターンの最⼤化をめざす 1万円から運⽤できる 全⾃動でおまかせできる リスクを抑えて運⽤できる NISAも⾃動で活⽤できる ※画面はイメージです © WealthNavi Inc. All Rights Reserved. 5

6.

1 社内で進むSpring Bootアップデートと 新たなnull安全性 © WealthNavi Inc. All Rights Reserved. 6

7.

社内で進むSpring Bootアップデート ロボアドのシステムは、Spring Bootのバージョンが3系以前のものが多くあります。 そのため社内でSpring Bootのアップグレードに関する議論が持ち上がり 3系、4系で導⼊に向けての調査を⾏いました。 7 @2025 WealthNavi Inc.

8.

JSpecify導⼊により変わるnull安全性 その中で、Spring Boot 4.0.0-M2の公式ブログでは、JSpecify準拠のnull安全アノテーションが コードベースに導⼊されたことが発表された。 そこで導⼊調査の結果から分かったJSpecifyの仕様と これまでのnullの歴史を振り返りながら、新たなnull安全性を紹介していく。 https://spring.io/blog/2025/03/10/null-safety-in-spring-apps-with-jspecify-and-null-away 8 @2025 WealthNavi Inc.

9.

2 1 Javaとnullの歴史:設計思想と進化の軌跡 © WealthNavi Inc. All Rights Reserved. 9

10.

アイスブレイク nullで痛い⽬を⾒たことがある⼈、いますか? 🙋 10 @2025 WealthNavi Inc.

11.

冗談ですが、我々は同志です いたら、裏で⼩⼀時間お話しましょう 11 @2025 WealthNavi Inc.

12.

Javaとnullの歴史年表 トニー‧ホーア⽒がnull参照を 導⼊。後に「10億ドルの過ち」 と発⾔する 1965 nullableアノテーションが乱⽴ (javax, JetBrains, Springなど) 1995 Java 1.0リリース。 nullが標準リテラルとして 登場 2000年代 Kotlinの台頭 「Helpful NullPointerExceptions」が導⼊ 2014 2017〜2020 2021~現在 Java 8以降でOptionalが導⼊ 12 JSpecifyプロジェクト始動。 null安全の標準化へ @2025 WealthNavi Inc.

13.

Javaとnullの歴史年表 トニー‧ホーア⽒がnull参照を 導⼊。後に「10億ドルの過ち」 と発⾔する 1965 nullableアノテーションが乱⽴ (javax, JetBrains, Springなど) 1995 Java 1.0リリース。 nullが標準リテラルとして 登場 2000年代 Kotlinの台頭 「Helpful NullPointerExceptions」が導⼊ 2014 2017〜2020 2021~現在 Java 8以降でOptionalが導⼊ 13 JSpecifyプロジェクト始動。 null安全の標準化へ @2025 WealthNavi Inc.

14.

1965年 トニー‧ホーア⽒がnull参照を導⼊ この時代の⾔語設計では、 変数に「まだ値が設定されていない」ことを⽰す仕組みがなかった イギリスのコンピュータ科学者 トニー‧ホーア⽒ によってALGOL Wの設計で 参照型に「何も指していない」状態を表すための簡単な⽅法としてnullを導⼊ ALGOL Wとは 教科書や学術論⽂などでアルゴリズム記述のデファクトスタンダード として30年以上使われた⾔語 14 @2025 WealthNavi Inc.

15.

これが”奴”の到来へ しかしこの判断が、後に⼤きな問題を引き起こす.... (・∀・) | | ガッ と ) | | Y /ノ 人 / ) < >__Λ∩ _/し' //. V`Д´)/ ←>>1 (_フ彡 / 15 @2025 WealthNavi Inc.

16.

奴の名はNullPointerException (ヌルポ)、それが10億ドルの過ちへ nullが世界中で、NullPointerException (ヌルポ)として膨⼤なバグやクラッ シュを引き起こす 後にトニー・ホーア⽒は 「私は誘惑に負けてnull参照を導⼊した。それは私の10億ドルの過ちだった」 と発⾔ https://qconlondon.com/london-2009/qconlondon.com/london-2009/presentation/Null%2bReferences_%2bThe%2bBillion%2bDollar%2bMistake.html 16 @2025 WealthNavi Inc.

17.

Javaとnullの歴史年表 トニー‧ホーア⽒がnull参照を 導⼊。後に「10億ドルの過ち」 と発⾔する 1965 nullableアノテーションが乱⽴ (javax, JetBrains, Springなど) 1995 Java 1.0リリース。 nullが標準リテラルとして 登場 2000年代 Kotlinの台頭 「Helpful NullPointerExceptions」が導⼊ 2014 2017〜2020 2021~現在 Java 8以降でOptionalが導⼊ 17 JSpecifyプロジェクト始動。 null安全の標準化へ @2025 WealthNavi Inc.

18.

1995年 Javaが世界に登場。だが、“null”という影も連れてきた… 1995年にJava 1.0 がリリースで、この時点からnull が導⼊される 「何も参照していない状態」を表す特別な値として利⽤される 特徴 ● 全ての参照型には必ずnullが代⼊可能な設計 ● プリミティブ型には null を代⼊できない ● null を参照するとヌルポ が発⽣ 18 @2025 WealthNavi Inc.

19.

Javaにおけるnullの課題① 型システムでnullを区別できない ● ● ● Javaでは、すべての参照型にnullが代⼊可能という⾔語仕様になっている このため、型レベルで「nullableかどうか」を表現できない 結果として、静的解析ではnullの有無を判定できない String name = getName(); // 外部依存 if (flag) { name = null; // 条件分岐でnullになる可能性 } System.out.println(name.length()); // 実行時にヌルポの可能性 静的解析は通るが、実⾏時にエラーが起きる 19 @2025 WealthNavi Inc.

20.

Javaにおけるnullの課題② Javaのnull設計における曖昧さ ● ● nullを許容するかどうかが明⽰されないため、設計書やコードコメントで補⾜する必要 がある チーム内で「この引数はnullを渡していいのか?」「戻り値がnullになる可能性はある か?」という議論が発⽣ public String getDisplayName(User user) { if (user == null || user.getName() == null) { return "Unknown"; } return user.getName(); } 防御的コードが⼤量に必要になることで、可読性や保守性が低下 20 @2025 WealthNavi Inc.

21.

Javaとnullの歴史年表 トニー‧ホーア⽒がnull参照を 導⼊。後に「10億ドルの過ち」 と発⾔する 1965 nullableアノテーションが乱⽴ (javax, JetBrains, Springなど) 1995 Java 1.0リリース。 nullが標準リテラルとして 登場 2000年代 Kotlinの台頭 「Helpful NullPointerExceptions」が導⼊ 2014 2017〜2020 2021~現在 Java 8以降でOptionalが導⼊ 21 JSpecifyプロジェクト始動。 null安全の標準化へ @2025 WealthNavi Inc.

22.

2000年代 null安全アノテーションの乱⽴ FindBugsやIntelliJ IDEAなどで静的解析をするため それぞれ独⾃の@Nullableや@Nonnullアノテーションを定義 それらは、⾃分たちの解析に最適なアノテーションを作った 互換性がなくライブラリ間で混乱を招いていた [stackoverflowから翻訳して引⽤] JSR 305 または Jetbrains の IntelliJ 向け独⾃アノテーションで実現可能になったコー ド検査機能は本当に気に⼊っています。残念ながら、両実装(JSR 305 と Jetbrains のもの)は互いにうまく混在しません https://stackoverflow.com/questions/4468599/nullable-notnull-with-intellij-idea-maven-jsr-305 22 @2025 WealthNavi Inc.

23.

null安全アノテーション表 Null関連アノテーション 定義元 主な利用シーン @Nullable, @NotNull JetBrains IntelliJ IDEAでの補完・警告 @Nullable Spring Framework Spring内部で使用 @Nullable, @NonNull FindBugs / SpotBugs 静的解析ツール向け。FindBugs系で使われる @Nullable, @NonNull Checker Framework 高度な型チェックが可能。学術寄り @NonNull Lombok コンストラクタやメソッド引数のnullチェックを自動 生成 23 @2025 WealthNavi Inc.

24.

乱⽴により開発現場での混乱 ● 同じ名前でも別物 ○ Spring FrameworkとJetBrainsの@Nullable、同じ名前だが別物 ● IDEで警告が出ない、補完されない ○ JetBrains系アノテーションはIntelliJで補完。しかしSpring Framework系は補完 されない ○ @Nullableを付けても、IDEがnullチェックをしてくれない → 意味がない ● チーム内で「どのアノテーションを使うべきか?」という議論が発⽣ ○ さらに、プロジェクトごとに使われているアノテーションが違うと統⼀が困難に null安全性の向上を目指したはずが、逆に混乱を招いた 24 @2025 WealthNavi Inc.

25.

JSR-305がJava標準のnull安全アノテーション導⼊へ そこで2006年にGoogleが提案したJSR-305が動き出す IDEや静的解析ツール(IntelliJ, SpotBugsなど)が、統⼀されたアノテーションを 使ってnullの有無を正確に解析できるようになること ついにJavaは新たなnull安全の時代へ 25 @2025 WealthNavi Inc.

26.

とはならず.... 休止 26 @2025 WealthNavi Inc.

27.

JSR-305は採⽤されず、null安全アノテーションの乱⽴のまま... JSR-305はコミュニティ内で議論が停滞し、休⽌してしまった 結局正式なJava標準として採⽤されなかった null安全アノテーションは、乱⽴したままになってしまう 27 @2025 WealthNavi Inc.

28.

Javaとnullの歴史年表 トニー‧ホーア⽒がnull参照を 導⼊。後に「10億ドルの過ち」 と発⾔する 1965 nullableアノテーションが乱⽴ (javax, JetBrains, Springなど) 1995 Java 1.0リリース。 nullが標準リテラルとして 登場 2000年代 Kotlinの台頭 「Helpful NullPointerExceptions」が導⼊ 2014 2017〜2020 2021~現在 Java 8以降でOptionalが導⼊ 28 JSpecifyプロジェクト始動。 null安全の標準化へ @2025 WealthNavi Inc.

29.

2014年 Java 8でOptional導⼊ JSR-305のようなアノテーションベースのnull安全がうまくいかなかった Java 8で⾔語レベルでnullを扱う新しい⽅法として Optional が導⼊ 29 @2025 WealthNavi Inc.

30.

Optionalとは何か? ● ● ● Java 8で導⼊されたnull安全のための型 nullの有無を型で表現することで、明⽰的な設計が可能に Optionalは「値があるかもしれない」を型で⽰す Optional<String> getName(); // nullの可能性を型で表現 30 @2025 WealthNavi Inc.

31.

Optionalのメリット ● メリット ○ コードの意図が明確になる:nullになる可能性を型で表現 ○ ヌルポのリスクが低減する:値の存在確認が強制される ○ メソッドチェーンによる簡潔な記述が可能:複雑な条件分岐を減らせる Optional.ofNullable(name) .map(String::length) .orElse(0); 31 @2025 WealthNavi Inc.

32.

Optionalの限界と注意点① Optional ⾃体が null になり得る Optionalはラッパーであるため、 Optionalインスタンス⾃体にnullを代⼊することが可能 Optional<User> userOpt = null; // コンパイルエラーにはならない Optionalで包んだからといってnullの危険性が完全に排除されるわけではない Javaの型システムはOptionalを「null安全な型」として扱っていない 32 @2025 WealthNavi Inc.

33.

Optionalの限界と注意点② パフォーマンス‧互換性 Optionalのパフォーマンスオーバーヘッド ● ● ● Optionalはラッパーなので、値を扱うたびにオブジェクトを⽣成 短命なOptionalを⼤量⽣成 → GC(ガベージコレクション)負荷が増える 設計上は「戻り値だけ」に限定して使うのが安全 Kotlinや型安全機構との⾮互換 ● ● Kotlinのnull安全型(String?)とは別概念 JavaのOptionalはラッパーでしかなく、Kotlinの型推論に反映されない 33 @2025 WealthNavi Inc.

34.

Javaとnullの歴史年表 トニー‧ホーア⽒がnull参照を 導⼊。後に「10億ドルの過ち」 と発⾔する 1965 nullableアノテーションが乱⽴ (javax, JetBrains, Springなど) 1995 Java 1.0リリース。 nullが標準リテラルとして 登場 2000年代 Kotlinの台頭 「Helpful NullPointerExceptions」が導⼊ 2014 2017〜2020 2021~現在 Java 8以降でOptionalが導⼊ 34 JSpecifyプロジェクト始動。 null安全の標準化へ @2025 WealthNavi Inc.

35.

2019年 Kotlinの台頭 この時期からKotlinが⾔語仕様でnull安全が担保されている⾔語として台頭 特徴 ● ● ● JetBrainsによって開発された静的型付けのプログラミング⾔語 Javaとの⾼い互換性を持ち、⾔語仕様でnull安全が担保されている Androidアプリ開発とバックエンド開発の両⽅で⽤いられる 35 @2025 WealthNavi Inc.

36.

Kotlin台頭の流れ ● 2011年:開発開始 ● 2016年:Kotlin 1.0正式リリース ● 2017年:GoogleがKotlinをAndroid開発の公式⾔語として採⽤ ● 2018年〜2020年:Spring FrameworkがKotlinをサポート ● 2020年~現在:バックエンドでも企業採⽤が加速 36 @2025 WealthNavi Inc.

37.

Kotlinのnull安全性① 型システムでnull許容を明⽰ 型 説明 String nullを許容しない型(non-null型) → null を代⼊するとコンパイルエラー String? nullを許容する型(nullable型) → null を代⼊可能 val nickname: String = null // ❌ 代入不可 val nickname: String? = null // OK 代入可能 nullが代⼊される可能性を型で表現することで、設計段階から安全性を確保 37 @2025 WealthNavi Inc.

38.

Kotlinのnull安全性② コンパイル時にnull安全を保証 Kotlinでは、nullable型に対して安全でないアクセスをすると静的解析でエラー Javaとの⼤きな違いであり、Kotlinのnull安全性の⼀番の要因 var name: String? = getName() if (flag) { name = null } println(name.length) // ❌ コンパイルエラー Javaでは実⾏時にエラーになるが、Kotlinでは事前に防げる 38 @2025 WealthNavi Inc.

39.

Kotlinのnull安全性③ null安全オペレーターで安全にアクセス nullable型(例:String?)の変数にそのままアクセスすると、 ヌルポのリスク 安全にアクセスするための構⽂が、null安全オペレーター オペレーター 役割 使⽤例 説明 ?.(安全呼び出し) nullでなければアクセス user?.name userがnullならnullを返す ?:(エルビス演算⼦) null時のデフォルト値 user?.name ?: "ゲスト" user?.nameがnullなら "ゲスト" を返す !!(⾮nullアサーション) nullでないと断⾔ user!!.name userがnullなら例外発⽣(⾮推奨) 39 @2025 WealthNavi Inc.

40.

Kotlinにおけるnull安全設計 「nullableかどうかは型で明示。迷いなし」 「nullチェックはコンパイラが自動で指摘」 「null安全オペレーターで、nullでも落ち着いて処理」 「Optional?不要。言語がすでにnull安全」 40 @2025 WealthNavi Inc.

41.

Javaにおけるnull安全設計 「nullが来るかもしれない?とりあえずif (obj != null)で囲め! 囲め!」 「例外? そんなもんtry-catchで受け⽌めろ!」 「Optional? 使い⽅は... まぁ、なんとかなんだろ!」 「アノテーション?プロジェクトごとにバラバラだけど、気合で統⼀感出せ!」 「レビューで『nullチェック漏れてるよ』って⾔われたら、⼼で泣いてコードで耐える!」 Kotlinは後発⾔語としてnull安全を型システムに組み込めた Javaは互換性やエコシステムの広さを重視して進化してきた役割の違いが、この設計に影響した 41 @2025 WealthNavi Inc.

42.

JavaとKotlinのnull設計思想の対⽐ 観点 Java Kotlin null許容性 型に含まれない 型で明⽰される nullチェック ⼿動で書く コンパイルで強制される 安全性 実⾏時にヌルポが起きる コンパイル時に防げる 設計の明⽰性 弱い(Javadoc頼り) 強い(型で表現) 42 @2025 WealthNavi Inc.

43.

2020年 Java 14でヌルポメッセージ改善 Java 14では、JEP 358として提案された「Helpful NullPointerExceptions」が導⼊ ヌルポ発⽣時のエラーメッセージが、分かりやすくなったという改善です [OpenJDK公式から翻訳して引⽤] どの変数が null であったかを正確に記述することにより、JVM によって⽣成され た NullPointerExceptions の使いやすさを向上します https://openjdk.org/jeps/358 43 @2025 WealthNavi Inc.

44.

従来のNullPointerExceptionのスタックトレース Java 13以前 String name = null; System.out.println(name.length()); Exception in thread "main" java.lang.NullPointerException スタックトレースだけだと具体的に何がnullなのかわからない 44 @2025 WealthNavi Inc.

45.

Helpful NullPointerExceptions導⼊後 Java 14以降 以下のオプションを指定することで有効になる -XX:+ShowCodeDetailsInExceptionMessages String name = null; System.out.println(name.length()); Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null nullだった具体的な式や変数名が表⽰されるため、デバッグ効率が⼤幅に向上 45 @2025 WealthNavi Inc.

46.

Javaとnullの歴史年表 トニー‧ホーア⽒がnull参照を 導⼊。後に「10億ドルの過ち」 と発⾔する 1965 nullableアノテーションが乱⽴ (javax, JetBrains, Springなど) 1995 Java 1.0リリース。 nullが標準リテラルとして 登場 2000年代 Kotlinの台頭 「Helpful NullPointerExceptions」が導⼊ 2014 2017〜2020 2021~現在 Java 8以降でOptionalが導⼊ 46 JSpecifyプロジェクト始動。 null安全の標準化へ @2025 WealthNavi Inc.

47.

2021年〜現在 JSpecifyプロジェクト始動 トニー‧ホーア⽒によるnullの導⼊から始まり、JSR-305の停滞、アノテーションの乱⽴など ⾔語仕様としてのnull安全性には⼀貫性を⽋いていた こうした背景から本格的なnull安全の標準化に向けて動き出す それが、Googleを中⼼に始動した JSpecifyプロジェクト 47 @2025 WealthNavi Inc.

48.

3 1 JSpecifyの概要と使い⽅ © WealthNavi Inc. All Rights Reserved. 48

49.

JSpecifyとは null関連アノテーションのライブラリ Google社が⽴ち上げたプロジェクト JSpecifyはこれまで乱雑していたnullに関係するライブラリや静的解析ツールなどのプロ ジェクトと合意形成を取ることでnull関連のアノテーションを統⼀することを⽬標 として掲げている Spring Boot4.0.0で採⽤ Spring Boot3系時点では Spring独⾃のアノテーション(@NonNull,@Nullableなど)を⽤いているが Spring Boot 4.0.0では、JSpecifyを代わりに使うようになっている 49 @2025 WealthNavi Inc.

50.

JSpecifyプロジェクトを⽀える組織 組織 プロジェクト Broadcom Spring Google Android, Error Prone, Guava JetBrains Kotlin, Intellij IDEA Meta Infer MicroSoft Azure SDK for Java Oracle OpenJDK PMD Team PMD Sonar SonarQube, SonarCloud, SonarLint Uber NullAway EISOP Team EISOP 50 @2025 WealthNavi Inc.

51.

JSpecify導⼊のメリット‧デメリット メリット ● ヌルポ発⽣率を極限まで減らす ● null安全チェックの静的解析が簡単にできる(NullAway) ● Kotlinとのシームレスな連携(相互運⽤性) ○ KotlinからJavaコードを呼び出す時に、戻り値がnull許容/⾮許容か解析 ○ JavaからKotlinへの変換時、@Nullableが付いた型はnull許容型(?)へ変換される デメリット ● 学習コストおよび「習慣化」の壁 51 @2025 WealthNavi Inc.

52.

JSpecify:類似ライブラリとの違い JSpecifyの@Nullable jakarta.annotationの@Nullable 52 @2025 WealthNavi Inc.

53.

JSpecify:類似ライブラリとの違い @Target(TYPE_USE)によって型が使われてる箇所なら、基本的にどこでも使えるようになった 例えばジェネリクス、インナークラス、配列⾃⾝(変数の型)へのアノテーション付与は jakarta.annotationではエラーになるが、JSpecifyでは問題なく使えるようになっている JSpecifyの@Nullableではエラーに ならない jakarta.annotationの@Nullableではエラー 53 @2025 WealthNavi Inc.

54.

JSpecify:導⼊⽅法 Gradle dependencies { api("org.jspecify:jspecify:1.0.0") } ※ Spring Boot 4.0.0ではデフォルトで⼊っているので、依存関係書かなくてもOK! Java互換性 Java8以上が必要 54 @2025 WealthNavi Inc.

55.

アノテーション解説 © WealthNavi Inc. All Rights Reserved. 55

56.

アノテーション解説:@Nullable 型がnull許容であることを⽰す時に使う 使⽤できる箇所はフィールド、戻り値、引数、ジェネリクスなど。クラス⾃体には使⽤できない 56 @2025 WealthNavi Inc.

57.

アノテーション解説:@NonNull 型がnull⾮許容であることを⽰す時に使う 使⽤できる箇所はフィールド、戻り値、引数、ジェネリクスなど。クラス⾃体には使⽤できない 基本的に使わない なぜなら‧‧‧次のスライドで話す@NullMarkedで@NonNullを網羅できるため 57 @2025 WealthNavi Inc.

58.

アノテーション解説:@NullMarked nullが出ない箇所に⼀々、@NonNullをつけるのは⾯倒 そこで活躍するのが@NullMarked @NullMarkedをpackage-info.javaに付けるとパッケージ内のクラスを⼀括で nonNull 扱いにできる ただし、@Nullableが付与されている箇所は上書きされず、サブパッケージには適⽤されない 58 @2025 WealthNavi Inc.

60.

アノテーション解説:@NullUnmarked ロジックを持たないクラス(エンティティやモデルなど)によってはnull安全チェックの対象にしたくな い そこで活躍するのが@NullUnmarked @NullUnmarkedが付与されたメソッド、クラス、パッケージではnull安全チェックの対象外となる メソッドに宣言 パッケージに宣言 (package-info.java) クラスに宣言 60 @2025 WealthNavi Inc.

61.

アノテーション解説:@NullUnmarked メソッドに宣⾔ 61 @2025 WealthNavi Inc.

62.

アノテーション解説:@NullUnmarked メソッドに宣⾔ クラスに宣⾔ 62 @2025 WealthNavi Inc.

63.

アノテーション解説:@NullUnmarked パッケージに宣言 (package-info.java) 63 @2025 WealthNavi Inc.

64.

Tips © WealthNavi Inc. All Rights Reserved. 64

65.

JSpecifyのTips:IntelliJ IDEAのリアルタイムコード解析 IntelliJ IDEAを使うと静的解析をしなくても、リアルタイムでJSpecifyの警告を出してくれる しかし、2025年11⽉時点ではNullAwayによる静的解析結果と異なる警告もあるので注意が必要 (おそらくNullAwayの解析結果の⽅が正しい) 65 @2025 WealthNavi Inc.

66.

JSpecifyのTips:プリミティブ型には使えない プリミティブ型にはnullを代⼊できないため、アノテーションを付与することもできない 66 @2025 WealthNavi Inc.

67.

JSpecifyのTips:配列型での使い⽅ 配列の要素に対してnullableを適⽤したい場合はString[]の前に@Nullableをつける @Nullable String[] example 配列⾃⾝にnullableを適⽤したい場合はStringと[]の間に@Nullableをつける String @Nullable [] example 67 @2025 WealthNavi Inc.

68.

JSpecifyのTips:FQCNで記載された型での使い⽅ ❌ public @Nullable com.wealthnavi.SampleClass method() {... パッケージ名と型名の間に付けるのが正しい ⭕ public com.wealthnavi.@Nullable SampleClass method() {... 68 @2025 WealthNavi Inc.

69.

実践編クイズ © WealthNavi Inc. All Rights Reserved. 69

70.

クイズの「前提ルール」 JSpecifyのNonNullがデフォルトと⾔う考え⽅に慣れてもらうために、 パッケージ全体に @NullMarked が適⽤されていることをクイズの前提とします private String func(List<String> list) { return list.getFirst(); } @NullMarkedの下では、暗黙的に@NonNull が適⽤される private @NonNull String func(@NonNull List<@NonNull String> list) { return list.getFirst(); } 70 @2025 WealthNavi Inc.

71.

JSpecifyのTips:オーバライドメソッドにおける使い⽅① public class SuperClass { public String method() {... public class SubClass extends SuperClass { @Override public @Nullable String method() {... 71 @2025 WealthNavi Inc.

72.

JSpecifyのTips:オーバライドメソッドにおける使い⽅① public class SuperClass { public String method() {... public class SubClass extends SuperClass { @Override public @Nullable String method() {... スーパークラスのメソッドの戻り値が@NonNullの時、サブクラスのオーバーライドメ ソッドの戻り値には@Nullableをつけることはできない 理由 スーパークラスのメソッドにはnullが返ってこないと契約しているのに対し、 サブクラスではnullを返してしまい、契約違反となる(リスコフの置換原則) 72 @2025 WealthNavi Inc.

73.

JSpecifyのTips:オーバライドメソッドにおける使い⽅① public class SuperClass { public @Nullable String method() {... public class SubClass extends SuperClass { @Override public @Nullable String method() {... public class SubClass extends SuperClass { @Override public String method() {.... どっちでも OK サブクラスのオーバーライドメソッドの戻り値に@Nullableを付けたい場合、スーパー クラスのメソッドの戻り値に@Nullableを付ける必要がある 73 @2025 WealthNavi Inc.

74.

JSpecifyのTips:オーバライドメソッドにおける使い⽅② public class SuperClass { public String method(@Nullable Object obj) {... public class SubClass extends SuperClass { @Override public String method(Object obj) {... 74 @2025 WealthNavi Inc.

75.

JSpecifyのTips:オーバライドメソッドにおける使い⽅② public class SuperClass { public String method(@Nullable Object obj) {... public class SubClass extends SuperClass { @Override public String method(@Nullable Object obj) {... スーパークラスのメソッドの引数がNullableの時、サブクラスのオーバーライドメソッ ドの引数にも@Nullableをつけないといけない 理由 スーパークラスのメソッド引数にはnullを許容すると契約しているのに対し、 サブクラスではnullを許容しないため、契約違反となる 75 @2025 WealthNavi Inc.

76.

JSpecifyのTips:オーバライドメソッドにおける使い⽅② public class SuperClass { public String method(Object obj) {... public class SubClass extends SuperClass { @Override public String method(@Nullable Object obj) {... public class SubClass extends SuperClass { @Override public String method(Object obj) {... どっちでも OK スーパクラスのメソッドの引数がNonNullなら、 サブクラスでのメソッドの引数はNullableでもNonNullでも良い 76 @2025 WealthNavi Inc.

77.

JSpecifyのTips:ジェネリクス型での使い⽅ 以下のクラスを使うケースを考えてみてください 使い⽅が正しいケース public class NumberList<E extends Number> implements List<E> NumberList<Integer> numberList = new NumberList<>(); {...} 77 @2025 WealthNavi Inc.

78.

JSpecifyのTips:ジェネリクス型での使い⽅ A NumberList<@Nullable Integer> numberList = new NumberList<>(); B NumberList<Integer> numberList = new NumberList<>(); 78 @2025 WealthNavi Inc.

79.

JSpecifyのTips:ジェネリクス型での使い⽅ B NumberList<Integer> numberList = new NumberList<>(); 79 @2025 WealthNavi Inc.

80.

JSpecifyのTips:ジェネリクス型での使い⽅ 正解はB NumberList<Integer> numberList = new NumberList<>(); Aは間違い NumberList<@Nullable Integer> numberList = new NumberList<>(); 解説 型となっているNumberListのジェネリクス、E extends Numberは@NullMarkedが 付与されているため、@NonNull E extends Numberとみなされる よって、NumberListをインスタンス化する時は、ジェネリクスに@Nullableを付与 することができない 80 @2025 WealthNavi Inc.

81.

1 4 NullAwayの概要および使い⽅ © WealthNavi Inc. All Rights Reserved. 81

82.

NullAwayとは null安全チェック⽤の静的解析ツール Uber社のOSS Google社のErrorProne(静的解析ツール)のプラグインとして動く 他ツールとの優位性 ビルド時オーバーヘッドの⽐較 ● ● 類似の静的解析ツール ○ 2.8倍 〜 5.1倍 NullAway ○ 1.15倍 (※ 2019年の論⽂ NullAway: Practical Type-Based Null Safety for Javaより https://arxiv.org/abs/1907.02127) 82 @2025 WealthNavi Inc.

83.

NullAway:導⼊⽅法(Gradle) plugins { id("net.ltgt.errorprone") version "4.3.0" } dependencies { errorprone "com.uber.nullaway:nullaway:0.12.10" errorprone "com.google.errorprone:error_prone_core:2.42.0" } import net.ltgt.Gradle.errorprone.CheckSeverity tasks.withType(JavaCompile).configureEach { options.errorprone { // ErrorProneの警告を無効化 disableAllChecks = true // NullAwayの指摘をエラーとして扱う check("NullAway", CheckSeverity.ERROR) // null安全チェックしたいパッケージを指定 option("NullAway:AnnotatedPackages", "com.sample") } } 83 @2025 WealthNavi Inc.

85.

5 1 導⼊すべきか、⾒送るべきか © WealthNavi Inc. All Rights Reserved. 85

86.

導⼊すべきか、⾒送るべきか JSpecify&NullAway導⼊をすべきケース ● Spring Bootを使っていて今後数年内でSpringバージョンアップを計画しているケース ● これから新規でプロジェクトを⽴ち上げるケース ● JavaとKotlinが混在しているケース ● Kotlinへの移⾏をしようか悩んでいるケース 導⼊を⾒送ってもいいケース ● Gradle, Maven, Bazel以外のビルドツールを使⽤しているケース ● Java8以下を使っているケース(ErrorProneの互換性影響) 86 @2025 WealthNavi Inc.

87.

We are hiring 採⽤強化中 安⼼して使える⾦融インフラを共につくる仲間募集 https://recruit.wealthnavi.com/ © WealthNavi Inc. All Rights Reserved. 87

88.

重要な注意事項 ● 本資料は、断定的判断を提供するものではなく、情報を提供することのみを⽬的としており、いかなる種類の商 品も勧誘するものではありません。最終的な決定は、お客様⾃⾝で判断するものとし、当社はこれに⼀切関与せ ず、また、⼀切の責任を負いません。 ● 本資料には将来の出来事に関する予想が含まれている場合がありますが、それらは予想であり、また、本資料の 内容の正確性、信頼性、完全性、適時性等を⼀切保証するものではありません。本資料に基づいて被ったいかな る損害についても、当社は⼀切の責任を負いません。また、当社は、新しい情報や将来の出来事その他の情報に ついて、更新⼜は訂正する義務を負いません。 ● 本資料を利⽤することによりお客様に⽣じた直接的損害、間接的損害、派⽣的損害その他いかなる損害について も、当社は⼀切の責任を負いません。 商号等:ウェルスナビ株式会社 金融商品取引業者 関東財務局長(金商) 第2884号 加入協会:日本証券業協会 一般社団法人日本投資顧問業協会 © WealthNavi Inc. All Rights Reserved.