JavaのNullPointerExceptionを修正する方法

beginner Java2026-03-17| Java 8以降(JDK/JRE)、任意のOS(Linux、macOS、Windows)、Spring Boot、Maven/Gradleプロジェクト

Error Message

java.lang.NullPointerException
#java#nullpointerexception#exception

エラーの内容

Exception in thread "main" java.lang.NullPointerException
    at com.example.UserService.getUsername(UserService.java:42)
    at com.example.Main.main(Main.java:15)

Spring Bootでは、Java 14で追加されたより詳細な形式が表示される場合があります:

java.lang.NullPointerException: Cannot invoke "com.example.User.getName()" because "user" is null

NPEはJavaで最も一般的なランタイム例外であり、実質的にすべての本番コードベースで発生します。JVMは、何も参照していない参照を使用しようとしたとき(メソッドの呼び出し、フィールドへのアクセス、nullオブジェクトの配列インデックスなど)にこの例外をスローします。

原因

スタックトレースに答えがあります。まず最初にそれを確認してください。根本原因はほぼ常に次のどれかに当てはまります:

  • メソッドがnullを返し、チェックせずにその結果を使用した
  • フィールドが初期化されなかった(newを忘れた)
  • オートワイヤーされたBeanがnull — テストでSpringコンテキストが読み込まれなかった
  • コレクションまたは配列の要素がnull
  • nullを返す可能性のあるものへのメソッドチェーン

修正手順

ステップ1:スタックトレースを読む

これをスキップしないでください。スタックトレースには正確なファイルと行番号が示されています。JDKやフレームワーク内部ではなく、自分のコードの最上位の行を見つけてください:

at com.example.UserService.getUsername(UserService.java:42)

42行目に移動してください。そこでnullが逆参照されています。その行のどのオブジェクトがnullかを特定してください。

ステップ2:nullチェックを追加する(クイックフィックス)

最速の修正方法 — 値を使用する前にガードを追加します:

// 修正前(userがnullの場合クラッシュ)
String name = user.getName();

// 修正後
if (user != null) {
    String name = user.getName();
} else {
    log.warn("ユーザーがnullです。名前の検索をスキップします");
}

ステップ3:Optionalを使用する(よりクリーンな修正)

Java 8のOptionalはnullの処理を明示的かつチェーン可能にします。メソッドが正当に結果を返さない可能性がある場合に使用してください:

// nullの代わりにOptionalを返す
public Optional<User> findUser(Long id) {
    User user = dao.find(id); // 見つからない場合はnullを返す
    return Optional.ofNullable(user);
}

// 呼び出し側 — nullチェック不要
String name = findUser(userId)
    .map(User::getName)
    .orElse("不明");

ステップ4:未初期化フィールドを修正する

フィールドアクセス時のNPEは通常、フィールドが一度も割り当てられなかったことを意味します。宣言時に初期化してください:

// 問題あり — listが初期化されていない
public class OrderService {
    private List<Order> orders;

    public void addOrder(Order o) {
        orders.add(o); // ここでNPE発生
    }
}

// 修正済み
public class OrderService {
    private List<Order> orders = new ArrayList<>();

    public void addOrder(Order o) {
        orders.add(o); // 正常に動作
    }
}

ステップ5:Spring AutowiredのNPEを修正する

よくあるSpringのミス — Springに管理させる代わりにnewでクラスをインスタンス化してしまっている:

// 問題あり — Springはこのインスタンスを管理しないため、repo内はnull
UserService service = new UserService();
service.doSomething(); // 内部でNPE発生

// 修正済み — Springにインジェクションを任せる
@Autowired
private UserService service;

Springコンテキストが読み込まれないユニットテストでは、代わりにMockitoで依存関係をモックしてください:

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock
    private UserRepository repo;

    @InjectMocks
    private UserService service;

    @Test
    void testGetUser() {
        when(repo.findById(1L)).thenReturn(new User("Alice"));
        assertEquals("Alice", service.getUsername(1L));
    }
}

ステップ6:メソッドチェーンのNPEを修正する

a.getB().getC().getValue()のようなチェーンは、いずれかのステップがnullを返すとNPEになります。Optionalでラップしてください:

// リスクあり — チェーンのどのリンクもnullになりうる
String city = order.getCustomer().getAddress().getCity();

// Optionalで安全に
String city = Optional.ofNullable(order)
    .map(Order::getCustomer)
    .map(Customer::getAddress)
    .map(Address::getCity)
    .orElse("N/A");

ステップ7:役立つNPEメッセージを有効にする(Java 14以降)

Java 14から、JVMは行番号だけでなく、式のどの部分がnullであったかを正確に教えてくれます。Java 15以降はデフォルトで有効です:

# Java 14で明示的に有効化
java -XX:+ShowCodeDetailsInExceptionMessages YourApp

# エラー出力がより具体的になる:
# Cannot invoke "Address.getCity()" because the return value
# of "Customer.getAddress()" is null

Java 8〜13では、原因を手動で絞り込むために、問題のあるチェーンの周りに構造化されたログを追加してください。

修正の確認

  • NPEを引き起こしたコードパスを再実行し、例外がスローされなくなったことを確認する
  • nullケースを明示的にカバーするユニットテストを書く:
@Test
void shouldHandleNullUser() {
    when(repo.findById(99L)).thenReturn(null);
    String result = service.getUsername(99L);
    assertEquals("不明", result); // デフォルト値を返し、例外はスローしない
}
  • ログを確認する — nullパスにlog.warnを追加した場合、ダウンストリームでクラッシュせずに表示されることを確認する

クイックリファレンス:よくあるパターン

// Objects.requireNonNull — 明確なメッセージで即時失敗
public UserService(UserRepository repo) {
    this.repo = Objects.requireNonNull(repo, "repoはnullであってはなりません");
}

// nullの代わりに空のコレクションを返す
public List<User> getUsers() {
    List<User> result = repo.findAll();
    return result != null ? result : Collections.emptyList();
}

// 文字列比較 — 定数を左側に置く
if ("ACTIVE".equals(status)) { ... } // statusがnullでも安全

デバッグのヒント

  • NPEが発生した行にブレークポイントを設定し、IDEで変数を調べる — null参照がすぐにわかる
  • 本番環境でのみNPEが発生する場合は、クラッシュ前に一時的なログ行を追加して問題のある変数を出力し、再デプロイする
  • IntelliJ IDEAは@NotNull/@Nullableアノテーションを使用してNPEが発生しやすいコードをハイライトする — 設定 → エディター → インスペクション → Java → 疑わしいバグ で有効にできる
  • コンパイル時のnull安全性のために、Lombokの@NonNullまたはChecker Frameworkのnullnessチェッカーを試してみる

Related Error Notes