Javaで配列の合計・平均を求める方法(forループ)

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

配列の合計 とは

配列の中身を for-each で順番にたどり、累積パターンで合計値を求めます。本レッスンでは、配列の合計 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

配列に累積パターンを持ち込む

前のレッスンまでで、1 から N までの合計を for 文と sum 変数で計算する 累積パターン をしっかり手に馴染ませてきました。今回はそれを 配列 (int[]) に持ち込みます。arr = {1, 2, 3} のような配列を受け取り、その中身の合計 1 + 2 + 3 = 6 を返すメソッドを書く、というのが今日の課題です。

仕様はとてもシンプルで、次のような対応関係になります。

  • arraySum({1, 2, 3})6
  • arraySum({})0 (空配列なら 0)
  • arraySum({-5, 5})0 (負の数とプラマイ相殺)
  • arraySum({10})10

やっていることは「箱の中身を全部足す」だけなので、Java を触っているとごく日常的な処理です。実務でも、売上の合計 アクセス数の合計 点数の合計 のように、配列やリストの中身を集計する場面は嫌というほど出てきます。ここで一度しっかり書けるようになっておくと、後がとても楽です。

「足す」「数える」「最大値を取る」「平均を取る」など、配列を 1 周なめながら 1 つの結果を作る処理を、英語では reduce (リデュース / 集約) と呼びます。sum はその一番素直な例で、合計だけでなく min max count average も同じ骨格で書けます。今日のコードはその雛形だと思って書いてみてください。

累積パターン ─ 配列版の組み立て方

手順は前のレッスンとほぼ同じで、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-eachfor (型 変数名 : 配列) という形で、「コロンの左に取り出す入れ物、右に取り出される元」を書きます。日本語にすると「arr の中の各 x について」と読めて、英語の for each x in arr がそのまま Java の構文になっています。集計や検索のように、インデックス を気にせず中身だけ見たいときは、いつも for-each を選ぶようにしましょう。

動きを追ってみる

arraySum({3, 1, 4, 1, 5}) を呼んだとき、sum の中身がどう変化していくかを 1 ステップずつ追ってみます。下の図は、ループが 1 周まわるごとに sum がどう書き換えられるかを表しています。

diagram (will load when visible)

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; } }

読み下すと「sum0 で用意し、arr の中の各 x について sumx を足し、最後に 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 周も回らず、sum0 のまま 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 だと、スレッドプール Future synchronized などを自分で組み立てる必要があるところを、ライブラリ側がぜんぶ面倒を見てくれるわけです。

もちろん、Stream を使えば常に速くなるわけではなく、要素数が少ないと逆に遅くなることもあります (オーバーヘッドのほうが大きいため)。それでも「ループの中身が独立していて、足し算のように順番に依存しない処理」は、後で並列化しやすい形で書いておくと、データが膨らんだときに対応がぐっと楽になります。

この講座では forfor-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 チェックを書きすぎる / 書かなさすぎる — 今回の課題では arrnull で渡されることは想定していませんが、実務だと 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); を一時的に挟んで、xsum が 1 周ごとにどう変わっているかを確認してみましょう。累積パターン のバグは、ほぼすべてここを見れば判定できます。

やってみよう

それでは右側のエディタで、Solution.arraySum(int[] arr) メソッドを完成させてみましょう。手順は次のとおりです。

  1. メソッドの中で int sum = 0; と書いて変数を初期化する
  2. for (int x : arr)for-each ループを書く
  3. ループの中で sum += x; (または sum = sum + x;) と書く
  4. ループの後ろで return sum; と書く
  5. 「実行」ボタンを押して、すべてのテストが緑になるか確認する

動いたら、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 つができることを確認しましょう。

  1. 合計 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. 合計 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. クラス名は Solution、メソッド名は arraySum、引数は int[] arr ひとつにすること
  2. メソッドの戻り値の型は int で、配列の中身の合計を返すこと
  3. 空配列 {} のときは 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

ヒント

main.java
main.java
学習モード

メモ

Javaで配列の合計・平均を求める方法(forループ)

⌘S で保存