Javaで処理時間を測定したい場合、System.nanoTime()
や Instant
/ Duration
などの標準APIを使うのが一般的です。しかし、こうした手法はコードが冗長になりがちで、読みやすさにも課題があります。
そんな中、処理時間の測定をもっと手軽に、そして明確にしてくれるのが、Googleが提供するライブラリ Guava の Stopwatch
クラスです。わずか数行で、ナノ秒精度の計測と時間単位の変換が可能になるため、開発やデバッグの効率を大きく向上させてくれます。
この記事では、Stopwatch
の基本的な使い方から応用テクニック、注意点や活用シーンまでを丁寧に解説します。「Javaで手軽に処理時間を計測したい」と考えている方にとって、実践的なヒントが得られる内容になっています。
Stopwatchとは?
Stopwatch
は、Googleが提供するJavaライブラリ Guava に含まれる、com.google.common.base.Stopwatch
クラスです。処理の開始から終了までの経過時間を、簡潔なコードで正確に測定できるユーティリティとして、多くの開発現場で活用されています。
標準APIの System.nanoTime()
や Instant.now()
/ Duration.between()
といった手法に比べて、Stopwatch
には以下のような明確な利点があります。
- コードがシンプルで読みやすい:処理の計測開始・終了をメソッドで明示できる
- 時間単位の指定が柔軟:ナノ秒・ミリ秒・秒などの単位を簡単に切り替え可能
- ログ出力との相性が良い:経過時間の可視化やトラブルシューティングに役立つ
このように、Stopwatch
は「わかりやすく、正確に、すぐ使える」ことを重視した、開発者にとって非常に便利な計測ツールです。
Stopwatchの基本的な使い方
Stopwatch
を使えば、処理時間の計測を非常にシンプルに記述できます。以下は、1秒間のスリープ処理を測定する基本的な例です。
import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;
public class StopwatchExample {
public static void main(String[] args) {
// 計測開始
Stopwatch stopwatch = Stopwatch.createStarted();
// 測定したい処理
try {
Thread.sleep(1500); // 1.5秒待機
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 計測停止
stopwatch.stop();
// 結果を様々な単位で出力
System.out.println("経過時間(秒): " + stopwatch.elapsed(TimeUnit.SECONDS));
System.out.println("経過時間(ミリ秒): " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
System.out.println("経過時間(ナノ秒): " + stopwatch.elapsed(TimeUnit.NANOSECONDS));
}
}
このように、Stopwatch.createStarted()
でインスタンスを生成すると、即座に計測が始まります。必要に応じて stop()
を呼び、elapsed()
で経過時間を取得します。取得時には TimeUnit
を指定することで、秒・ミリ秒・ナノ秒などの任意の単位に変換できます。
よく使うメソッド一覧
メソッド | 説明 |
---|---|
createStarted() | 計測開始状態でインスタンス作成 |
createUnstarted() | 計測未開始状態でインスタンス作成 |
start() | 計測開始 |
stop() | 計測停止 |
reset() | 内部時間をリセット(再使用可能) |
elapsed(TimeUnit) | 指定単位で経過時間を取得 |
elapsed() | Duration で経過時間を取得(Guava 21以降) |
isRunning() | 計測中かどうかを判定 |
これらのメソッドを組み合わせることで、柔軟かつ簡潔に処理時間を測定できます。特に reset()
と isRunning()
の使い方を覚えておくと、再利用や状態管理がしやすくなります。
応用:複数処理の計測
Stopwatch
は、1つの処理だけでなく、複数の処理時間を個別または連続で測定する用途にも活用できます。ここでは、2つの典型的なパターンを紹介します。
① 個別に処理時間を計測する
それぞれの処理を独立して計測したい場合は、stop()
→ reset()
→ start()
という操作を繰り返すことで、正確な処理時間を区切って記録できます。
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
doHeavyTask1();
stopwatch.stop();
System.out.println("タスク1完了:" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
stopwatch.reset(); // 状態をリセットして再利用
stopwatch.start();
doHeavyTask2();
stopwatch.stop();
System.out.println("タスク2完了:" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
この方法は、各処理の実行時間を明確に比較したい場面(例:処理のボトルネック特定やリファクタリング時)に最適です。
② 連続して累積時間を計測する
複数の処理を連続して実行しながら、全体の経過時間や途中時点のタイムスタンプを確認したいときには、stop()
や reset()
は不要です。
Stopwatch stopwatch = Stopwatch.createStarted();
doHeavyTask1();
long time1 = stopwatch.elapsed(TimeUnit.MILLISECONDS);
System.out.println("タスク1完了:" + time1 + " ms");
doHeavyTask2();
long time2 = stopwatch.elapsed(TimeUnit.MILLISECONDS);
System.out.println("タスク2完了(累積):" + time2 + " ms");
System.out.println("タスク2単体:" + (time2 - time1) + " ms");
このスタイルは、処理全体の経過時間を通して把握したいケースや、各処理の「終了時点での累積時間」を記録したい場合に便利です。
なお、elapsed()
の呼び出しタイミングによって計測値が異なるため、必要であれば一時変数(例:time1
, time2
)を用いて時間差を算出するのがポイントです。
Stopwatchの使用上の注意点とベストプラクティス
Stopwatch
は手軽で便利なツールですが、使う際にはいくつかの注意点があります。以下では、正しく活用するために押さえておくべきポイントを解説します。
① スレッドセーフではない
Stopwatch
は スレッドセーフではありません。複数スレッドで1つのインスタンスを共有すると、予期しない動作になる可能性があります。マルチスレッド環境では、各スレッドごとに個別の Stopwatch
インスタンスを用意するのが基本です。
② 高精度だが万能ではない
Stopwatch
の内部では System.nanoTime()
を使っており、ナノ秒レベルの高精度な計測が可能です。ただし、以下のような要因により、精度には多少のブレが生じる場合があります。
- OSやCPUのスケジューリングによる遅延
- JVMのJITコンパイルやガベージコレクションの影響
- 仮想マシン上での実行や電源管理機能によるタイミングのずれ
そのため、Stopwatchはあくまで「目安としての処理時間の測定」用途に使うのが適しています。
③ ベンチマークには不向き
正確な性能比較やアルゴリズムのスループットを測定したい場合には、Stopwatch
は適していません。そうしたケースでは、JMH(Java Microbenchmark Harness) のような専門的なベンチマークツールの使用を検討すべきです。
④ 実務でのおすすめ活用法
- ログ出力と組み合わせる:処理開始・終了のログと一緒に、所要時間を記録
- try-finallyブロックで確実に停止:
stop()
の呼び忘れを防止 - elapsed()の再利用に注意:
elapsed()
は毎回最新の時間を返すため、比較には中間値の保存を
こうしたベストプラクティスを守ることで、Stopwatch
をより安全かつ正確に活用できます。
まとめ:シンプルな処理時間計測にはGuavaのStopwatch!
Stopwatch
は、GoogleのGuavaライブラリに含まれる便利なユーティリティで、Javaでの処理時間の計測をシンプルかつ高精度に実現できます。
System.nanoTime()
や Duration
などの標準APIに比べて、記述が直感的で、時間単位の変換や状態管理も容易な点が大きな魅力です。個別・連続の計測にも対応でき、テストやログ出力など多くの現場で役立ちます。
ただし、スレッドセーフではない点や、精密なベンチマーク用途には適さないといった制約もあるため、使用目的に応じて使い分けることが大切です。
「ちょっとした処理の実行時間を手軽に測りたい」「ログに処理時間を出してボトルネックを見つけたい」といった場面では、Stopwatch
は非常に強力な選択肢となるでしょう。
日々の開発において、「この処理、どれくらい時間がかかっているんだろう?」と思った時は、ぜひStopwatchを活用してみてください。きっと開発効率とコードの品質向上に貢献してくれるはずです。