Kodrill

関数型インタフェースとラムダ式

Java SE 17 Gold (1Z0-826-JPN) 試験

内部クラス・static なネストしたクラス・無名クラス/関数型インタフェースの定義/ラムダ式とメソッド参照/Predicate・Consumer・Function・Supplier

問題数
18 問
合格ライン
65%
実行して確認済み
15 問
この分野の要点を読む6 章・約 18 分。実行して確かめたコード例と、試験でよくある引っかけをまとめています

ログインなしで試す

無料の 5 問を、1問ごとに正誤と解説を見ながら解けます。解答は保存されません。

5 問を試す

無料登録して学習を記録する

学習履歴・ダッシュボード・ブックマーク・模試モードが使えます。

★ 残り 13 問はプレミアム会員限定です

無料プランでは先頭 5 問まで解けます。プレミアムなら全問題・苦手問題の復習・広告非表示が使えます。
料金プランを見る

問題と解説を見る (無料)

登録しなくても、次の5問は問題文と解説をそのまま読めます。

関数型インタフェースとラムダ式の要点

内容の確認日: 2026-10-04

この分野では、ラムダ式とメソッド参照の書き方に加えて、その土台になるネストしたクラス (内部クラス・static なネストしたクラス・無名クラス) と、java.util.function パッケージの関数型インタフェースが問われます。次の分野の Stream API はラムダ式を前提にしているので、ここでしっかり固めておきましょう。

出題項目は「内部クラス (内部クラス, static な内部クラス, 無名クラス) の使用」「関数型インタフェースの定義とインスタンス化」「ラムダ式とメソッド参照の使用」「java.util.function パッケージの主要なインタフェース (Predicate, Consumer, Function, Supplier) の使用」の 4 つです。

ネストしたクラス

クラスの中に宣言したクラスには、次の種類があります。

・内部クラス (static でないメンバークラス): 外側のクラスのインスタンスに結び付く。outer.new Inner() のように、外側のインスタンスを使って生成する。外側の private なメンバーも使える ・static なネストしたクラス: 外側のインスタンスと結び付かない。new Outer.Nested() で生成でき、外側の static なメンバーだけを直接使える ・ローカルクラス: メソッドの中で宣言したクラス ・無名クラス: new インタフェース名() { ... } のように、名前を付けずに宣言と生成を同時に行うクラス

内部クラスの中で、外側のクラスのフィールドが同じ名前で隠れている場合は、外側のクラス名.this.フィールド名 で外側のものを指定できます。

Main.java
public class Main {    private int value = 10;    private static int count = 1;​    class Inner {        int value = 20;​        void show() {            int value = 30;            System.out.println(value + " " + this.value + " " + Main.this.value);        }    }​    static class Nested {        void show() {            System.out.println("count = " + count);        }    }​    public static void main(String[] args) {        Main outer = new Main();        Main.Inner inner = outer.new Inner();        inner.show();        new Main.Nested().show();    }}
ターミナル
java Main
30 20 10
count = 1

無名クラスやラムダ式の中から使えるローカル変数は、final か実質的に final (宣言後に一度も代入し直していない) な変数だけです。後から代入し直すと、ラムダ式の中で使っている箇所がコンパイルエラーになります。

Main.java
public class Main {    public static void main(String[] args) {        int base = 10;        Runnable r = () -> System.out.println(base);        base = 20;        r.run();    }}
ターミナル
javac Main.java

コンパイルエラー (4 行目): base は 5 行目で代入し直しているので実質的に final ではなく、ラムダ式の中で使えない

関数型インタフェース

関数型インタフェースは、抽象メソッドをちょうど 1 つだけ持つインタフェースです。ラムダ式やメソッド参照は、関数型インタフェースの型の値として使います。default メソッドと static メソッドはいくつあっても構いません。また、equals のように Object クラスにある public メソッドと同じシグネチャの抽象メソッドは、数に含めません。

@FunctionalInterface を付けると、条件を満たしているかをコンパイラが確かめ、抽象メソッドが 0 個や 2 個以上ならコンパイルエラーにします。付けなくても条件を満たしていれば関数型インタフェースとして使えます。型パラメータを持つ関数型インタフェースも定義できます。

Main.java
@FunctionalInterfaceinterface Converter<T, R> {    R convert(T value);​    default Converter<T, String> describe() {        return v -> "[" + convert(v) + "]";    }​    boolean equals(Object o);}​public class Main {    public static void main(String[] args) {        Converter<String, Integer> length = String::length;        System.out.println(length.convert("Gold"));        System.out.println(length.describe().convert("Java"));    }}
ターミナル
java Main
4
[4]

ラムダ式の書き方とスコープ

ラムダ式は (引数) -> 処理 の形で書きます。主な省略のルールは次のとおりです。

・引数の型は省略できる。書く場合はすべての引数に書く (一部だけは不可)。Java SE 11 からは (var a, var b) のように var も使える ・引数が 1 つで型を書かない場合だけ、( ) を省略できる ・処理が 1 つの式なら { } と return を省略できる。{ } を書いたら、値を返すには return が必要

ラムダ式は新しいスコープを作らず、囲んでいるメソッドと同じスコープにあるとみなされます。そのため、ラムダ式の引数に、メソッドのローカル変数と同じ名前は使えません。また、ラムダ式の中の this は、ラムダ式を囲んでいるクラスのインスタンスを指します (無名クラスの中の this は、無名クラス自身のインスタンスです)。

Main.java
import java.util.function.Function;​public class Main {    public static void main(String[] args) {        String s = "x";        Function<String, Integer> f = s -> s.length();        System.out.println(f.apply("abc"));    }}
ターミナル
javac Main.java

コンパイルエラー (6 行目): ラムダ式の引数 s が、同じスコープのローカル変数 s と重複している

メソッド参照

処理が既存のメソッドを呼ぶだけなら、ラムダ式の代わりにメソッド参照 (クラス名::メソッド名 など) を使えます。次の 4 種類があります。

・static メソッドの参照: Integer::parseInt (s -> Integer.parseInt(s) と同じ) ・特定のオブジェクトのメソッドの参照: System.out::println (x -> System.out.println(x) と同じ) ・任意のオブジェクトのメソッドの参照: String::toUpperCase (s -> s.toUpperCase())。String::startsWith は (s, prefix) -> s.startsWith(prefix) のように、第 1 引数がメソッドを呼ぶ対象になる ・コンストラクタの参照: ArrayList::new (() -> new ArrayList<>() と同じ)

Main.java
import java.util.ArrayList;import java.util.List;import java.util.function.BiPredicate;import java.util.function.Function;import java.util.function.Supplier;​public class Main {    public static void main(String[] args) {        Function<String, Integer> parse = Integer::parseInt;        BiPredicate<String, String> starts = String::startsWith;        Supplier<List<String>> maker = ArrayList::new;        Function<String, String> upper = String::toUpperCase;​        List<String> list = maker.get();        list.add(upper.apply("java"));        System.out.println(parse.apply("41") + 1);        System.out.println(starts.test("Gold", "Go"));        System.out.println(list);    }}
ターミナル
java Main
42
true
[JAVA]

式::メソッド名 の形のメソッド参照では、:: の左側の式はメソッド参照を作った時点で評価されます。その後で変数に別のオブジェクトを代入しても、メソッド参照が使うのは最初のオブジェクトです (ラムダ式と違い、変数が実質的に final である必要もありません)。

Main.java
import java.util.function.Supplier;​public class Main {    public static void main(String[] args) {        StringBuilder sb = new StringBuilder("ab");        Supplier<Integer> length = sb::length;        sb = new StringBuilder("abcde");        System.out.println(length.get());    }}
ターミナル
java Main
2

java.util.function の主なインタフェース

主なインタフェースと、その抽象メソッドの名前は次のとおりです。メソッド名はよく問われるので、正確に覚えましょう。

・Supplier<T>: 引数なしで値を返す。T get() ・Consumer<T>: 値を受け取り、何も返さない。void accept(T t) ・Predicate<T>: 値を受け取り、boolean を返す。boolean test(T t) ・Function<T, R>: 値を変換する。R apply(T t) ・UnaryOperator<T>: 同じ型に変換する (Function<T, T> のサブインタフェース) ・BinaryOperator<T>: 同じ型の 2 つの値から同じ型の値を作る (BiFunction<T, T, T> のサブインタフェース) ・BiConsumer・BiPredicate・BiFunction: 引数が 2 つの版

プリミティブ型に特化したインタフェースは、メソッド名が変わるものがあります。IntPredicate は test、IntFunction<R> は apply のままですが、ToIntFunction<T> は applyAsInt、IntSupplier は getAsInt です。

インタフェースには、関数を組み合わせる default メソッドがあります。Function の f.andThen(g) は f の後に g、f.compose(g) は g の後に f を適用します。Predicate は and・or・negate で条件を組み合わせられます。

Main.java
import java.util.Comparator;import java.util.function.BinaryOperator;import java.util.function.Function;import java.util.function.Predicate;import java.util.function.ToIntFunction;​public class Main {    public static void main(String[] args) {        Function<Integer, Integer> plus2 = n -> n + 2;        Function<Integer, Integer> times3 = n -> n * 3;        System.out.println(plus2.andThen(times3).apply(1));        System.out.println(plus2.compose(times3).apply(1));​        Predicate<String> empty = String::isEmpty;        Predicate<String> shortWord = s -> s.length() <= 3;        Predicate<String> p = empty.negate().and(shortWord);        System.out.println(p.test("") + " " + p.test("abc") + " " + p.test("abcd"));​        BinaryOperator<Integer> min = BinaryOperator.minBy(Comparator.naturalOrder());        System.out.println(min.apply(5, 3));​        ToIntFunction<String> length = String::length;        System.out.println(length.applyAsInt("lambda"));    }}
ターミナル
java Main
9
5
false true false
3
6

plus2.andThen(times3) は (1 + 2) * 3 = 9、plus2.compose(times3) は 1 * 3 + 2 = 5 です。

試験でよくある引っかけ

  • 内部クラスの生成

    static でない内部クラスは、outer.new Inner() のように外側のインスタンスが必要です。static なネストしたクラスは new Outer.Nested() で作れます。

  • 実質的に final

    ラムダ式・無名クラスから使うローカル変数は、後から代入し直すとコンパイルエラーです。代入がラムダ式より後にあっても同じです。

  • 関数型インタフェースの抽象メソッドの数

    default・static メソッドと、Object の public メソッドと同じ抽象メソッドは数えません。残りがちょうど 1 つなら関数型インタフェースです。

  • ラムダ式の引数名

    囲んでいるメソッドのローカル変数と同じ名前の引数は、コンパイルエラーです。

  • andThen と compose の順番

    f.andThen(g) は f → g、f.compose(g) は g → f の順に適用します。

  • プリミティブ型の関数型インタフェース

    ToIntFunction は applyAsInt、IntSupplier は getAsInt です。apply や get ではありません。

問題で確認する

この分野の問題を、解説つきで読めます (登録不要)。

出典・参考

コード例は、試験の対象バージョンで実際にコンパイル・実行して結果を確認しています。