LoginSignup
107

More than 3 years have passed since last update.

Java8のFunction, Consumer, Supplier, Predicateの調査

Last updated at Posted at 2017-09-06

動機

Java8でlambdaとかStreamとか追加クラスとかあるけど、Function, Consumer, Supplier, Predicateなどが基礎になっている気がするのでちゃんと理解する。

Function

使い方

Javaにおけるメソッドの挙動をインスタンスで扱う仕組み。
従来、以下のようにしていたメソッド定義を、

MethodDefinition
R functionName(T arg) {
    return new R();
}

以下のような形で、インスタンス定義に変えることが出来る。

ConventionalDefinition
Function<T, R> functionalInstance = new Function<T, R>() {
    @Override
    public R apply(T arg) {
        return new R();
    }
};

これだと面倒なので、lambda式を使って以下でも良い。

InstanceDefinition
Function<T, R> functionalInstance = arg -> new R();

メソッド定義の場合だと、以下のようにして呼び出ししていたが、

MethodCall
R returnValue = functionName((T) argument);

Functionを使った場合は、applyメソッドを使って、

InstanceCall
R returnValue = functionalInstance.apply((T) argument);

とする。

Javaにおけるメソッドは第一級オブジェクトではないけれど、そういうスタイルを導入しやすいように新しく仕組みを作ったという感じだろうか。

Consumer

Functionが分かればあとは簡単で、Consumerは引数を消費するインスタンスを定義するためのインターフェイス。
引数は取るが返り値は存在しないので、ジェネリクスによる型指定は引数側の一つだけ。

イメージとしては、以下のメソッドのインスタンス版。

void consumer(T arg) {
    something(arg);
}

定義方法は、以下の通り。acceptというメソッドをオーバーライドして挙動を定める。

Consumer<T> consumer = new Consumer<T>() {
    @Override
    public void accept(T arg) {
        something(arg);
    }

lambdaなら、以下。

Consumer<T> consumer = arg -> something(arg);

呼び出しは、以下のように実施する。

consumer.accept((T) argument)

Supplier

Supplierは、引数を取らないが返り値は存在する挙動を定義するためのインターフェイス。

イメージとしては、以下のメソッドのインスタンス版作るためのもの。

T consumer() {
    return new T();
}

以下のように定義する。

Supplier<T> supplier = new Supplier<T>() {
    @Override
    public T get() {
        return new T();
    }
}

lambdaなら以下。

Supplier<T> supplier = () -> new T();

使用する場合は以下のようにする。

supplier.get();

Predicate

Predicateは、ある引数を受け取って、真偽値を返すインターフェース。

// 引数が1だったらtrue、それ以外はfalse
Predicate<Integer> predicate = arg -> arg == 1;

Integer argument = 1;
if (predicate.test(argument)) {
    System.out.println("argument is 1");
} else {
    System.out.println("argument is not 1");
}

という感じで使う。

Function<T, Boolean>に近いと思うが、この場合だとBooleanからbooleanへのアンボクシングが入るので、それを避けるのが一つの目的だろうか。
andとかorというメソッドもあるようだが、あまり使わなさそうなので省略する。

synchronizedについて完全理解したいなら

synchronizedの解説と典型的誤り例
を書いたので、こちらもどうぞ。経験的に、7割くらいの人がなにか間違っています。

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
107