Javaのメソッド参照とコンストラクタ参照の使い方を完全ガイド!初心者向けに::とClass::newを解説
生徒
「Javaのラムダ式を勉強していると、::っていう記号を見かけるんですけど、何なんですか?」
先生
「それはメソッド参照と呼ばれる書き方で、ラムダ式をさらに簡潔に書くための機能なんです。」
生徒
「普通のラムダ式との違いや使い方を教えてもらえますか?」
先生
「もちろん。さらに、Class::newという書き方でコンストラクタも参照できるので、合わせて覚えておくと便利ですよ。」
1. メソッド参照とは?
Javaのメソッド参照(method reference)は、「ラムダ式の中で既存メソッドをそのまま呼ぶだけ」の場面で使える省略記法です。記号::(ダブルコロン)を使い、冗長なラムダを読みやすい1行に置き換えられます。イメージとしては、A::bがx -> A.b(x)の短縮形だと思ってください。
まずは比較から見てみましょう。次のラムダ式は、受け取った名前をそのまま出力しているだけです。
list.forEach(name -> System.out.println(name));
この処理はSystem.outのprintlnを呼び出しているだけなので、::を使って、より簡潔に次のように書けます。
list.forEach(System.out::println);
なぜこれで動くの?――forEachは「1つの文字列を受け取って何かする」役割(Consumer<String>)を期待しています。System.out::printlnも「文字列を1つ受け取って出力する」振る舞いなので、ちょうどピッタリはまり、ラムダの代わりとして使えるのです。
import java.util.*;
public class MethodRefIntro {
public static void main(String[] args) {
List<String> list = Arrays.asList("Java", "ラムダ", "メソッド参照");
// ふつうのラムダ
list.forEach(s -> System.out.println(s));
// メソッド参照で同じ意味(短く読みやすい)
list.forEach(System.out::println);
}
}
Java
ラムダ
メソッド参照
Java
ラムダ
メソッド参照
ポイント
::は「そのメソッドをそのまま使う」の合図。書き換えても意味が変わらないときに使う。- 読みやすさが上がるなら採用、処理が増えるなら従来のラムダ式を使う、という使い分けが基本。
- まずは
forEach(System.out::println)の形で感覚をつかむのがおすすめ。
このように、メソッド参照は「同じ意味をより短く・自然に」表現できる道具です。最初は出力の置き換えから慣れていきましょう。
2. メソッド参照の種類と分類
Javaのメソッド参照は主に4つのパターンに分類されます。
- クラス名::静的メソッド名(例:
Math::abs) - オブジェクト名::インスタンスメソッド名(例:
System.out::println) - クラス名::インスタンスメソッド名(例:
String::length) - クラス名::new(コンストラクタ参照)
このように、用途や呼び出し方に応じて記述方法が異なります。順番に具体例を見ていきましょう。
3. クラス名::静的メソッドの参照
まずは静的メソッドを参照する例です。例えば、絶対値を求めるMath.absメソッドを使いたい場合です。
Function<Integer, Integer> absFunction = Math::abs;
System.out.println(absFunction.apply(-10));
10
このように、関数型インターフェースと組み合わせて使用することで、ラムダ式より短く記述できます。
4. オブジェクト::インスタンスメソッドの参照
既存のオブジェクトがあり、そのメソッドを使いたいときに便利なのがこの書き方です。
Consumer<String> printer = System.out::println;
printer.accept("こんにちは、Javaの世界!");
こんにちは、Javaの世界!
ここでは、System.outというオブジェクトに対してprintlnメソッドを呼び出しています。
5. クラス名::インスタンスメソッドの参照
この書き方は一見不思議に見えますが、引数として渡されたオブジェクトに対してインスタンスメソッドを呼ぶ場合に使えます。
Function<String, Integer> lengthFunc = String::length;
System.out.println(lengthFunc.apply("ラムダ式"));
4
このように、引数がそのまま対象オブジェクトとして使われるときに便利です。
6. コンストラクタ参照(Class::new)の使い方
コンストラクタ参照では、Class::newのように記述することで、オブジェクトの生成をラムダ式のように記述できます。
Supplier<ArrayList<String>> supplier = ArrayList::new;
ArrayList<String> list = supplier.get();
list.add("Java");
System.out.println(list);
[Java]
このように、Supplierインターフェースなどと組み合わせることで、新しいインスタンスを簡単に生成できます。
7. コンストラクタ参照の応用:引数ありのコンストラクタ
引数を受け取るコンストラクタを使いたい場合でも、メソッド参照を使うことができます。以下は、Functionを使った例です。
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String toString() {
return "名前:" + name;
}
}
Function<String, Person> personCreator = Person::new;
Person p = personCreator.apply("山田");
System.out.println(p);
名前:山田
このように、引数のあるコンストラクタでも、関数型インターフェースに合わせて簡潔に記述できます。
8. ラムダ式とメソッド参照の使い分け
ラムダ式とメソッド参照はどちらもJavaでよく使われる記法ですが、以下のような観点で使い分けると良いでしょう。
- 処理が1つのメソッド呼び出しだけなら「メソッド参照」
- 複数行の処理や条件分岐が必要なら「ラムダ式」
コードをより読みやすく、簡潔に保つためには、場面に応じた選択が重要です。
まとめ
この記事で取り上げたのは、「長く書けるけれど、あえて短く丁寧に伝える」ための書き方でした。ラムダ式も便利ですが、ただ既存のメソッドへ渡すだけの場面では、まわりくどく見えることがあります。そんなときにそっと差し替えるのがメソッド参照です。コードの行数が減ること自体より、「何をしたいのか」がパッと伝わることのほうが価値があります。短い記述にしても読み手が迷わないなら、積極的に置き換えていきましょう。
四つの型は覚え方にコツがあります。クラス名から直接呼べるものはそのまま書き、手元のオブジェクトがあるならそれを左側に置きます。引数で渡ってくる値に対して呼ぶならクラス名::メソッド名、そして新しいインスタンスを作るなら::new。これだけの工夫で、毎日の処理が少しずつ軽くなります。大切なのは「全部を参照にする」のではなく、読みやすさが上がるところだけ選ぶ姿勢です。
また、コンストラクタ参照は思った以上に使いどころがあります。必要になるまで作らない、作り方をひとつにまとめる、あとから差し替えられる――この三つが揃うだけで、テストもリファクタリングも楽になります。使い始めはArrayListやRandomのような身近な型からで十分です。慣れてきたら、引数つきのコンストラクタにも広げていけば、自然と手になじみます。
小さい置き換えから試すミニ手順
- 出力・長さ取得・空文字判定・生成の4箇所を探す
- 意味が変わらないことを確認してメソッド参照へ置換
- 読みづらくなったらすぐラムダへ戻し、理由をメモする
- チームで「どこを参照にするか」の目安を軽く共有する
import java.util.*;
import java.util.function.*;
public class WrapUpSample {
public static void main(String[] args) {
List<String> raw = Arrays.asList(" Java ", "", "Method", " ");
raw.stream()
.map(String::trim) // 余白を落とす(参照)
.filter(s -> !s.isEmpty()) // 空を除く(意図が見えるラムダ)
.map(String::toUpperCase) // 大文字へ(参照)
.forEach(System.out::println); // 出力(参照)
}
}
「参照にできる所は短く、説明したい所はラムダで素直に」。このバランスが保てているかを、仕上げのチェックポイントにしておくと安心です。
生徒
「書き換えたあと、読むスピードが上がった気がします。特に出力と長さ取得は参照にすると目が止まらないですね。」
先生
「そうそう。“考えなくていい所”を軽くするのが狙いです。逆に、条件や前処理はラムダでちゃんと見えるようにしておくと、あとで読み返しても迷いません。」
生徒
「コンストラクタ参照も、必要になったときだけ作るっていう発想がしっくりきました。生成の決まりをひとつにまとめられるのが良いですね。」
先生
「まずはArrayList::newのような身近な所からで十分。慣れてきたら引数つきも試してみましょう。大事なのは、短さより“伝わりやすさ”。今日はそこが一番の学びでしたね。」