0
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?

More than 3 years have passed since last update.

Java8 ラムダ式の filter() で使用する条件をパラメータで渡す

Posted at

ラムダ式は変数に代入して再利用することができますが、そのフィルタ条件などは固定されています。
Java8 ラムダ式を変数に代入して再利用する

そのため、そのフィルタ条件を変えたい場合、別々の式を定義する必要があるかもしれません。
例えば、
”文字列の長さが5の文字列のみ”をフィルタするラムダ式と、
”文字列の長さが8の文字列のみ”をフィルタするラムダ式が欲しい場合、以下のように2つの式を定義する方法が考えられます。

lengthFiveOrEight
// 文字列の長さが5
final Predicate<String> lengthEqualFive = name -> name.length() == 5;
// 文字列の長さが8
final Predicate<String> lengthEqualEight = name -> name.length() == 8;

条件が常に固定であれば問題ありませんが、そのアプリケーションが柔軟に条件の変更をしたい場合、その数だけ式を定義することになるかもしれません。

この条件(この例では5か8)をパラメータとして受け取ることが出来れば、このような重複を避けることが出来ます。
例えば、以下のようなメソッドを定義する方法が考えられます。

lengthEqualWith
Predicate<String> lengthEqualWith(final Integer expectsLength) {
  return name -> name.length == expectsLength;
}

単にラムダ式を変数に代入する代わりに、ラムダ式を返すメソッドに引数を渡し、その引数をラムダ式に適用するような形です。
lengthEqualWith() を呼び出す時に、expectsLength をパラメータとして渡してあげることで、柔軟に条件を変更することが可能となります。

以下のリストを使ってフィルタしてみます。

final List<String> months = 
Arrays.asList("January", "February", "March", "April", "May", "June", "July", "Augast", "September", "October", "November", "December");

以下のように lengthEqualWith(N) を適用しています。

System.out.println("Length is 5");
List<String> result1 = months.stream().filter(lengthEqualWith(5)).collect(Collectors.toList());
result1.forEach(System.out::println);
		
System.out.println("Length is 8");
List<String> result2 = months.stream().filter(lengthEqualWith(8)).collect(Collectors.toList());
result2.forEach(System.out::println);

以下のような(期待通りの)結果が得られます。

Length is 5
March
April
Length is 8
February
November
December

このラムダ式は expectsLength 変数をスコープ内で探しますが、このスコープのことを静的スコープ(または構文スコープ)と呼ばれるようです。
expectsLength 変数がスコープ内に存在(キャッシュ)していれば、ラムダ式はその値を使います。

今回の例では、lengthEqualWith() メソッド内部がその静的スコープになります。
ラムダ式は final のローカル変数にしかアクセスできないため、expectsLength 変数は final である必要があります。

たとえ、final と宣言されていなくとも、final である条件が満たされていれば(つまり、その変数が初期化されており、不変であれば)動作するようです。

ただ、Java としてはそれらの条件が満たされているかを評価する必要がある(コストがかかる)ため、こういった値をキャッシュするのとしないのでは、パフォーマンスに若干の違いが出るかもしれません。

0
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
0
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?