Java入門のよくある間違い

レッスンの本文で注意している点を、つまずきの側から148件ぶん並べ直しました。書いた覚えのある形が見つかったら、 そのままレッスンに戻って前後を読めます。

はじめての Java プログラム

レッスンを読む

ダブルクォートとシングルクォートの混同

文字列は "Hello" のように 必ずダブルクォート で囲みます。'Hello' と書くと「文字 1 個」の型 (char) になってしまい、コンパイルエラーです

はじめての Java プログラムで詳しく読む

変数を宣言する

レッスンを読む

型を書き忘れる

age = 20; のように、いきなり代入から書くとエラーになります。Java では最初に必ず int age = 20; のように型を書く必要があります

変数を宣言するで詳しく読む

初期化せずに使う

int x; System.out.println(x); のように、値を入れる前にローカル変数を使うと variable x might not have been initialized と怒られます

変数を宣言するで詳しく読む

型と合わない値を代入する

int age = "20"; のように、int 型の箱に文字列を入れようとするとエラーになります。int age = 20; のように、型と値の種類を合わせましょう

変数を宣言するで詳しく読む

四則演算と剰余

レッスンを読む

整数除算で小数を期待する

int avg = (a + b) / 2; と書いて、平均が想定より 1 小さい、というのは定番の罠です。double avg = (a + b) / 2.0; のように、片方を小数にして回避しましょう

四則演算と剰余で詳しく読む

ゼロ除算で実行時エラー

int x = 10 / 0; を実行すると ArithmeticException: / by zero が出てプログラムが落ちます。% も同様で 10 % 0 も例外になります。割る前に if (b != 0) でチェックするか、b == 0 の場合の戻り値を決めておくのが安全です

四則演算と剰余で詳しく読む

優先順位を勘違いする

1 + 2 * 39 ではなく 7 です。「左から順番」と思い込んで計算するとズレます。迷ったらカッコを付けて自分の意図を明示しましょう

四則演算と剰余で詳しく読む

インクリメントとデクリメント

レッスンを読む

同じ式の中で同じ変数を何度も増減させる

int y = x++ + x++; のように 1 行で x を 2 回動かすコードは、読みづらいうえに動作の理解も難しくなります。Java では仕様上動作は決まっていますが、避けるべきコード の代表例です

インクリメントとデクリメントで詳しく読む

n をそのまま n++ してしまう

今回の課題のように引数の値を保ったまま +1 -1 した値が欲しい場合、n++ をすると n の値そのものが変わってしまいます。必ず別の変数にコピーしてから動かすこと

インクリメントとデクリメントで詳しく読む

比較演算子

レッスンを読む

=== の混同

上で説明した通り。if (a = 5) と書いてしまうと Java ではコンパイルエラー、他の言語では「代入してから true 判定」という別の動きになる罠です

比較演算子で詳しく読む

文字列を == で比較する

String s1 = "hello"; String s2 = new String("hello"); s1 == s2 は意外にも false になります。文字列の中身を比べたいときは必ず s1.equals(s2) を使ってください。== はオブジェクトの「参照」が同じかを見るので、中身が同じでも別オブジェクトなら false です

比較演算子で詳しく読む

浮動小数の == 比較

double x = 0.1 + 0.2; x == 0.3false です。double は内部で 2 進数表現するため、計算誤差が生じます。浮動小数を比べたいときは Math.abs(x - 0.3) < 1e-9 のように「許容誤差以内か」で判定するのが定石です

比較演算子で詳しく読む

論理演算子

レッスンを読む

& | (ビット演算) と && || の混同

& 1 個と | 1 個は、int 用のビット演算子です。boolean にも一応使えますが、短絡評価が効かないので推奨されません。if の条件には必ず && || を 2 個重ねて書きましょう

論理演算子で詳しく読む

! を忘れる / 付け忘れる

「ログインしていない場合」は !isLoggedIn です。isLoggedIn のままだと逆の意味になります。日本語の「~でない」を ! に翻訳する習慣をつけてください

論理演算子で詳しく読む

優先順位の勘違い

&&|| よりも優先順位が高いです。a || b && ca || (b && c) の意味になります。意図したとおりに書きたいときは、迷わずカッコ () で囲みましょう

論理演算子で詳しく読む

演算子の優先順位

レッスンを読む

a + b * c(a + b) * c と勘違いする

数学の 2 + 3 × 4 と同じく、* が先です。Java の式を読むときは、まず * / % を探して心の中で先にカッコを補うクセを付けましょう

演算子の優先順位で詳しく読む

x = y = z の結合方向を逆にする

代入 = は 右から左 に結合するので x = (y = z) と読みます。(x = y) = z ではないので注意。さらに代入式は = の右辺の値を返すため、if ((line = reader.readLine()) != null) のような書き方も存在します

演算子の優先順位で詳しく読む

ビット演算 & | と論理演算 && || の優先順位を混同する

ビット演算 & ^ | は等価演算子 == != や関係演算子 < > よりも優先順位が低く、論理演算子 && || よりは高い位置にあります。ただし &&& の本質的な違いは優先順位だけでなく 短絡評価 (short-circuit evaluation) の有無です。&& は左辺が false の時点で右辺を評価しませんが、& は必ず両辺を評価します。たとえば if (obj != null & obj.getValue() > 0) のように & を使うと、objnull でも右辺が実行されて NullPointerException が発生します。論理判定では必ず && || を使ってください

演算子の優先順位で詳しく読む

文字列の連結

レッスンを読む

数値同士を連結したつもりが足し算になる

"合計: " + a + b と書くと、a + b が最初に連結されてしまい、a = 1, b = 2 の場合 "合計: 12" になります。"合計: " + (a + b) のようにカッコで括れば "合計: 3" になります

文字列の連結で詳しく読む

評価順序を勘違いする

1 + 2 + "円""3円" ですが、"金額: " + 1 + 2"金額: 12" です。String が登場した瞬間から、以降の + は文字列連結になります

文字列の連結で詳しく読む

null を連結すると "null" になる

String name = null; String msg = "こんにちは、" + name; と書くと、msg"こんにちは、null" という文字列になります。意図せず null を含んだ表示が出てしまい、ユーザーに気付かれて慌てる、というのは Java の現場でよくある失敗です。事前に if (name != null) でチェックするか、Objects.toString(name, "匿名") のようにデフォルト値を用意しましょう

文字列の連結で詳しく読む

型変換 (キャスト)

レッスンを読む

キャストの位置を間違える

(double)(a / b) のようにカッコ全体に掛けると、先に整数除算してから double 化することになり、小数部が消えます。(double) a / b のように 割り算する前のオペランド にキャストするのが正解です

型変換 (キャスト)で詳しく読む

桁あふれ (overflow)

long → intint → byte のような縮小変換で、変換先の範囲を超えると値が壊れます。たとえば int n = (int) 3000000000L;int の上限 (約 21 億) を超えるため、まったく違う負の数になります。(int) のキャストはコンパイラに「失われてもいいから変換する」と伝える宣言なので、警告は出ません。範囲を超えていないか自分でチェックする責任があります

型変換 (キャスト)で詳しく読む

(double) を片側だけに付けるのを忘れる

int a = 7, b = 2; のとき、double r = a / b; と書いても結果は 3.0 で、3.5 にはなりません。整数除算してから double に拡大しているだけだからです。少なくともどちらか一方に (double) を明示しないと、小数演算にはなりません

型変換 (キャスト)で詳しく読む

if 文の基本

レッスンを読む

{ } を省略してハマる

if (x > 0) return "positive"; のように { } なしで 1 行書いた後、「処理を追加しよう」と 2 行目を足しても、その 2 行目は if の中ではなく外として扱われます。インデントが揃っているのでぱっと見では気づきにくく、デバッグに時間を取られる典型例です

if 文の基本で詳しく読む

if (x = 0) と書いてしまう

─ 代入の = と比較の == の混同です。x = 0 は「x0 を代入する」という意味で、条件式としては成り立ちません。Java では boolean を期待する場所に int の代入結果が来るのでコンパイルエラーになり、最近の言語の中では比較的安全です

if 文の基本で詳しく読む

if (x); と書いてしまう

if のカッコの直後にセミコロン ; を置くミスです。これは「条件が true のとき何もしない」という空文として扱われ、その後ろの { }if と無関係なただのブロックになります。文法エラーにならないのでとくに厄介で、コードレビューで指摘されるまで気づかないことすらあります

if 文の基本で詳しく読む

else の前にセミコロン ; を入れる

if (n % 2 == 0) { ... }; のように } の後ろに ; を書いてしまうと、その時点で文が終わってしまい、続く else が孤立してエラーになります。} else { の前に余計な ; を入れない、これが鉄則です

if-else 文で詳しく読む

else に条件を書いてしまう (else if との混同)

else (n > 0) { ... } のように、else の後ろに丸カッコで条件を書こうとする間違いです。条件付きの else を書きたいときは else if (n > 0) { ... } のように else if と書きます。else 単体は条件を取らない、と覚えてください

if-else 文で詳しく読む

%== の優先順位の勘違い

n % 2 == 0 という式は % のほうが == より先に計算される ので、内部的には (n % 2) == 0 と評価されます。心配ならカッコを付けて (n % 2) == 0 と書いてもまったく問題ありません。むしろ可読性が上がるので、慣れないうちはカッコを付けるのもおすすめです

if-else 文で詳しく読む

else if で複数分岐

レッスンを読む

範囲の広い条件を上に書いてしまう

先ほどの grade の例。score >= 60 を一番上に書くと、95 点でも C 判定になります。厳しい条件を上、ゆるい条件を下 が鉄則

else if で複数分岐で詳しく読む

else ifelseif と書く

Java では elseif の 間に半角スペースが必要 です。elseif と続けて書くと ';' expected'else' without 'if' のようなコンパイルエラーになります。Pythonelif とも違うので注意

else if で複数分岐で詳しく読む

最後の else を忘れて return が足りない

ifelse if だけ書いて else を書かないと、戻り値のあるメソッドでは missing return statement のコンパイルエラーになります。最後は else でガッチリ閉じる、または if の外側で return を 1 本用意する

else if で複数分岐で詳しく読む

成績判定プログラム

レッスンを読む

>=> と書いてしまう

90 以上」のつもりで if (score > 90) と書くと、ちょうど 90 点が "A" ではなく "B" に落ちてしまいます。「以上」は >=、「より大きい」は >、と日本語と記号を必ずペアで覚えてください

成績判定プログラムで詳しく読む

条件の順序を逆にしてしまう

if (score >= 60) ... else if (score >= 70) ... のように下から並べると、70 点以上の人もみんな最初の score >= 60 でヒットしてしまい、"D" のままになります。else if チェーンは必ず狭い (厳しい) 条件から書く

成績判定プログラムで詳しく読む

範囲を重複させる

if (score >= 90)else if (score >= 80 && score < 95) のように、範囲が重なる書き方をすると、どちらにヒットするかが順番に依存してしまい、読む人を混乱させます。境界はきっちり閉じる

成績判定プログラムで詳しく読む

else を忘れて漏れを作る

else if (score >= 60) で止めて else を書かないと、50 点のときに "F" を返す経路がなくなり、コンパイラに「missing return statement」と怒られます。多段階の if の最後は必ず else で受ける

成績判定プログラムで詳しく読む

うるう年を判定する

レッスンを読む

%== の優先順位を勘違いする

year % 4 == 0 を「year % (4 == 0)」と解釈してしまう人がいますが、実際は % のほうが == より優先順位が高いので (year % 4) == 0 と評価されます。心配なときは自分で () を付けて意図を明確にしてもよいです

うるう年を判定するで詳しく読む

&&|| の優先順位を取り違える

&&|| より優先順位が高いです。a || b && ca || (b && c) の意味になります。うるう年式で (year % 4 == 0 && year % 100 != 0) のように カッコで囲んでいる のはこの理由で、可読性とミス防止のためにカッコを残すのがおすすめです

うるう年を判定するで詳しく読む

=== の打ち間違い

year % 4 == 0year % 4 = 0 と書くと「year % 40 を代入」しようとしてコンパイルエラーになります。比較は イコール 2 個、代入は イコール 1 個、と暗唱して指に覚えさせてください

うるう年を判定するで詳しく読む

break を忘れる

一番多いミス。case 1: の処理後に break; を書かないと、case 2: のブロックに勝手に流れ込みます。return で抜ける形なら起きませんが、System.out.println(...) などで終わる場合は 必ず break; を最後に書くこと

switch 文で詳しく読む

case の値の型ミスマッチ

switch (day)dayint なのに case "1": と書くと、incompatible types: String cannot be converted to int というエラーが出ます。case の値は switch の式と 同じ型 にする必要があります

switch 文で詳しく読む

default を書き忘れる

戻り値があるメソッドだと missing return statement のコンパイルエラーで気づけますが、void メソッドだと黙って通り抜けてバグの温床になります。default は常に書く習慣を付けましょう

switch 文で詳しく読む

switch 式 (Java 14+) との混同

Java 14 から追加された switch 式 は String s = switch (day) { case 1 -> "Monday"; ... }; のように -> (アロー) を使う新構文です。従来の switch 文 (case ... : + break;) とは別物で、構文を混ぜると ';' expected などのエラーが出ます。このレッスンでは古典的な switch 文の方を使います

switch 文で詳しく読む

三項演算子

レッスンを読む

?: の順番を逆にする

正しいのは 条件 ? 真の値 : 偽の値 の順番です。条件 : 真の値 ? 偽の値 のように書くとコンパイルエラーになります。「クエスチョン (?) が先、コロン (:) が後」と覚えましょう

三項演算子で詳しく読む

ネストして読めなくする

a ? b ? c : d : e ? f : g のような書き方は、構造を理解していてもパッと意味が取れません。3 段以上のネストは避けて if-elseswitch を使う

三項演算子で詳しく読む

両辺の型がずれてコンパイルエラー

? の後と : の後で型が違う (例: n >= 0 ? "正の数" : -n) と、Java は「結果の型がひとつに決まらない」と怒ります。文字列と数値を混ぜないように、両辺の型を必ず揃えましょう

三項演算子で詳しく読む

じゃんけんの勝敗判定

レッスンを読む

条件の網羅性が足りない

勝ちパターンを 2 つしか書かずに残り 1 つを忘れる、引き分けの判定を書き忘れる、といったケースです。テストケースを増やしてあげると、こういった抜けが必ず炙り出されます。先ほどの Mermaid 図のように、すべての分岐を絵にしてから書くと抜けが減ります

じゃんけんの勝敗判定で詳しく読む

||&& の使い間違い

me == 0 || opponent == 1 のように、本来 && で繋ぐべき条件を || で書いてしまうミスです。|| は どちらか片方でも true ならパスしてしまうので、「自分がグー」というだけで勝ち扱いになるなど、判定が壊滅的に狂います。「両方とも成り立つ必要があるなら &&、どれか 1 つでも成り立てばよいなら ||」と毎回声に出して確かめてください

じゃんけんの勝敗判定で詳しく読む

引き分けの検出忘れ

勝ちパターンだけ書いて、勝ちでなかったらすべて "lose" を返してしまうと、janken(1, 1) のような同じ手のときも "lose" になります。me == opponent をどこかで必ず判定する必要があります

じゃんけんの勝敗判定で詳しく読む

FizzBuzz の判定部分

レッスンを読む

判定順序を逆にする

if (n % 3 == 0) return "Fizz"; から書き始めてしまうと、15 のときも "Fizz" が返ってしまい、"FizzBuzz" の出番がなくなります。FizzBuzz (両方の倍数) を 必ず最初に 判定するのが鉄則です

FizzBuzz の判定部分で詳しく読む

String.valueOf を忘れて型エラー

─ 戻り値の型は String なのに、return n; と書いてしまうと「intString として返せません」というコンパイルエラーになります。整数を文字列にしたいときは String.valueOf(n)Integer.toString(n) を使うか、もしくは return "" + n; のように空文字と連結する手もあります

FizzBuzz の判定部分で詳しく読む

% 3 && % 5 のような略記を使う

n % 3 && n % 5 のように書きたくなる人がいますが、これは文法エラーです。&& の左右には boolean が必要なので、必ず n % 3 == 0 && n % 5 == 0 のように == 0 まで 書いてください

FizzBuzz の判定部分で詳しく読む

for 文の基本

レッスンを読む

区切り文字をカンマにしてしまう

for (int i = 0, i < 10, i++) のようにカンマで区切るのは間違いで、正しくはセミコロン ; です

for 文の基本で詳しく読む

条件と更新を逆にして無限ループ

for (int i = 0; i < 10; i--) のように更新が逆向きだと i が永遠に増えないので、ループが終わりません。chotdekiru の Java Playground では 5 秒の実行制限で強制終了されますが、本番環境では CPU を食い続けてシステムが固まります

for 文の基本で詳しく読む

ループ変数をループの外で使ってしまう

for (int i = 0; i < 10; i++)i は丸カッコ内で宣言されているので、for ブロックの外では使えません

for 文の基本で詳しく読む

1 から N までの合計

レッスンを読む

sum を初期化せずに使う

int sum; とだけ書いて sum = sum + i; をやると、Java のコンパイラに「variable sum might not have been initialized」と怒られます。初期値 0 を必ず書きましょう

1 から N までの合計で詳しく読む

継続条件を i < n にしてしまう

i < n だと最後の n が足されません。sumOneToN(10) の答えが 55 ではなく 45 になります。<=< の違いで結果がガラッと変わるので、ループ条件を書いたら頭の中で「i は最後にいくつまで到達するか?」を必ず確認するクセをつけましょう

1 から N までの合計で詳しく読む

int の桁あふれ (overflow)

n がとても大きい (100000 以上など) と、合計が int の最大値 約 21 億 を超えて、マイナスの数になってしまうことがあります。今回の課題では n は小さいので気にしなくて OK ですが、本格的な数値計算では long 型を使うのが安全です

1 から N までの合計で詳しく読む

九九の段を作る

レッスンを読む

0 から始める / 1 から始めるの混同

九九は n * 1 から n * 9 までです。for (int i = 0; i < 9; i++) と書くと i は 0〜8 になり、n * 0 = 0 が先頭に入ってしまいます。今回は i = 1; i <= 9; i++ が正解です

九九の段を作るで詳しく読む

末尾の余計な空白

result = result + value + " "; のように書くと、最後の値の後ろにも空白が残ります。テストは "3 6 9 12 15 18 21 24 27" のように末尾に空白なしを期待しているので、if (i == 1) で分岐するか、if (i > 1) で先に空白を入れるパターンを使いましょう

九九の段を作るで詳しく読む

in の取り違え

文字列に並べるのは n * i の結果であって、i そのものではありません。うっかり result = result + i; と書くと "1 2 3 4 5 6 7 8 9" がいつも返ってきてしまい、n = 3 でも n = 7 でも同じ出力になります

九九の段を作るで詳しく読む

条件を更新し忘れて無限ループ

while (n > 0) { count = count + 1; } のように n を更新する行を書き忘れると、n は永遠に正のままで、count だけが増え続けます。Java の executor では 5 秒で強制終了されますが、本物のアプリでは画面が固まって最悪のユーザー体験になります。ループの中で「条件に関係する変数を必ず変える」のは絶対のルールです

while 文で詳しく読む

初期値を境界の外に置いてしまう

int count = 1; のように count を最初から 1 にしてしまうと、すべての結果が +1 ずれます。「ループに入る前に何回実行したことになっているか」をいつも意識して、初期値を決めましょう

while 文で詳しく読む

エッジケース (0 や負の数) を考えていない

今回は 01 桁として扱う仕様でしたが、これに気づかず while (n > 0) だけで提出すると、digitCount(0)0 を返してテスト失敗です。仕様の境界値は必ずテストケースに混ぜて、コードを書く前に紙に書き出すクセをつけましょう

while 文で詳しく読む

カウントダウン

レッスンを読む

終了条件の > 0>= 1 の混同

整数の n であればどちらも結果は同じですが、n > 0 と書くつもりで n >= 0 と書いてしまうと、0 までカウントが進んで "3 2 1 0" のように余計な 0 が混ざります。>= 1> 0 のどちらかで意図を統一しましょう

カウントダウンで詳しく読む

n-- の位置を間違えて無限ループ

result = result + n + " "; の 前 に n-- を書いてしまうと、最初の値 n が結果に入らないまま 1 減って、想定とずれた文字列になります。さらに n-- 自体を書き忘れると n が永遠に減らず無限ループです

カウントダウンで詳しく読む

末尾に余計な空白が残る

result + n + " " で連結すると、必ず最後にスペースが 1 つ余ります。"3 2 1 " のように末尾に空白が残った状態のままだと、テストの "3 2 1" と一致せず fail します。trim() で末尾の空白を必ず削ること

カウントダウンで詳しく読む

do { ... } while (条件) の末尾セミコロン忘れ

do { ... } while (n <= 0) で終わると「; expected」というコンパイルエラーになります。do-while は文の最後に 必ず ; を付けるのがルールです。while 文と違うところなので意識して書きましょう

do-while 文で詳しく読む

条件の方向を逆にする (上昇 vs 下降)

「正の数を見つける」課題なのに while (n > 0); と書いてしまうと、最初から正の数だったときに即終わり、負だったときは無限ループになります。「ループを 続ける ための条件」を書く、という基本に立ち戻ってください。n を上昇させて正を探すなら、ループ継続条件は n <= 0 (まだ正でない間続ける) です

do-while 文で詳しく読む

更新を忘れて無限ループ

do { ... } while (n <= 0); の中で n++ を書き忘れると、n がずっと初期値のままで条件が変わらず、永遠にループします。Java の Playground では実行が 5 秒で打ち切られますが、本番システムでこれをやると CPU 100% でサーバーが落ちます。ループ本体で必ず変数を更新する を呪文にしてください

do-while 文で詳しく読む

二重ループ

レッスンを読む

ij を混同する

内側で書きたいのに i++ と書いてしまうと、外側のカウンタを勝手にいじることになり、無限ループや想定外の動作になります。「外側 i、内側 j」と最初に決めてから書きましょう

二重ループで詳しく読む

内側ループ後の改行を忘れる

1 行ぶんの * を並べたあとに \n を追加しないと、全部が 1 行につながって *** のような出力になります。改行は内側ループの「外」、外側ループの「中」**が定位置です

二重ループで詳しく読む

末尾に余計な改行が付く

pyramid(3) の期待値は "*\n\n*" で、末尾の \n はありません。毎回改行を付けてしまうと最後にも 1 つ余分に付き、テストが fail します。if (i < n - 1) で最後の行だけ改行をスキップするか、改行を行の「先頭」に置いて 1 行目だけスキップするテクニックを使いましょう

二重ループで詳しく読む

break と continue

レッスンを読む

breakreturn を混同する

break はループから抜けるだけで、メソッド自体は終わりません。一方 return はメソッドそのものを終了します。「ループの外でまだ処理を続けたいなら break、メソッドごと終わらせたいなら return」と使い分けてください。「break を書いたのに return まで処理が来てしまった」と慌てる人が多いですが、それは break の正しい動きです

break と continueで詳しく読む

continue で更新を忘れて無限ループ

while ループの中で continue を使うとき要注意です。int i = 0; while (i < 10) { if (i == 3) continue; i++; } のように、continue の前にループ変数を更新していないと、i = 3 のところで永遠に止まります。for ループなら更新式が自動的に走るので比較的安全ですが、while のときは continue の前に必ず更新を済ませる、または continue の中でも更新する書き方を意識しましょう

break と continueで詳しく読む

ラベル付き break の構文ミス

ラベルは outer: のように : をつけて for の 直前の行に単独で 書きます。for outer:outer for のような書き方はコンパイルエラーです。break outer; の側はラベル名のあとに空白を入れて、最後に ; で締めます。たまにしか使わない構文なので、必要なときは公式ドキュメントで形を確認してください

break と continueで詳しく読む

FizzBuzz 完成

レッスンを読む

判定順序を逆にする

─ 前章でも触れた話ですが、if (i % 3 == 0) を最初に書いてしまうと 15 のときも "Fizz" が返ってしまい、"FizzBuzz" が一度も出てきません。必ず i % 15 == 0 を最初に判定する か、i % 3 == 0 && i % 5 == 0 を最初に書きましょう

FizzBuzz 完成で詳しく読む

末尾のスペースを取り忘れる

"1 2 Fizz 4 Buzz " のように末尾にスペースが残ると、テストの期待値 "1 2 Fizz 4 Buzz" と異なり fail します。trim() で取り除くか、最初から先頭判定方式で書きましょう

FizzBuzz 完成で詳しく読む

n0 のときに何が返るかを考えていない

─ もし fizzbuzzList(0) が呼ばれたら、for は 1 回も回らず result"" のまま trim() を経て空文字列が返ります。今回のテストでは n >= 1 しか使いませんが、業務コードなら エッジケース として「0 のときに何を返すべきか」を意識しておくとバグが減ります

FizzBuzz 完成で詳しく読む

メソッドを定義する

レッスンを読む

戻り値型を void にしているのに値を return してしまう

void は「戻り値なし」の意味なので、return "Hello"; のように値を返すとコンパイルエラーになります。値を返したいなら戻り値型を Stringint に変更しましょう

メソッドを定義するで詳しく読む

return; だけ書いて値を返し忘れる

逆に戻り値型を String にしているのに return; とだけ書くと「missing return value」エラーが出ます。戻り値の型に合った値を必ず指定してください

メソッドを定義するで詳しく読む

static の付け忘れ

chotdekiru の coding 問題は Solution.getGreeting() のように、クラス名から直接呼び出します。static を忘れるとインスタンス化が必要なメソッドになってしまい、テスト側から呼べずに fail します

メソッドを定義するで詳しく読む

引数を受け取るメソッド

レッスンを読む

引数の型を省略する

public static int square(n) のように int を書き忘れると、Java は「n の型がわからない」と怒ります。引数は 必ず型から書く、と覚えましょう。同じ理由で int a, b ではなく int a, int b のように毎回型を書きます

引数を受け取るメソッドで詳しく読む

引数の数を間違えて呼び出す

メソッド側が square(int n) のように 1 個の引数を期待しているのに、呼び出し側で Solution.square() (引数なし) や Solution.square(3, 4) (引数 2 個) と書くと、method square in class Solution cannot be applied to given types のようなエラーが出ます。引数の 個数と型 が完全に一致していないとコンパイルは通りません

引数を受け取るメソッドで詳しく読む

変数名が衝突すると思い込む

呼び出し側に int n = 5; という変数があると、「メソッド側の n と被るからダメなんじゃない?」と心配する人がいます。実際には別物として扱われるので、まったく問題ありません。むしろ呼び出し側でもメソッド側でも、その場で自然な名前を使うほうが読みやすいコードになります

引数を受け取るメソッドで詳しく読む

戻り値を返す

レッスンを読む

return 文を書かない

戻り値の型を Stringint と書いたのに、メソッド本体のどこにも return がないパターン。エディタのエラー欄に「missing return statement」と出たら、まず全ての分岐に return が届いているか確認しましょう。ifreturn して elsereturn しないと、それだけで未到達の分岐ができてしまいます

戻り値を返すで詳しく読む

return の後にコードを書く (dead code)

return 0; の次の行に System.out.println("...") のような処理を書いてしまうやつ。デバッグ用の println を消し忘れる事故が多いです。return の後に書いてあるコードは絶対に動きません

戻り値を返すで詳しく読む

戻り値型と return 値の型不一致

int を返すと書いたのに "123" のような String を返してしまうケース。逆に String を返すメソッドで return 0; と書いてしまうのもよくあります。エラー「incompatible types」「cannot return a value of type X」が目印

戻り値を返すで詳しく読む

複数の引数を取るメソッド

レッスンを読む

引数の順序を逆に渡す

rectangleArea(width, height) のつもりが rectangleArea(height, width) で呼んでしまうケース。長方形の面積では結果が同じなので気づきにくいですが、drawRect(x, y, width, height) のような関数では位置がズレて図形が変な場所に描かれます。呼び出すときは「メソッド宣言と同じ順番で書けているか」を必ず確認してください

複数の引数を取るメソッドで詳しく読む

型を 1 個だけ書く

int width, height のように書いて、int width, int height と書き忘れるパターン。Java のコンパイラから ';' expected <identifier> expected といった分かりにくいエラーが出ます。引数 1 個ごとに型を書く、を呪文として唱えてください

複数の引数を取るメソッドで詳しく読む

引数 0 個のメソッドと混同する

1 つ前のレッスンで書いた helloWorld() のような引数なしメソッドの感覚で、rectangleArea() と引数を渡さずに呼び出してしまうケース。コンパイラから method rectangleArea in class Solution cannot be applied to given types と長いエラーが出ます。引数を必要とするメソッドは、呼び出すときも同じ数だけ値を渡す必要があります

複数の引数を取るメソッドで詳しく読む

配列の基本

レッスンを読む

1 始まりと勘違いする

数学やスプレッドシートに慣れていると、最初の要素を arr[1] と書きたくなります。Java のインデックスは 0 始まりなので、最初は arr[0]、最後は arr[arr.length - 1] です。arr[arr.length] と書くと off-by-one エラー で ArrayIndexOutOfBoundsException になります

配列の基本で詳しく読む

length をメソッド呼び出しで書く

arr.length() と書きたくなりますが、配列の length は プロパティ なのでカッコは付けません。Strings.length() (カッコあり) との違いが地味に厄介で、コンパイラに cannot find symbol と怒られたら大抵これです

配列の基本で詳しく読む

null チェックを忘れる

int[] arr = null; の状態で arr.lengtharr[0] を触ると、即 NullPointerException で落ちます。引数で受け取る配列は、信頼できないなら if (arr == null) のチェックを先に入れる癖をつけましょう

配列の基本で詳しく読む

配列の要素にアクセス

レッスンを読む

負のインデックスを渡す

一部の言語 (例えば Python) では arr[-1] で末尾要素が取れますが、Java では 負のインデックスはすべて例外。便利機能はないので、自分で arr.length - 1 を書く必要がある

配列の要素にアクセスで詳しく読む

配列を for で走査

レッスンを読む

i < arr.lengthi <= arr.length にしてしまう

配列の添字は 0 から arr.length - 1 までです。i <= arr.length だと最後の周で arr[arr.length] という存在しない要素にアクセスし、ArrayIndexOutOfBoundsException で落ちます。継続条件は必ず <、と決めてしまうのが安全です

配列を for で走査で詳しく読む

末尾に余計な , が残る

result = result + arr[i] + ", "; のように書くと、最後の要素の後ろにもカンマと空白が付いてしまい、"1, 2, 3, " のような出力になります。テストはこれを fail と判定します。先頭だけ特別扱い (if (i > 0) で前に ", ") で組み立てるのが定番のテクニックです

配列を for で走査で詳しく読む

空配列の処理を忘れる

arr.length0 の場合に何を返すかを考えていないと、NullPointerException や思わぬ文字列を返してしまうことがあります。今回の課題では空配列は "" を返す決まりです。for (int i = 0; i < arr.length; i++) パターンなら自然にループをスキップしてくれるので、安心して使えます

配列を for で走査で詳しく読む

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

レッスンを読む

null チェックを書きすぎる / 書かなさすぎる

今回の課題では arrnull で渡されることは想定していませんが、実務だと null が来る可能性があります。安全側に倒すなら if (arr == null) return 0; を冒頭に書きます。逆に「null ではなく空配列で渡す」と決めたなら、書く必要はありません。呼び出し側との契約をはっきりさせる ことが、null を巡るバグを防ぐ一番のコツです

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

配列の平均

レッスンを読む

整数除算のままにしてしまう

return sum / arr.length; と書くと戻り値の型が double でも、右辺の int / int の結果 intdouble に変換されるだけです。arrayAvg(new int[]{4, 7})5.5 を期待しているのに 5.0 が返ってきて「あれ?」となります。割り算の前に、片方を (double) でキャスト しましょう

配列の平均で詳しく読む

キャストの位置を間違える

(double)(sum / arr.length) は意味がありません。括弧の中で先に int の割り算が走ってしまうからです。(double) sum / arr.length のように、キャストは割り算の左側の値だけに掛けるのが正解です

配列の平均で詳しく読む

空配列を素通りさせる

if (arr.length == 0) return 0.0; を忘れると、arr.length0 のとき sum / 0 を計算しようとして ArithmeticExceptionNaN が出てきます。割る前に必ず分母が 0 でないかをチェックするのが鉄則です

配列の平均で詳しく読む

配列の最大値

レッスンを読む

max = 0 で初期化して負の数で失敗

int max = 0; で始めると、配列が [-1, -5, -3] のように 全要素がマイナス のとき、答えが 0 になってしまいます。実際の最大値は -1 なのに、です。max の初期値は arr[0] または Integer.MIN_VALUE にするのが鉄則です

配列の最大値で詳しく読む

空配列で IndexOutOfBoundsException

int max = arr[0]; を書いた直後に、空配列 [] が渡されると、arr[0] にアクセスした瞬間に例外が飛びます。必ず if (arr.length == 0) return 0; のような 空配列ガード を先頭に置いてください

配列の最大値で詳しく読む

>=> の違い

更新条件を arr[i] >= max と書いても答え自体は同じになりますが、>= だと「同じ値」に出会うたびに上書きが走るので、わずかに余計な代入が発生します。> で「より大きいときだけ更新する」のが教科書的な書き方です

配列の最大値で詳しく読む

配列の線形探索

レッスンを読む

見つかった後もループを続けてしまう

for の中で return i; ではなく、int found = i; のように変数に保存するだけにしてしまうと、後ろにある同じ値で found が上書きされてしまうことがあります。「先頭から見て 最初 に見つかった位置」という仕様なので、見つけた瞬間に return で抜けるのが正解です。どうしてもループの後で返したい場合は、見つかった時点で break; してから return found; する形にしましょう

配列の線形探索で詳しく読む

index の初期化忘れ / 初期化ミス

拡張 for で書くときに int index = 0; の宣言を忘れると cannot find symbol のコンパイルエラーになります。逆に int index = -1; から始めてしまうと、arr[0]target と一致したときに -1 が返ってしまい、テストが fail します。初期値は 0 が正解です

配列の線形探索で詳しく読む

複数一致の挙動を取り違える

arr = [10, 20, 10, 20]target = 10 の答えは、0 (最初の 10) であって 2 (後ろの 10) ではありません。普通の for ループで先頭から return する書き方になっていれば自然に 0 が返りますが、「最後に一致した index を返したい」と仕様を勘違いすると 2 を返すコードを書いてしまいます。仕様を読むときに「最初」「最後」「全部」のどれを期待されているか必ず確認するクセを付けましょう

配列の線形探索で詳しく読む

拡張 for ループ

レッスンを読む

for-each で要素を書き換えたつもりになる

for (int x : arr) { x = ... } は元の配列に反映されない。書き換えたいときは通常の for 文を使い、arr[i] に直接代入する

拡張 for ループで詳しく読む

コロン : の代わりにカンマやセミコロンを使う

通常の for 文の影響で for (int x ; arr)for (int x , arr) と書いてしまう。正しいのは コロン : 一文字 で、それ以外は全部コンパイルエラー

拡張 for ループで詳しく読む

要素の型を間違える

int[] の配列に対して for (String x : arr) とやると incompatible types のエラーになる。要素の型と一致させる必要があり、自信がなければ var (Java 10 以降) でコンパイラに推論させるのも手

拡張 for ループで詳しく読む

クラスを定義する

レッスンを読む

クラス名を小文字で始める

public class book { ... } のように小文字で書くとコンパイル自体は通ってしまうことがあるものの、Java の世界ではクラス名を小文字で始めるのは強い アンチパターン です。チームのコードレビューでも一発で指摘されます。必ず Book のように大文字始まりで書きましょう

クラスを定義するで詳しく読む

ファイル名とクラス名が食い違う

Book.java の中に public class Library { ... } と書くと、class Library is public, should be declared in a file named Library.java というエラーで止まります

クラスを定義するで詳しく読む

クラスにフィールドを持たせる

レッスンを読む

クラスにメソッドを定義する

レッスンを読む

static を付けたり外したりを間違える

クラス内のフィールドを使うインスタンスメソッドに static を付けると、non-static field cannot be referenced from a static context というエラーが出ます。逆にユーティリティ的な計算なのに static を外すと、毎回 new してから呼ばないといけなくなり不便です。「フィールドに触るかどうか」で判断しましょう

クラスにメソッドを定義するで詳しく読む

this を使わずに引数とフィールドを混同する

メソッドの引数とフィールドが同じ名前のとき、title = title; と書いても何も起きません (引数が引数に代入されているだけ)。this.title = title; のように、フィールド側だけ this. を付けて区別する必要があります

クラスにメソッドを定義するで詳しく読む

戻り値の型と return の値がずれる

メソッドの宣言が public String getDescription() なのに return 123; と書くとコンパイルエラーです。戻り値の型と return で返す値の型は必ず一致させてください。何も返さないなら戻り値型を void に変える、というルールも忘れずに

クラスにメソッドを定義するで詳しく読む

インスタンスを作る

レッスンを読む

new を書き忘れる

Book b = Book(); のように new を抜いてしまうと、「Book という名前のメソッドを呼ぼうとした」と解釈されてコンパイルエラーになります。インスタンスを作るときは必ず new を先頭に付けてください

インスタンスを作るで詳しく読む

変数宣言と new を混同する

Book b; だけで終わってしまうと、変数 b は宣言されていますが中身は null のままです。この状態で b.read() を呼ぶと実行時に NullPointerException が飛んできます。必ず = new Book(); まで書ききりましょう

インスタンスを作るで詳しく読む

static メソッドをインスタンスから呼ぼうとする

Solution.helloWorld() のような static メソッドは、本来クラス名から呼ぶものです。インスタンスを作って s.helloWorld() と書いてもエラーにはなりませんが、警告が出るうえに意味も薄れます。static はクラス、それ以外はインスタンス、と使い分けましょう

インスタンスを作るで詳しく読む

コンストラクタ

レッスンを読む

コンストラクタに戻り値型を書いてしまう

public void Book(...) public String Book(...) のように voidString を入れてしまうと、Java のコンパイラはそれを 同じ名前のただのメソッド として扱います。引数付きで new Book("x", "y") のように呼ぼうとするとコンパイルエラーになります(コンストラクタとして認識されるものが引数なしのデフォルトコンストラクタしかないため)。一方、引数なしで new Book() と呼んだ場合はデフォルトコンストラクタが動くものの、フィールドは初期化されないままになります。public ClassName(...) { の形を厳守してください

コンストラクタで詳しく読む

複数コンストラクタの解決ミス

public Book(String title)public Book(String title, String author) の両方を用意した状態で new Book("Java入門") と呼ぶと、引数 1 個の方が選ばれます。new Book("Java入門", null) を呼ぶと 2 引数の方が選ばれ、authornull のまま fullTitle() を実行すると null が出力に混ざります。引数の数と意味は、コンストラクタを増やすたびに丁寧に確認しましょう

コンストラクタで詳しく読む

デフォルトコンストラクタが消えていることに気づかない

─ 自分で public Book(String title, String author) を 1 つ追加した瞬間、new Book() は使えなくなります。テストコードや別ファイルでまだ new Book() を呼んでいると、constructor Book in class Book cannot be applied to given types というエラーが出ます。引数なしも使いたいなら、public Book() {} を明示的に書き足してください

コンストラクタで詳しく読む

this キーワード

レッスンを読む

static メソッドの中で this を使ってしまう

public static String describe() の中で this.title と書くと「non-static variable this cannot be referenced from a static context」と怒られます。static メソッドはクラス全体に属するので、「自分自身のインスタンス」が存在しません。インスタンスメソッド (static が付かないメソッド) でだけ this が使えます

this キーワードで詳しく読む

this を省略したつもりが、ローカル変数を上書きしてしまう

Book(String title) { title = title; } のように書くと、引数 title を引数自身に代入するだけでフィールドは空のまま。フィールドへ書き込みたいときは必ず this.title = title; と書くか、引数名を変える (_title newTitle など) ようにします

this キーワードで詳しく読む

コンストラクタで this(...) を 2 行目以降に書く

this(...) はコンストラクタの 先頭行 でなければなりません。何か別の処理を挟むと「call to this must be first statement in constructor」というエラーになります。共通処理は this(...) で呼ばれる側のコンストラクタにまとめるのが鉄則です

this キーワードで詳しく読む

カプセル化 (private と getter)

レッスンを読む

フィールドをついつい public にしてしまう

書き始めのうちは、public int balance; のほうがコード量が少なくて楽に感じます。けれどそれは「これから先、誰かが変な値を入れても止められない」という時限爆弾を埋めている状態です。フィールドは原則 private、必要に応じて getter / setter を足す という順番を体に染み込ませてください。Java の世界では「private が当たり前、public フィールドは要相談」が共通認識です

カプセル化 (private と getter)で詳しく読む

getter / setter を機械的に全フィールドに作る

IDE の自動生成でフィールドの数だけ getter / setter が並ぶと、見た目はリッチですが、実質的には public フィールドと同じ「中身を素通しできるクラス」になりがちです。setter は「外から自由に書き換えてほしい場合だけ」用意する、それ以外は読み取り専用にする (getter だけ作る)、という判断をするとカプセル化が一段強くなります。balance のように外から直接いじらせたくない値には、deposit(int) withdraw(int) のような 意図のあるメソッド を用意するのが理想です

カプセル化 (private と getter)で詳しく読む

ボイラープレートだらけのクラスになって本質が埋もれる

private フィールドと getter / setter を律儀に書いていくと、Java のコードはどうしても縦に長くなります。意味のあるロジックが 1 行なのに、その周りに 50 行のボイラープレートがついている、ということもよくあります。これを Lombok@Getter @SetterJava 16 以降の record で短く書く、というテクニックもありますが、まずは「カプセル化は手間に見合った価値がある」と感じてもらえる程度の手書きに慣れることが大事です

カプセル化 (private と getter)で詳しく読む

Person クラスを作る

レッスンを読む

フィールドの初期化漏れ

フィールドだけ宣言して、コンストラクタの中で this.name = name; を書き忘れるパターン。コンパイルは通ってしまうのに、introduce() を呼ぶと namenull のままで "null (0)" のような結果が返ってきます。Java では String のフィールドは初期値 nullint のフィールドは初期値 0 になる仕様なので、入れ忘れに気づきにくいのが厄介です

Person クラスを作るで詳しく読む

コンストラクタなしで放置する

コンストラクタを 1 つも書かないと、Java が自動で 引数なしのデフォルトコンストラクタ を作ってしまいます。すると new Person("太郎", 25) という書き方ができず、コンパイラから constructor Person in class Person cannot be applied to given types と怒られます。引数付きで初期化したいなら、その引数を取るコンストラクタを必ず自分で書く のが鉄則です

Person クラスを作るで詳しく読む

equals を実装していないのに == で比較する

2 人の Person を比べたくて taro == hanako のように == で書くと、Java は メモリ上の同じ場所を指しているか だけを見ます。中身が同じでも new で別々に作っていれば結果は false です。中身を比べたいときは equals メソッドを自分で実装する必要があります

Person クラスを作るで詳しく読む

toString のオーバーライド

レッスンを読む

@Override アノテーションを忘れる

付け忘れてもコンパイル自体は通ってしまうので、気づかずにメソッド名を tostring と書き間違えても、コンパイラは何も言ってくれません。すると toString() は親の実装が呼ばれ続け、いつまで経っても Point@1540e19d のままで「あれ、書いたはずなのに反映されない」とハマります。@Override を付けておけば、コンパイル時に即エラーで教えてくれます

toString のオーバーライドで詳しく読む

引数を勝手に増やしてしまう

Object.toString()引数なし のメソッドです。これを public String toString(int n) のように引数付きにしてしまうと、それは別のメソッドの オーバーロード (overload) になり、オーバーライド にはなりません。@Override を付けていればコンパイラが「親クラスに引数 inttoString はない」と教えてくれます

toString のオーバーライドで詳しく読む

戻り値の型を間違える

Object.toString() の戻り値は String です。これを void にしたり、Object にしたりすると、String 以外の戻り値を持つメソッドはオーバーライドとして認められません。やはり @Override を付けておけばコンパイラが守ってくれます

toString のオーバーライドで詳しく読む