PR

【Java】throwとthrowsの違いとは?例外処理の流れを初心者向けに1から解説

throwとthrowsの記事内容を表すJavaカテゴリ用のunDraw背景アイキャッチ画像 Java

Javaのthrowthrowsの違いは、throwは例外を実際に投げる文、throwsは例外が外へ出る可能性を宣言する句という点です。

名前が似ているため最初は混ざりやすいですが、置かれる場所も役割も違います。throwはメソッドの中で使い、throwsはメソッド定義の横に書きます。

『その場で起こすのが throw』『外へ伝える可能性を示すのが throws』と覚えると、かなり整理しやすくなります。

この記事では、両者の違い、具体的なコード、try-catchとの関係、checked exceptionでthrowsが必要になる理由まで順番に解説します。

この記事はtry-catch文そのものの入門ではなく、try-catchの次に混ざりやすいthrowとthrowsの読み分けに絞ります。try-catchの基本はJavaの例外処理の基本、リソース解放の話はtry-with-resourcesの記事に分けます。

スポンサーリンク

まず結論:throwは投げる、throwsは宣言する

Java Language Specificationでは、throwは例外を発生させて制御を移す文として定義されています。一方、throwsはメソッドやコンストラクタが外へ出し得るchecked exceptionを宣言する句です。

次の図では、『実行される文』と『宣言として書く句』を分けて見てください。

throwは例外を投げる文でthrowsは例外が外へ出る可能性を宣言する句であることを比較した図
throwは『今ここで投げる』、throwsは『このメソッドから外へ出るかもしれないと宣言する』と分けて読みます。

1分で違いを見る

比較throwthrows
書く場所メソッド本体の中メソッド宣言やコンストラクタ宣言
役割例外を実際に投げる例外が外へ出る可能性を示す
throw new IllegalArgumentException()read() throws IOException
try-catchとの関係投げた先で捕まる呼び出し側に処理を促す

throwはどこで使うか

入力値が不正なときなど、メソッドの中で自分から例外を発生させたい場合にthrowを使います。

static void validatePrice(int price) {
    if (price < 0) {
        throw new IllegalArgumentException("price must be zero or more");
    }
}

この例では、価格が負数ならその場で処理を止め、IllegalArgumentExceptionを投げています。

throwsはどこで使うか

メソッドの中でchecked exceptionが外へ出る可能性がある場合、呼び出し側へその可能性を知らせるためにthrowsを書きます。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

static String loadText(Path path) throws IOException {
    return Files.readString(path);
}

この例では、ファイル読み込み中にIOExceptionが起きる可能性を、メソッド宣言で示しています。

throwsを書いたからといって、その場で例外が処理されるわけではありません。呼び出し側がtry-catchで処理するか、さらに外へ渡す必要があります。

try-catchとどうつながるか

public static void main(String[] args) {
    try {
        String text = loadText(Path.of("memo.txt"));
        System.out.println(text);
    } catch (IOException e) {
        System.out.println("ファイルを読めませんでした");
    }
}

ここでは、loadText側がthrows IOExceptionで可能性を示し、呼び出し側がtry-catchで受け止めています。

try-catchそのものの基本が曖昧な場合は、先にJavaの例外処理の基本を読んでから戻ると理解しやすいです。

checked exceptionでthrowsが必要になる理由

checked exceptionは、コンパイラが『処理するか、外へ渡すかを決めてください』と確認する種類の例外です。そのため、メソッド内で発生し得るchecked exceptionを自分で捕まえない場合は、throwsで宣言する必要があります。

一方、IllegalArgumentExceptionのような実行時例外は、必ずしもthrowsへ書く必要はありません。ここが最初につまずきやすい分岐です。

初心者がつまずきやすいポイント

つまずきまずこう理解する
throwsを書けば処理済みだと思うthrowsは宣言であり、処理ではない
throwthrowsを同じ場所で使うと思うthrowは本体、throwsは宣言部
実行時例外でも必ずthrowsが必要だと思うunchecked exceptionでは必須ではない
caller側の処理を見ない例外は投げた後の受け取り方まで見る

リソースを開く処理と例外の関係まで進みたい場合は、try-with-resourcesも次に読むとつながります。

throwsをさらに外へ渡す場合

呼び出し側で必ずcatchしなければならない、というわけではありません。今のメソッドでは処理せず、さらに外側へ任せたい場合は、呼び出し側のメソッドにもthrowsを書きます。

static void printFile(Path path) throws IOException {
    String text = loadText(path);
    System.out.println(text);
}

このコードでは、printFileの中ではIOExceptionを処理していません。代わりに、printFileを呼び出す側へ『IOExceptionが外へ出るかもしれない』と伝えています。

つまりthrowsは、例外を消すためのものではありません。責任の場所を外へ渡すための宣言です。最終的には、どこかでtry-catchするか、さらに外へ伝えるかを決める必要があります。

例外メッセージは読む人のために書く

throwで例外を投げるときは、メッセージも大切です。後からログを見た人が、何が悪かったのかを判断できるようにします。

if (price < 0) {
    throw new IllegalArgumentException("price must be zero or more: " + price);
}

この例では、単に『エラー』と書くのではなく、どの値が問題だったのかまで含めています。初心者のうちは、例外メッセージを利用者向けの文章ではなく、開発者が原因を追うための手がかりとして考えるとよいです。

よくある疑問

throwsだけを書けば例外は解決する?

解決したわけではありません。throwsは『このメソッドでは処理せず、外へ伝える』という宣言です。呼び出し側がtry-catchで受けるか、さらに外へthrowsで渡すかを決める必要があります。

throw new Exception() と書けばよい?

何でもExceptionで投げると、呼び出し側が原因を判断しにくくなります。入力値が不正ならIllegalArgumentExceptionのように、状況に合う例外クラスを選ぶ方が読みやすくなります。初心者のうちは、まず既存の代表的な例外を使い分けるところから始めましょう。

RuntimeExceptionはthrowsに書かないの?

RuntimeException系の例外は、必ずthrowsへ書く必要はありません。ただし、APIとして利用者に注意してほしい場合に、ドキュメント上で説明することはあります。まずは『checked exceptionは処理か宣言が必要、unchecked exceptionは必須ではない』という大枠を押さえれば十分です。

公式情報と関連して読みたい記事

まとめ

throwthrowsは、名前は似ていますが役割が違います。

  • throwは例外を実際に投げる文
  • throwsは外へ出る可能性を宣言する句
  • throwsは処理そのものではない
  • 呼び出し側のtry-catchまで見て、流れで理解する

この違いを押さえると、例外処理のコードを『どこで起きて、どこで受けるのか』まで追いやすくなります。

タイトルとURLをコピーしました