Javaで配列の合計・平均を求める方法(forループ)
配列の合計 とは
配列の中身を for-each で順番にたどり、累積パターンで合計値を求めます。本レッスンでは、配列の合計 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
配列に累積パターンを持ち込む
前のレッスンまでで、1 から N までの合計を for 文と sum 変数で計算する 累積パターン をしっかり手に馴染ませてきました。今回はそれを 配列 (int[]) に持ち込みます。arr = {1, 2, 3} のような配列を受け取り、その中身の合計 1 + 2 + 3 = 6 を返すメソッドを書く、というのが今日の課題です。
仕様はとてもシンプルで、次のような対応関係になります。
arraySum({1, 2, 3})→6arraySum({})→0(空配列なら0)arraySum({-5, 5})→0(負の数とプラマイ相殺)arraySum({10})→10
やっていることは「箱の中身を全部足す」だけなので、Java を触っているとごく日常的な処理です。実務でも、売上の合計 アクセス数の合計 点数の合計 のように、配列やリストの中身を集計する場面は嫌というほど出てきます。ここで一度しっかり書けるようになっておくと、後がとても楽です。
「足す」「数える」「最大値を取る」「平均を取る」など、配列を 1 周なめながら 1 つの結果を作る処理を、英語では
reduce(リデュース / 集約) と呼びます。sumはその一番素直な例で、合計だけでなくminmaxcountaverageも同じ骨格で書けます。今日のコードはその雛形だと思って書いてみてください。
累積パターン ─ 配列版の組み立て方
手順は前のレッスンとほぼ同じで、for のループ範囲が「1 から N まで」から「配列の先頭から末尾まで」に変わるだけです。具体的には次の 3 ステップで組み立てます。
- 準備 — 結果を貯める
int sum = 0;を用意する - 繰り返し — 配列の中身を 1 つずつ取り出して
sumに足していく - 完成 — ループが終わった時点で、
sumの中身が答えになっている
配列を頭からなめる書き方は、Java では大きく 2 通りあります。インデックス を使う伝統的な for と、中身を直接取り出す for-each (拡張 for 文) の 2 つです。まずは両方の文法を眺めてみましょう。
Java
// パターン 1: インデックス for
for (int i = 0; i < arr.length; i++) {
sum = sum + arr[i];
}
// パターン 2: for-each (拡張 for 文)
for (int x : arr) {
sum = sum + x;
}どちらも結果は同じです。違うのは「ループの中で i というインデックスを使えるかどうか」だけで、合計を取りたいだけのときはインデックスは要らないので、for-each のほうがずっと読みやすくなります。
for-eachはfor (型 変数名 : 配列)という形で、「コロンの左に取り出す入れ物、右に取り出される元」を書きます。日本語にすると「arrの中の各xについて」と読めて、英語のfor each x in arrがそのまま Java の構文になっています。集計や検索のように、インデックスを気にせず中身だけ見たいときは、いつもfor-eachを選ぶようにしましょう。
動きを追ってみる
arraySum({3, 1, 4, 1, 5}) を呼んだとき、sum の中身がどう変化していくかを 1 ステップずつ追ってみます。下の図は、ループが 1 周まわるごとに sum がどう書き換えられるかを表しています。
sum という箱の中身が、配列の要素を 1 つ取り出すたびに 0 → 3 → 4 → 8 → 9 → 14 と書き換わっていきます。ループが終わった瞬間、その箱に入っている 14 が答えです。前回の 1 から N までの合計のときと、骨格はまったく同じであることに注目してください。違うのは「i を動かす」のか「配列の中身を動かす」のかだけです。
実際に書いてみる
上の考え方をそのままコードに落とすと、for-each 版はこうなります。int sum = 0; で初期化し、for-each で各要素を x に取り出し、sum に加える、これだけです。
Java
public class Solution {
public static int arraySum(int[] arr) {
int sum = 0;
for (int x : arr) {
sum = sum + x;
}
return sum;
}
}読み下すと「sum を 0 で用意し、arr の中の各 x について sum に x を足し、最後に sum を返す」となります。sum = sum + x; は sum += x; と短く書いても同じです。
インデックスを使った伝統的な書き方だと、こうなります。同じ結果を返しますが、見た目がちょっと混み合います。
Java
public class Solution {
public static int arraySum(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
}arr.length は 配列の要素数 を返すフィールドで、メソッド呼び出しではないので末尾に () を付けません (arr.length() と書くとコンパイルエラーになります)。一方で String の長さは s.length() でメソッド呼び出しになる、というのが Java の地味にややこしいところです。「配列はフィールド、文字列はメソッド」と呪文のように覚えておくと、迷子になりません。
空配列 {} を渡したらどうなるか、も確認しておきましょう。for-each 版は、arr の中身が 0 個なのでループは 1 周も回らず、sum は 0 のまま return されます。インデックス版も arr.length = 0 なので、i < 0 が最初から false になりループに入りません。どちらも自然に 0 が返って、特別な分岐を書かなくても済むようになっています。
並列処理を意識した書き方 ─ Stream の予告
Java には、もっと宣言的に書ける道具がいくつもあります。中でも代表選手が Stream API です。今は触りだけ紹介しておきます。
Java
import java.util.Arrays;
public class Solution {
public static int arraySum(int[] arr) {
return Arrays.stream(arr).sum();
}
}「Arrays.stream(arr) で配列を IntStream (整数の流れ) に変換して、sum() で合計する」というたった 1 行です。for のループ構造が消えて、何をしたいか がそのまま読めるコードになりました。
Streamの本当のうれしさは、書き換えれば並列処理(parallel) にできることです。Arrays.stream(arr).parallel().sum()と書くだけで、JVM が裏で配列を分割して複数の CPU コアに割り振ってくれます。手書きのforだと、スレッドプールFuturesynchronizedなどを自分で組み立てる必要があるところを、ライブラリ側がぜんぶ面倒を見てくれるわけです。
もちろん、Stream を使えば常に速くなるわけではなく、要素数が少ないと逆に遅くなることもあります (オーバーヘッドのほうが大きいため)。それでも「ループの中身が独立していて、足し算のように順番に依存しない処理」は、後で並列化しやすい形で書いておくと、データが膨らんだときに対応がぐっと楽になります。
この講座では for と for-each をまず使えるようになることが目標ですが、Stream という選択肢の存在は頭の片隅に置いておきましょう。後の章で本格的に登場します。
よくある間違い
配列合計でハマる初心者の落とし穴を 3 つ紹介しておきます。
sumを初期化しない —int sum;と書いただけだと、sum += x;のところでJavaのコンパイラにvariable sum might not have been initializedと怒られます。必ずint sum = 0;と初期値を書きましょう- 累積の代わりに上書き —
sum = x;と書いてしまうと、毎回sumの中身がxで上書きされて、最後の要素しか残りません。arraySum({1, 2, 3})が3を返してきたら、まずここを疑ってください。sum = sum + x;(またはsum += x;) と書く、が累積パターンの命です nullチェックを書きすぎる / 書かなさすぎる — 今回の課題ではarrがnullで渡されることは想定していませんが、実務だとnullが来る可能性があります。安全側に倒すならif (arr == null) return 0;を冒頭に書きます。逆に「nullではなく空配列で渡す」と決めたなら、書く必要はありません。呼び出し側との契約をはっきりさせる ことが、nullを巡るバグを防ぐ一番のコツです
もうひとつ、for-each を使うときに「ループの中で arr の中身を書き換えたい」と思うことがあるかもしれません。for (int x : arr) { x = x * 2; } と書いても、x は コピー なので arr のほうは変わりません。書き換えたいときはインデックス版に切り替えて arr[i] = arr[i] * 2; と書く必要があります。for-each は読み取り専用、と覚えておくと安全です。
エラーが出たり想定外の値が返ってきたら、デバッグの基本は同じです。
for-eachのループの中でSystem.out.println("x=" + x + " sum=" + sum);を一時的に挟んで、xとsumが 1 周ごとにどう変わっているかを確認してみましょう。累積パターンのバグは、ほぼすべてここを見れば判定できます。
やってみよう
それでは右側のエディタで、Solution.arraySum(int[] arr) メソッドを完成させてみましょう。手順は次のとおりです。
- メソッドの中で
int sum = 0;と書いて変数を初期化する for (int x : arr)のfor-eachループを書く- ループの中で
sum += x;(またはsum = sum + x;) と書く - ループの後ろで
return sum;と書く - 「実行」ボタンを押して、すべてのテストが緑になるか確認する
動いたら、for-each を伝統的なインデックス for (int i = 0; i < arr.length; i++) に書き換えても、同じ答えになることを確かめてみてください。そのあと、余裕があれば Arrays.stream(arr).sum() 版にも置き換えてみると、Java の表現の幅が体に染み込みます。「同じ仕様を 3 通りの書き方で書ける」ようになると、コードレビューや実務でもいろいろな書き方を読み解けるようになって、グッと中級者っぽくなります。
累積パターンは、ここから先 平均 最大値 最小値 条件に合うものだけ数える といった集計処理に何度も顔を出します。骨格を変えずに「sum += の部分を Math.max に変える」「if で条件を付ける」だけで、応用問題がどんどん解けるようになるので、ここでしっかり手を動かしておきましょう。
よくある質問
Q. Java と他言語の文法はどう違いますか?
A. Java は静的型付けで、変数宣言時に型を明示します(int x = 0;)。中括弧でブロックを表し、文末にセミコロンが必要です。Python の動的型付けや JavaScript の柔軟さに慣れていると最初は窮屈ですが、コンパイル時にバグが発見できる安全性がメリットです。
Q. コードが動かないときに最初に見るべき場所は?
A. コンパイルエラーは行番号とエラー種別(cannot find symbol、incompatible types など)が表示されます。実行時例外はスタックトレースの最初の at ... が原因行です。IDE(IntelliJ / VS Code)の警告も丁寧に潰すと、半分のバグは未然に防げます。
Q. Java の習得後に学ぶべき技術は何ですか?
A. 基本構文を抑えたら java-intermediate(コレクション / ジェネリクス / Stream / 例外)に進み、Spring Boot や Web 開発に展開するのが王道です。クラウド時代は Kotlin / Scala への展開も視野に入りますが、まずは Java 標準を固めるのが効率的です。
次のレッスン
次は 配列の平均 で、配列の中身を for-each で順番にたどり、累積パターンで合計値を求めます を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- 合計 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 合計 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- クラス名は
Solution、メソッド名はarraySum、引数はint[] arrひとつにすること - メソッドの戻り値の型は
intで、配列の中身の合計を返すこと - 空配列
{}のときは0を返すこと (ループに入らないケースに対応)
入出力例
test-cases.txt
arraySum([1,2,3]) → 6
arraySum([]) → 0
arraySum([-5,5]) → 0
arraySum([10]) → 10
arraySum([3,1,4,1,5,9,2,6]) → 31