100本ノック
Java Gold試験において、**関数型インターフェース(Functional Interface)**はすべての基盤です。Stream APIや並列処理のコードが読めるかどうかは、ここを完璧に理解しているかにかかっています。
試験で問われる「引数の数」「戻り値の型」「プリミティブ版の名称」を中心に、100のチェックポイントをまとめました。
1. 4大インターフェースの基本 (1-20)¶
Predicate<T>:引数1つ(T) → 戻り値booleanConsumer<T>:引数1つ(T) → 戻り値void(消費して終わり)Function<T, R>:引数1つ(T) → 戻り値R(変換)Supplier<T>:引数なし → 戻り値T(提供)UnaryOperator<T>:引数1つ(T) → 戻り値T(同型変換。Functionの親戚)@FunctionalInterfaceアノテーション:抽象メソッドが1つであることを保証(必須ではない)- 関数型インターフェースは**抽象メソッドが「1つだけ」**(デフォルトメソッドやstaticメソッドは何個あってもOK)
java.lang.Objectのpublicメソッド(equalsなど)を抽象メソッドとして宣言しても、カウントされない- ラムダ式:
(引数) -> { 処理 } - ラムダ式の型推論:引数の型は省略可能
- 引数が1つの場合、
()は省略可能 - 処理が1文の場合、
{}とreturnと;は省略可能 - ラムダ式内からアクセスできるローカル変数は final または 実質的 final のみ
- メソッド参照:
クラス名::メソッド名またはインスタンス::メソッド名 - 構築参照:
ClassName::new Predicate.and(Predicate):条件の結合 (&&)Predicate.or(Predicate):条件の結合 (||)Predicate.negate():条件の反転 (!)Function.andThen(Function):処理の連鎖(Aの後B)-
Function.compose(Function):処理の連鎖(Bの前A)2. 2引数(Bi)シリーズ (21-40)¶
-
BiPredicate<T, U>:引数2つ →boolean BiConsumer<T, U>:引数2つ →voidBiFunction<T, U, R>:引数2つ →RBinaryOperator<T>:引数2つ(T, T) → 戻り値TBinaryOperatorはBiFunction<T, T, T>を継承しているBiConsumerはMap.forEach((k, v) -> ...)で多用されるBiFunctionはMap.replaceAll((k, v) -> ...)で多用される- 2引数版に
Supplierは存在しない(引数なしが定義のため) -
3引数以上の標準インターフェースは存在しない(自作が必要)
3. プリミティブ特化型 (41-70)¶
試験で最も「差がつく」のはここです。Int, Long, Double の名称を正確に覚えましょう。
IntPredicate,LongPredicate,DoublePredicateIntConsumer,LongConsumer,DoubleConsumerIntSupplier,LongSupplier,DoubleSupplierIntFunction<R>:intを受け取りRを返すToIntFunction<T>:Tを受け取りintを返す(ここがひっかけ!)IntToDoubleFunction:int→doubleIntToLongFunction:int→longObjIntConsumer<T>:Tとintを受け取りvoid(BiConsumerの変種)BooleanSupplier:引数なしでbooleanを返す(Predicateではない!)- プリミティブ版を使う理由は「オートボクシング」による性能低下を防ぐため
- プリミティブPredicateの抽象メソッド名は
test - プリミティブConsumerの抽象メソッド名は
accept - プリミティブSupplierの抽象メソッド名は
getAsInt,getAsBoolean等 -
プリミティブFunctionの抽象メソッド名は
apply,applyAsInt等4. 応用と試験のひっかけ (71-100)¶
-
抽象メソッドがゼロのインターフェースは関数型ではない(Marker Interface)
- 抽象メソッドが2つ以上のインターフェースは関数型ではない
List.removeIf(Predicate)List.replaceAll(UnaryOperator)List.sort(Comparator):Comparatorも関数型インターフェースComparator.comparing(Function)Comparator.thenComparing(Function)Optional.ifPresent(Consumer)Optional.orElseGet(Supplier)Optional.map(Function)Optional.filter(Predicate)- ラムダ式の中でチェック例外を投げる場合は
try-catchが必須 Function.identity():引数をそのまま返す関数- ラムダ式と匿名クラスの違い:
thisの意味(ラムダのthisは囲んでいるクラスを指す) - メソッド参照
String::toUpperCaseはFunction<String, String> - メソッド参照
System.out::printlnはConsumer<String> Comparator.reversed():順序を逆にするComparator.nullsFirst(Comparator)Comparator.nullsLast(Comparator)Stream.generate(Supplier)Stream.iterate(T, UnaryOperator)Stream.allMatch(Predicate)Stream.collect(Collector):Collectorは関数型ではないが内部でSupplier,BiConsumer,BinaryOperatorを使うIterable.forEach(Consumer)Map.computeIfAbsent(K, Function)Map.merge(K, V, BiFunction)- ラムダ式のパラメータ名は、囲んでいるスコープの変数名と重複できない
Predicate.isEqual(Object):staticメソッド- カスタム関数型インターフェースの作成方法
- ラムダ式自体はオブジェクトとして扱える
💡 Java Gold 試験対策の「急所」¶
試験では**「このメソッドの引数に渡せるラムダ式はどれか?」**という形式で、インターフェースの型を特定させる問題が出ます。
特に以下の3つの区別を徹底してください:
- **
Function<T, R>vsUnaryOperator<T>**: 戻り値が引数と同じ型ならUnaryOperatorです。 - **
IntFunction<R>vsToIntFunction<T>**:Intが最初に来るか最後に来るかで「引数」か「戻り値」かが決まります。 - **
SuppliervsConsumer**: 「もらうだけ」か「あげるだけ」か。
まずは 「1. 4大インターフェースの基本 (1-20)」 の具体的なコード例から確認しましょうか?