3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

主要な関数型インタフェースと役割

Last updated at Posted at 2025-04-21

はじめに

本記事ではJavaのラムダ式および関数型インタフェースについて、主要な関数型インタフェースとその具体例について説明していきます。

ラムダ式の基本とその背景について知りたい方は、こちらの記事を参考にしてください。
ラムダ式の基本とその背景

対象者

・ラムダ式および関数型インタフェースを初めて学ぶ初心者
・基礎的な知識を習得済みで、再確認や実践例を通じて理解を深めたい方

関数型インタフェースの実践例

主要な関数型インタフェースの種類とその使い方

Java SEでは汎用性の高い関数型インタフェースがクラスライブラリとしてあらかじめ用意されています。
これらを使用すれば、複雑な処理を除いて開発者自身で関数型インタフェースを定義する必要がなくなります。
特に主要なものは以下の通り。

【主要な関数型インタフェース】

分類 関数型インタフェース 抽象メソッド 説明
引数なし、戻り値なし Runnable void run() 任意の処理を実行する
引数なし、戻り値あり Supplier<T> T get() 任意の処理を実行し、結果を返す
引数あり、戻り値なし Consumer<T> void accept(T) 指定された引数で、任意の処理を実行する(戻り値なし)
BiConsumer<T,U> void accept(T, U) 指定された2つの引数で、任意の処理を実行する(戻り値なし)
引数あり、戻り値あり Function<T,R> R apply(T) 指定された引数で、任意の処理を実行し、結果を返す
BiFunction<T,U,R> R apply(T, U) 指定された2つの引数で、任意の処理を実行し、結果を返す
Predicate<T> boolean test(T) 指定された引数で、任意の判定処理を行い、結果をboolean型で返す
BiPredicate<T,U> boolean test(T, U) 指定された2つの引数で、任意の判定処理を行い、結果をboolean型で返す
UnaryOperator<T> T apply(T) 指定された引数に対して何らかの演算処理を行い、その結果を返す。
※引数と戻り値が同一のFunctionインタフェースと同様
BinaryOperator<T> T apply(T, T) 指定された2つの引数に対して何らかの演算処理を行い、その結果を返す。
※2つの引数と戻り値がすべて同一のBiFunctionインタフェースと同様

今回は上記のうち、RunnableSupplierConsumerFunctionPredicateの5つについて具体例を交えて触れてみたいと思います。
尚、本記事では具体例について触れませんが、BiConsumerBiFunctionなど、引数を2つ取るインタフェースもあらかじめ用意されています。

Runnableインタフェース

Runnableインタフェースは「引数なし、戻り値なし」の関数型インタフェースです。
主にスレッドプログラミングで使用されますが、それ以外のケースでも使用可能です。

以下はRunnableインタフェースをラムダ式で実装し、Hello, World!を出力する処理を代入しています。
Runnableインタフェースのrunメソッドを実行することで、処理が行われます。

【Runnableの具体例①】

public class RunnableExample1 {
    public static void main(String[] args) {
    	Runnable task = () -> System.out.println("Hello, World!");
    	task.run();
    }
}

【出力結果】

Hello, World!

以下は複数のスレッドを使用して、複数のタスクを実行する例になります。

【Runnableの具体例②】

public class RunnableExample2 {
    public static void main(String[] args) {
        // Runnableを実装したタスク1
        Runnable task1 = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Task 1: Count " + i);
                try {
                    Thread.sleep(400); // 0.4秒間停止
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        // Runnableを実装したタスク2
        Runnable task2 = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Task 2: Count " + i);
                try {
                    Thread.sleep(600);// 0.6秒間停止
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        // Threadにタスクを登録して実行
        Thread thread1 = new Thread(task1);
        Thread thread2 = new Thread(task2);

        thread1.start();
        thread2.start();
    }
}

【出力結果】

Task 1: Count 0
Task 2: Count 0
Task 1: Count 1
Task 2: Count 1
Task 1: Count 2
Task 2: Count 2
Task 1: Count 3
Task 1: Count 4
Task 2: Count 3
Task 2: Count 4

※スレッドの実行順序やタイミングは保証されません。(スケジューリングによるため)

Supplierインタフェース

Supplierインタフェースは「引数なし、戻り値あり」の関数型インタフェースです。
戻り値を一つ返すため、様々な値を取得する際に使用されます。

以下はSupplierインタフェースをラムダ式で実装し、Hello, World!を出力する処理を代入しています。
Supplierインタフェースのgetメソッドを実行することで、処理が行われます。

【Supplierの具体例①】

public class SupplierExample1 {
    public static void main(String[] args) {
    	Supplier<String> stringSupplier = () -> "Hello, World!";
    	String s = stringSupplier.get();
    	System.out.println(s);
    }
}

【出力結果】

Hello, World!

以下は現在時刻を取得する例になります。

【Supplierの具体例②】

public class SupplierExample2 {
    public static void main(String[] args) {
        Supplier<Long> currentTimeSupplier = () -> System.currentTimeMillis();
        Long currentTime = currentTimeSupplier.get();
        System.out.println("Current Time: " + currentTime);
    }
}

【出力結果】

Current Time: 1743750478216

Consumerインタフェース

Consumerインタフェースは「引数あり、戻り値なし」の関数型インタフェースです。
引数は一つ受け取りますが、戻り値は返さないため、何かしらの副作用を発生させるために使用されます。

以下はConsumerインタフェースをラムダ式で実装し、変数:messageを出力する処理を代入しています。
Consumerインタフェースのacceptメソッドを実行することで、処理が行われます。

【Consumerの具体例①】

public class ConsumerExample1 {
    public static void main(String[] args) {
        Consumer<String> c = message -> System.out.println(message);
        c.accept("Hello, World!");
    }
}

【出力結果】

Hello, World!

以下はリスト内の各要素を大文字に変換して出力する例です。
IterableインタフェースのforEachメソッドにConsumer型の変数:printUpperCaseを渡していますが、これはIterableインタフェースにforEachメソッドがデフォルト実装として提供されており、引数としてConsumerを受け取るように設計されているためです。

【Consumerの具体例②】

public class ConsumerExample2 {
    public static void main(String[] args) { 
        List<String> cities = Arrays.asList("Tokyo", "Osaka", "Chiba");
        Consumer<String> printUpperCase = city -> System.out.println(city.toUpperCase());
        cities.forEach(printUpperCase);
    }
}

【出力結果】

TOKYO
OSAKA
CHIBA

Functionインタフェース

Functionインタフェースは「引数あり、戻り値あり」の関数型インタフェースです。
引数を一つ受け取り、戻り値も一つ返すため、数値の計算結果の取得や文字列の長さの取得等に使用できます。

以下はFunctionインタフェースをラムダ式で実装し、applyメソッドを実行することで商品の価格から消費税込みの価格を計算しています。
Function<T,R>Tは引数、Rは戻り値ですので、以下の場合はともにDouble型を指定しています。

【Functionの具体例①】

public class FunctionExample1 {
    public static void main(String[] args) {
    	double taxRate = 1.08;
        Function<Double, Double> taxFunction = (price) -> price * taxRate;
        double price = 1000.0;
        double taxPrice = taxFunction.apply(price);
        System.out.println(taxPrice);
    }
}

【出力結果】

1080.0

以下はString型の文字列を受け取り、その長さを返す例です。
返す値は数値のため、戻り値の方はInteger型を指定しています。

【Functionの具体例②】

public class FunctionExample2 {
    public static void main(String[] args) {
        Function<String, Integer> lengthFunction = (String str) -> str.length();
        Integer length = lengthFunction.apply("Hello");
        System.out.println(length);
    }
}

【出力結果】

5

Predicateインタフェース

Predicateインタフェースは「引数あり、戻り値あり」の関数型インタフェースです。
引数を一つ受け取り、何らかの処理を行った上で結果をboolean型で返却します。

以下の例では数値が偶数かどうかを判定しています。
Predicateインタフェースのtestメソッドを実行することで判定を行っています。

【Predicateの具体例①】

public class PredicateExample1 {
    public static void main(String[] args) {
        Predicate<Integer> isEven = n -> n % 2 == 0;
        System.out.println(isEven.test(4));
        System.out.println(isEven.test(7));
    }
}

【出力結果】

true
false

また、以下の例では文字列が空かどうかを判定しています。

【Predicateの具体例②】

public class PredicateExample2 {
    public static void main(String[] args) {
        Predicate<String> isEmpty = str -> str.isEmpty();
        System.out.println(isEmpty.test(""));
        System.out.println(isEmpty.test("Hello"));
    }
}

【出力結果】

true
false

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

java.util.functionパッケージには、引数や戻り値が特定のプリミティブ型に特化した専用のインタフェースが用意されています。
本記事では具体例について触れませんが、以下に代表的なものを示しておきます。

Supplierインタフェースの特化型

引数 戻り値 インタフェース
なし int型 IntSupplier
なし long型 LongSupplier
なし double型 DoubleSupplier

Consumerインタフェースの特化型

引数 戻り値 インタフェース
int型 なし IntConsumer
long型 なし LongConsumer
double型 なし DoubleConsumer

Functionインタフェースの特化型

引数 戻り値 インタフェース
int型 総称型 IntFunction<R>
long型 総称型 LongFunction<R>
double型 総称型 DoubleFunction<R>
総称型 int型 ToIntFunction<T>
総称型 long型 ToLongFunction<T>
総称型 double型 ToDoubleFunction<T>

Predicateインタフェースの特化型

引数 戻り値 インタフェース
int型 boolean型 IntPredicate
long型 boolean型 LongPredicate
double型 boolean型 DoublePredicate
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?