- JAVA
Java メソッドの定義と書き方|引数・戻り値・呼び出しをコード付きで解説
Javaのメソッドとは、ひとまとまりの処理に名前を付けて、何度でも呼び出せるようにしたものです。修飾子 戻り値の型 メソッド名(引数) { 処理 } の形で定義し、メソッド名(値) で呼び出します。 入力として受け取る値を「引数」、結果として返す値を「戻り値」と呼びます。
この記事では、定義の各パーツの意味、void・戻り値あり・static・インスタンスの4パターン、引数の渡し方、オーバーロードまでを1ページで説明します。サンプルはすべてOpenJDK 21.0.10で java ファイル名.java として動かし、実行結果とコンパイルエラーのメッセージをそのまま載せています。 プリミティブ型と配列・オブジェクトを渡したときの動きの違いも、出力で確かめられます。
メソッド定義の早見表
まず、定義の各パーツです。public static int add(int a, int b) を例にします。
| パーツ | 例 | 役割 | 省略 |
|---|---|---|---|
| アクセス修飾子 | public |
どこから呼べるかを決める(public/protected/指定なし/private) | できる(同じパッケージ内から呼べる扱いになる) |
| static | static |
インスタンスを作らずに呼べるメソッドにする | できる(付けないとインスタンスメソッドになる) |
| 戻り値の型 | int |
返す値の型。返さないときは void |
できない |
| メソッド名 | add |
呼び出すときの名前。小文字始まりで動詞から書くのが慣例 | できない |
| 引数リスト | (int a, int b) |
受け取る値の型と名前。なければ () |
かっこは必須 |
| 本体 | { return a + b; } |
実行する処理 | できない(抽象メソッドなどを除く) |
次に、よく使う4パターンと呼び出し方です。
| パターン | 定義の例 | 呼び出し方 | 戻り値の扱い |
|---|---|---|---|
| static・戻り値なし | static void printLine() |
printLine(); |
なし |
| static・戻り値あり | static int triple(int n) |
int x = triple(7); |
変数に入れる、式の中で使う |
| インスタンス・戻り値なし | void rename(String s) |
t.rename("B"); |
なし |
| インスタンス・戻り値あり | String label() |
String s = t.label(); |
変数に入れる、式の中で使う |
頻出のコンパイルエラーと直し方も先にまとめます(詳しい再現は後半にあります)。
| メッセージ | 主な原因 | 直し方 |
|---|---|---|
missing return statement |
値を返さずに終わる道がある | すべての道にreturnを書く |
incompatible types: String cannot be converted to int |
返す値の型が戻り値の型と違う | 型をそろえる、変換する |
incompatible types: unexpected return value |
voidメソッドで値を返している | 戻り値の型を書き直す |
method ... cannot be applied to given types |
引数の個数や型が定義と合わない | 定義どおりの個数・型で呼ぶ |
non-static method ... cannot be referenced from a static context |
mainなどのstaticメソッドからインスタンスメソッドを直接呼んだ | staticを付ける、またはnewしてから呼ぶ |
'void' type not allowed here |
voidメソッドの結果を値として使った | 戻り値のあるメソッドにする |
cannot find symbol |
メソッド名の書き間違い、別メソッドのローカル変数を参照 | 名前を確かめる、戻り値で受け取る |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Java メソッドの定義と書き方|引数・戻り値・呼び出しをコード付きで解説」
メソッドの定義と呼び出しの基本
メソッドはクラスの中、ほかのメソッドの外に書きます。 いちばん短い完成形はこちらです。
public class FirstMethod {
// メソッドの定義:2つの整数を足して返す
static int add(int a, int b) {
int sum = a + b;
return sum;
}
public static void main(String[] args) {
int result = add(3, 5); // メソッドの呼び出し
System.out.println("3 + 5 = " + result);
System.out.println("10 + 20 = " + add(10, 20));
}
}
$ java FirstMethod.java
3 + 5 = 8
10 + 20 = 30
用語を整理します。
| 用語 | 上の例での該当箇所 | 意味 |
|---|---|---|
| 仮引数 | int a, int b |
定義側で書く、値の受け皿になる変数 |
| 実引数 | 3, 5 や 10, 20 |
呼び出し側で渡す実際の値 |
| 戻り値 | sum の値(8や30) |
メソッドが呼び出し元へ返す値 |
| シグネチャ | add(int, int) |
メソッド名と引数の型の並び。メソッドを見分ける単位 |
add(3, 5) と書いた場所は、メソッドの実行が終わると戻り値(8)に置き換わると考えるとわかりやすくなります。そのため、変数に代入することも、println の中に直接書くこともできます。
メソッドを使う理由
| 利点 | 内容 |
|---|---|
| 同じ処理を1か所にまとめられる | 修正するときに直す場所が1つで済む |
| 処理に名前が付く | withTax(price) のように、何をしているかが名前で伝わる |
| mainメソッドが短くなる | 全体の流れを上から読める |
| 部品ごとに確かめられる | 引数を変えて呼ぶだけで動きを確認できる |
呼び出しの流れと書く順番
メソッドは、定義した順ではなく呼び出した順に実行されます。mainより下に定義しても呼び出せます。
public class Order {
public static void main(String[] args) {
System.out.println("main 開始");
int price = total(120, 3);
System.out.println("合計 " + price);
System.out.println("main 終了");
}
// main より下に書いても呼び出せる
static int total(int unit, int qty) {
System.out.println(" total 開始");
int sub = unit * qty;
int result = withTax(sub);
System.out.println(" total 終了");
return result;
}
static int withTax(int amount) {
System.out.println(" withTax 実行");
return amount * 110 / 100;
}
}
main 開始
total 開始
withTax 実行
total 終了
合計 396
main 終了
sequenceDiagram
participant main
participant total
participant withTax
main->>total: total(120, 3)
total->>withTax: withTax(360)
withTax-->>total: 396
total-->>main: 396
呼び出されたメソッドが終わると、呼び出した行の続きへ戻ります。 メソッドの中から別のメソッドを呼ぶこともでき、内側から順に戻ってきます。
4つのパターンを実行結果で確かめる
メソッドは「staticか、インスタンスか」と「戻り値がないか、あるか」の組み合わせで4パターンに分けられます。 1つのクラスに4つとも書いて動かします。
public class FourPatterns {
private String name = "タスクA"; // インスタンスが持つデータ
// 1. static・戻り値なし(void)
static void printLine() {
System.out.println("--------");
}
// 2. static・戻り値あり
static int triple(int n) {
return n * 3;
}
// 3. インスタンスメソッド・戻り値なし(void)
void rename(String newName) {
this.name = newName;
}
// 4. インスタンスメソッド・戻り値あり
String label() {
return "[" + name + "]";
}
public static void main(String[] args) {
printLine(); // 1. そのまま呼ぶ
System.out.println(triple(7)); // 2. 戻り値を使う
System.out.println(FourPatterns.triple(4)); // クラス名.メソッド名 でも呼べる
FourPatterns t = new FourPatterns(); // インスタンスを作る
System.out.println(t.label()); // 4. 変数名.メソッド名
t.rename("タスクB"); // 3. 中のデータを書き換える
System.out.println(t.label());
printLine();
}
}
--------
21
12
[タスクA]
[タスクB]
--------
voidと戻り値ありの違い
| 観点 | void(戻り値なし) | 戻り値あり |
|---|---|---|
| 戻り値の型の位置に書くもの | void |
int、String、boolean、配列、クラス名など |
| returnの書き方 | 省略できる。途中で終えるなら return; |
return 値; が必須 |
| 呼び出し側 | printLine(); と文として書く |
int x = triple(7); のように結果を使う |
| 向いている処理 | 表示する、保存する、状態を書き換える | 計算する、判定する、変換する |
戻り値のあるメソッドでも、triple(7); のように結果を使わずに呼ぶことはできます(その場合、戻り値は捨てられます)。
staticメソッドとインスタンスメソッドの違い
| 観点 | staticメソッド | インスタンスメソッド |
|---|---|---|
| 定義 | static を付ける |
static を付けない |
| 呼び出し方 | メソッド名() または クラス名.メソッド名() |
変数名.メソッド名()(先にnewが必要) |
| 使えるデータ | 引数とstaticフィールド | 引数に加えて、そのインスタンスのフィールド(this) |
| 向いている処理 | 引数だけで結果が決まる計算・変換 | インスタンスが持つデータを読み書きする処理 |
| 標準ライブラリの例 | Math.max(3, 5)、Integer.parseInt("12") |
"abc".length()、list.add(x) |
「引数だけで結果が決まるか」が見分ける目安です。 triple(7) は引数の7だけで21が決まるのでstatic、label() はどのインスタンスかによって結果が変わるのでインスタンスメソッドにしています。学び始めのうちは、mainメソッドと同じクラスに static を付けて書くと、そのまま呼び出せて動きを確かめやすくなります。
引数の書き方
引数は「型 名前」をカンマで区切って並べます。呼び出すときは、定義と同じ順番・同じ個数・合う型で値を渡します。
public class Args {
// 引数なし
static String greet() {
return "こんにちは";
}
// 引数1つ
static String greet(String name) {
return "こんにちは、" + name + "さん";
}
// 引数2つ(型が違う)
static String repeat(String s, int times) {
return s.repeat(times);
}
// 可変長引数(0個以上の int を受け取る)
static int sum(int... nums) {
int total = 0;
for (int n : nums) {
total += n;
}
return total;
}
public static void main(String[] args) {
System.out.println(greet());
System.out.println(greet("佐藤"));
System.out.println(repeat("ab", 3));
System.out.println(sum());
System.out.println(sum(1, 2, 3));
System.out.println(sum(new int[]{10, 20}));
}
}
こんにちは
こんにちは、佐藤さん
ababab
0
6
30
| 書き方 | 定義 | 呼び出し | ポイント |
|---|---|---|---|
| 引数なし | greet() |
greet() |
かっこは省略できない |
| 引数1つ | greet(String name) |
greet("佐藤") |
型ごとに1つずつ書く |
| 引数が複数 | repeat(String s, int times) |
repeat("ab", 3) |
順番どおりに対応する |
| 可変長引数 | sum(int... nums) |
sum()、sum(1, 2, 3) |
メソッドの中では配列として扱う。引数リストの最後に1つだけ書ける |
同じ型が続く場合も (int a, b) とは書けず、(int a, int b) と型を1つずつ書きます。 また、Javaにはデフォルト引数(省略時の値を定義に書く仕組み)がありません。省略できる形にしたいときは、次のオーバーロードを使います。
オーバーロード:同じ名前で引数違いのメソッドを作る
引数の型・個数・並びが違えば、同じ名前のメソッドを複数定義できます。これをオーバーロードと呼びます。 上の greet() と greet(String) もオーバーロードです。どれが呼ばれるかは、渡した値の型で決まります。
public class Overload {
static String show(int n) { return "int: " + n; }
static String show(long n) { return "long: " + n; }
static String show(double d) { return "double: " + d; }
static String show(String s) { return "String: " + s; }
static String show(int a, int b) { return "int,int: " + a + "," + b; }
public static void main(String[] args) {
System.out.println(show(10));
System.out.println(show(10L));
System.out.println(show(2.5));
System.out.println(show("10"));
System.out.println(show(1, 2));
byte b = 5;
System.out.println(show(b)); // byte → int に広げて呼ばれる
System.out.println(show('A')); // char → int に広げて呼ばれる
}
}
int: 10
long: 10
double: 2.5
String: 10
int,int: 1,2
int: 5
int: 65
show(byte) や show(char) は定義していないので、いちばん近い広い型(int)のメソッドが選ばれました。 charの 'A' は文字コードの65として渡されています。
| オーバーロードとして区別されるもの | 区別されないもの |
|---|---|
引数の個数(show(int) と show(int, int)) |
戻り値の型だけの違い |
引数の型(show(int) と show(String)) |
引数の名前だけの違い |
引数の型の並び(f(int, String) と f(String, int)) |
アクセス修飾子だけの違い |
戻り値の型だけを変えて定義すると、次のエラーになります。
static int size(String s) { return s.length(); }
static long size(String s) { return s.length(); }
E10.java:3: error: method size(String) is already defined in class E10
static long size(String s) { return s.length(); }
^
戻り値とreturnの書き方
return 値; は「値を呼び出し元へ返す」と同時に「メソッドをそこで終える」文です。 戻り値の型には、int・boolean・Stringのほか、配列やクラス、recordも指定できます。
import java.util.List;
public class Returns {
// 条件によって早めに返す(早期リターン)
static String grade(int score) {
if (score < 0 || score > 100) {
return "対象外";
}
if (score >= 80) {
return "A";
}
if (score >= 60) {
return "B";
}
return "C";
}
// void メソッドでも return; で途中終了できる
static void printIfNotEmpty(String s) {
if (s == null || s.isEmpty()) {
return;
}
System.out.println("値: " + s);
}
// boolean を返す(名前は is / has で始めると読みやすい)
static boolean isEven(int n) {
return n % 2 == 0;
}
// 配列を返す
static int[] minMax(int[] values) {
int min = values[0];
int max = values[0];
for (int v : values) {
if (v < min) min = v;
if (v > max) max = v;
}
return new int[]{min, max};
}
// record で複数の値に名前を付けて返す
record Stats(int count, double average) {}
static Stats stats(List<Integer> list) {
int sum = 0;
for (int v : list) {
sum += v;
}
return new Stats(list.size(), (double) sum / list.size());
}
public static void main(String[] args) {
System.out.println(grade(85) + " " + grade(60) + " " + grade(10) + " " + grade(120));
printIfNotEmpty("");
printIfNotEmpty("りんご");
System.out.println(isEven(4) + " " + isEven(7));
int[] mm = minMax(new int[]{4, 9, 1, 7});
System.out.println("最小 " + mm[0] + " / 最大 " + mm[1]);
Stats s = stats(List.of(70, 85, 90));
System.out.println(s);
System.out.println(s.count() + "件 平均 " + s.average());
}
}
A B C 対象外
値: りんご
true false
最小 1 / 最大 9
Stats[count=3, average=81.66666666666667]
3件 平均 81.66666666666667
printIfNotEmpty("") は return; で途中終了したため、何も表示していません。
複数の値を返したいとき
Javaのメソッドが返せる値は1つです。複数の結果を返したいときは、1つの入れ物にまとめます。
| 方法 | 書き方の例 | 向いている場面 |
|---|---|---|
| 配列 | return new int[]{min, max}; |
同じ型の値が少数。位置(0番目、1番目)で意味が決まる |
| record | return new Stats(count, average); |
型の違う値や、名前を付けて区別したい値(Java 16以降) |
| クラス | return new Result(...); |
返した後に値を書き換えたい、メソッドも持たせたい |
| List・Map | return List.of(a, b, c); |
個数が決まっていない |
値に名前が付くrecordは、s.count() のように意味の伝わる形で取り出せます。 配列で返す場合は、何番目が何の値かをコメントやメソッド名で伝えると読み手が迷いません。
早期リターンで条件分岐を浅くする
grade メソッドのように、対象外の条件を先に確かめてreturnする書き方を早期リターンと呼びます。 if-elseを入れ子にするよりも、上から順に読めるようになります。最後の return "C"; は「どの条件にも当てはまらなかったとき」の戻り値で、これがあるため、すべての道で値が返ります。
引数に渡した値は変わるか:プリミティブと配列・オブジェクト
Javaの引数は、すべて「値のコピー」を渡します(値渡し)。ただし、配列やオブジェクトの変数に入っている値は「実体のある場所を指す参照」なので、コピーされるのは参照です。 この違いによって、呼び出し元から見た結果が変わります。5つのケースをまとめて動かします。
import java.util.Arrays;
public class PassValue {
static class Item {
String name;
int qty;
Item(String name, int qty) { this.name = name; this.qty = qty; }
@Override public String toString() { return name + " x" + qty; }
}
// 1. プリミティブ型:コピーを書き換えるだけ
static void addTen(int n) {
n += 10;
System.out.println(" メソッド内 n = " + n);
}
// 2. 配列:中身を書き換えると呼び出し元にも見える
static void fillFirst(int[] arr) {
arr[0] = 99;
}
// 3. オブジェクト:フィールドを書き換えると呼び出し元にも見える
static void addQty(Item item) {
item.qty += 10;
}
// 4. 引数の変数に別のものを代入しても、呼び出し元は変わらない
static void replace(int[] arr, Item item) {
arr = new int[]{7, 7, 7};
item = new Item("別の品", 0);
System.out.println(" メソッド内 arr = " + Arrays.toString(arr) + ", item = " + item);
}
// 5. String は変更できない型:連結しても呼び出し元は変わらない
static void appendMark(String s) {
s = s + "!";
System.out.println(" メソッド内 s = " + s);
}
public static void main(String[] args) {
int num = 1;
addTen(num);
System.out.println("1. int : " + num);
int[] data = {1, 2, 3};
fillFirst(data);
System.out.println("2. 配列 : " + Arrays.toString(data));
Item pen = new Item("ペン", 5);
addQty(pen);
System.out.println("3. オブジェクト: " + pen);
replace(data, pen);
System.out.println("4. 再代入後 : " + Arrays.toString(data) + ", " + pen);
String word = "hello";
appendMark(word);
System.out.println("5. String : " + word);
}
}
メソッド内 n = 11
1. int : 1
2. 配列 : [99, 2, 3]
3. オブジェクト: ペン x15
メソッド内 arr = [7, 7, 7], item = 別の品 x0
4. 再代入後 : [99, 2, 3], ペン x15
メソッド内 s = hello!
5. String : hello
結果を表にまとめます。
| ケース | メソッド内でしたこと | 呼び出し元の値 | 理由 |
|---|---|---|---|
| 1. int | n += 10 |
変わらない(1のまま) | 値そのもののコピーを書き換えただけ |
| 2. 配列 | arr[0] = 99 |
変わる([99, 2, 3]) | コピーされた参照が同じ配列を指している |
| 3. オブジェクト | item.qty += 10 |
変わる(x15) | コピーされた参照が同じオブジェクトを指している |
| 4. 引数へ再代入 | arr = new int[]{...} |
変わらない | メソッド内の変数が別のものを指すようになっただけ |
| 5. String | s = s + "!" |
変わらない(helloのまま) | 連結は新しいStringを作る。4と同じ再代入になる |
「引数の変数そのものへの代入」は呼び出し元に届かず、「引数が指している中身の書き換え」は呼び出し元からも見える、と覚えると5つとも説明できます。
flowchart LR
subgraph 呼び出し元
D[data]
end
subgraph メソッド
A[arr]
end
D --> X["配列 {99, 2, 3}"]
A --> X
受け取った配列を書き換えずに結果を返す
呼び出し元のデータを変えたくないときは、メソッドの中でコピーを作り、コピーを加工して返します。
import java.util.Arrays;
public class SafeCopy {
// 受け取った配列は書き換えず、並べ替えた新しい配列を返す
static int[] sorted(int[] src) {
int[] copy = Arrays.copyOf(src, src.length);
Arrays.sort(copy);
return copy;
}
public static void main(String[] args) {
int[] original = {3, 1, 2};
int[] result = sorted(original);
System.out.println("元の配列: " + Arrays.toString(original));
System.out.println("戻り値 : " + Arrays.toString(result));
}
}
元の配列: [3, 1, 2]
戻り値 : [1, 2, 3]
| 設計 | メリット | 向いている場面 |
|---|---|---|
| 引数を書き換える(voidで返さない) | コピーのぶんのメモリを使わない | 「この配列を並べ替える」と名前や説明で明示できるとき |
| コピーを加工して返す | 呼び出し元のデータがそのまま残る | 元のデータを後でも使う、複数の場所から呼ばれるとき |
変数の有効範囲(スコープ)
メソッドの中で宣言した変数(ローカル変数)と引数は、そのメソッドの中だけで使えます。 呼び出しが終わると消え、次の呼び出しでは新しく作られます。
public class Scope {
static int counter = 0; // クラス全体で共有(static フィールド)
static void countUp() {
int local = 0; // 呼ばれるたびに作り直される
local++;
counter++;
System.out.println("local = " + local + ", counter = " + counter);
}
public static void main(String[] args) {
countUp();
countUp();
countUp();
}
}
local = 1, counter = 1
local = 1, counter = 2
local = 1, counter = 3
localは毎回1に戻り、staticフィールドのcounterは呼び出しをまたいで増えています。別のメソッドのローカル変数を使おうとすると、次のエラーになります。
static int total(int a, int b) {
int sum = a + b;
return sum;
}
public static void main(String[] args) {
total(1, 2);
System.out.println(sum);
}
E14.java:8: error: cannot find symbol
System.out.println(sum);
^
symbol: variable sum
location: class E14
メソッドの結果を外で使いたいときは、戻り値として受け取ります(int sum = total(1, 2);)。
よくあるコンパイルエラーと直し方
ここからは、メソッドを書き始めたときによく出会うエラーを、メッセージごとに再現します。
missing return statement
public class E1 {
static int abs(int n) {
if (n < 0) {
return -n;
}
}
public static void main(String[] args) {
System.out.println(abs(-3));
}
}
E1.java:6: error: missing return statement
}
^
1 error
error: compilation failed
nが0以上のとき、returnを通らずにメソッドの終わりに着いてしまいます。戻り値のあるメソッドでは、どの道を通っても必ずreturnに行き着くようにします。
static int abs(int n) {
if (n < 0) {
return -n;
}
return n; // if に当てはまらないときの戻り値
}
incompatible types(戻り値の型が合わない)
戻り値の型と、実際に返している値の型が違うときのメッセージです。パターンごとに並べます。
| コード | メッセージ | 直し方 |
|---|---|---|
static int length(String s) { return s; } |
incompatible types: String cannot be converted to int |
return s.length(); のようにintを返す |
static int half(int n) { return n / 2.0; } |
incompatible types: possible lossy conversion from double to int |
戻り値の型をdoubleにする、または (int) (n / 2.0) とキャストする |
static void hello(String name) { return "..." + name; } |
incompatible types: unexpected return value |
戻り値の型をStringにする |
static int next(int n) { return; } |
incompatible types: missing return value |
return n + 1; のように値を付ける |
実際の表示の例です。
E3.java:3: error: incompatible types: possible lossy conversion from double to int
return n / 2.0;
^
possible lossy conversion は「小数点以下などの情報が失われる可能性がある変換」を知らせるメッセージです。 intからdoubleのように広い型へ返すぶんには自動で変換されますが、逆向きは明示的なキャストが必要です。
cannot be applied to given types(引数が合わない)
引数の個数が違う場合です。
static int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
System.out.println(add(1));
}
E5.java:6: error: method add in class E5 cannot be applied to given types;
System.out.println(add(1));
^
required: int,int
found: int
reason: actual and formal argument lists differ in length
引数の型が違う場合(add("1", 2))は、reasonの行が変わります。
required: int,int
found: String,int
reason: argument mismatch; String cannot be converted to int
required が定義側の型、found が呼び出し側で渡した型です。 この2行を見比べると、足りない引数や型の違いがすぐにわかります。文字列の数字を渡したいときは Integer.parseInt("1") でintに変換します。
non-static method cannot be referenced from a static context
public class E7 {
int twice(int n) {
return n * 2;
}
public static void main(String[] args) {
System.out.println(twice(4));
}
}
E7.java:6: error: non-static method twice(int) cannot be referenced from a static context
System.out.println(twice(4));
^
mainはstaticメソッドなので、インスタンスがない状態で動きます。そこからインスタンスメソッドの twice を直接呼ぶと、「どのインスタンスの twice か」が決まらないためエラーになります。直し方は2通りです。
public class E7Fixed {
int twice(int n) {
return n * 2;
}
static int twiceStatic(int n) {
return n * 2;
}
public static void main(String[] args) {
System.out.println(twiceStatic(4)); // 直し方1:static を付ける
System.out.println(new E7Fixed().twice(4)); // 直し方2:インスタンスを作って呼ぶ
}
}
8
8
| 直し方 | 選ぶ目安 |
|---|---|
メソッドに static を付ける |
フィールドを使わず、引数だけで結果が決まる処理 |
new でインスタンスを作って呼ぶ |
インスタンスのフィールドを読み書きする処理 |
voidメソッドの結果を値として使った
static void log(String msg) {
System.out.println(msg);
}
public static void main(String[] args) {
String s = log("開始");
System.out.println(log("終了"));
}
E8.java:6: error: incompatible types: void cannot be converted to String
String s = log("開始");
^
E8.java:7: error: 'void' type not allowed here
System.out.println(log("終了"));
^
2 errors
voidメソッドは値を返さないので、代入や println の引数には使えません。結果を使いたいなら戻り値の型を付け、表示だけが目的なら log("開始"); と文として呼びます。
そのほかのメッセージ
| メッセージ | 再現したコード | 原因と直し方 |
|---|---|---|
cannot find symbol / symbol: method ad(int,int) |
ad(1, 2)(定義は add) |
メソッド名の書き間違い。symbolの行に、探した名前と引数の型が出る |
illegal start of expression |
mainメソッドの中に static int add(...) { } を定義 |
メソッドの中にメソッドは定義できない。クラス直下へ移す |
reference to show is ambiguous |
show(long, int) と show(int, long) を定義して show(1, 2) |
どちらにも同じ近さで合うため選べない。show(1L, 2) のように型を明示する |
method size(String) is already defined |
戻り値の型だけ違う同名メソッド | 引数の型か個数を変える、または名前を変える |
illegal start of expression のときは、後ろに <identifier> expected や class, interface, enum, or record expected といったエラーも続けて表示されました(今回は合計4件)。複数のエラーが並んだときは、いちばん上の1件から直すと、残りがまとめて消えることがよくあります。
メソッド名の付け方と設計の目安
| 項目 | 慣例・目安 | 例 |
|---|---|---|
| 表記 | 小文字で始め、単語の区切りを大文字にする(ローワーキャメルケース) | calcTotal、findByName |
| 先頭の語 | 動詞から始める | get、set、add、remove、create、find、print |
| booleanを返すメソッド | is/has/can で始める |
isEmpty()、hasNext() |
| 値を変換するメソッド | to で始める |
toString()、toUpperCase() |
| 1つのメソッドの役割 | 1つに絞る | 「計算する」と「表示する」は分ける |
| 引数の個数 | 少なめに保つ | 多くなったらrecordやクラスにまとめる |
計算と表示を分けておくと、計算だけを別の場所でも使えるようになります。 先ほどの total が戻り値を返し、mainが表示を受け持っていたのはこの考え方です。
自分自身を呼び出すメソッド(再帰)
メソッドは、その中から自分自身を呼び出すこともできます。終了条件を先に書くのが決まりごとです。
public class Recursion {
// 自分自身を呼び出すメソッド(再帰)
static long factorial(int n) {
if (n <= 1) {
return 1; // 終了条件
}
return n * factorial(n - 1);
}
public static void main(String[] args) {
System.out.println("5! = " + factorial(5));
System.out.println("10! = " + factorial(10));
}
}
5! = 120
10! = 3628800
factorial(5) は 5 * factorial(4)、factorial(4) は 4 * factorial(3) と順に呼び出され、factorial(1) が1を返したところから掛け算が戻ってきます。
よくある質問
Q. メソッドと関数は違うものですか? A. 「処理に名前を付けて呼び出す」という役割は同じです。Javaでは処理を必ずクラスの中に定義するため、メソッドと呼びます。staticメソッドは、ほかの言語でいう関数に近い使い方ができます。
Q. voidメソッドにreturnは書けますか?
A. 書けます。値を付けずに return; と書くと、その場でメソッドを終えます。条件に合わないときに早めに抜ける書き方でよく使います。値を付けると unexpected return value のコンパイルエラーになります。
Q. 引数に渡した変数がメソッドの中で書き換わることはありますか? A. intなどのプリミティブ型は書き換わりません。配列やオブジェクトは、メソッドの中で要素やフィールドを書き換えると、呼び出し元からも変わって見えます。引数の変数に別の配列やオブジェクトを代入した場合は、呼び出し元には影響しません。
Q. mainメソッドから自作のメソッドを呼ぶとエラーになります。
A. non-static method ... cannot be referenced from a static context と表示されていれば、呼びたいメソッドにstaticが付いていないことが理由です。メソッドに static を付けるか、new クラス名() でインスタンスを作ってから 変数名.メソッド名() で呼びます。
まとめ
- メソッドは
修飾子 戻り値の型 メソッド名(引数) { 処理 }で定義し、メソッド名(値)で呼び出す。 - 戻り値がないときは
void、あるときは型を書いて、すべての道でreturn 値;を書く。 - staticメソッドはそのまま呼べる。インスタンスメソッドは
newしてから変数名.メソッド名()で呼ぶ。 - 引数は型・個数・順番を定義とそろえる。エラーの
requiredとfoundを見比べると違いがわかる。 - 同じ名前でも引数の型や個数が違えば定義できる(オーバーロード)。戻り値の型だけの違いは区別されない。
- プリミティブ型は渡しても呼び出し元は変わらない。配列・オブジェクトは中身を書き換えると呼び出し元にも見える。
- ローカル変数はメソッドの中だけで有効。結果を外で使うときは戻り値で受け取る。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Java メソッドの定義と書き方|引数・戻り値・呼び出しをコード付きで解説」
株式会社RJCでは、Javaのメソッドの定義や引数・戻り値の考え方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。