※ 2019/12/23追記
コードの表記が崩れているご指摘を頂き、該当箇所を修正致しました。
ありがとうございます。
備忘録がてらメモ。
概ね実現したいのはタイトルの通り。
Java8から登場したStreamAPIの[Stream.filter()]は、条件に一致する要素だけをフィルタリングしてくれるとても便利なメソッドだ。
例: Demo1.java
package test; import java.util.Arrays;
public class Demo1 { public static void main(String[] args) { Arrays.asList("hoge", "fuga", "foo", "bar") .stream() .filter("hoge"::equals) .forEach(System.out::println); } }
上記コードを実行すると[hoge]だけが標準出力される。
ちなみに上記の[Stream.filter()]内の["hoge"::equals]は[String.equals(str)]をメソッド参照として記述したものだ。
メソッド参照を使用しない場合は、ラムダ式なら[str -> "hoge".equals(str)]と書くことになる。
では、上記のコードを変更して、条件に一致しなかった物だけをフィルタリングするにはどうすれば良いか。
もちろん書くことは可能だが、メソッド参照が使えなくなってしまう。
例: Demo2.java
public class Demo2 { public static void main(String[] args) { Arrays.asList("hoge", "fuga", "foo", "bar") .stream() .filter(str -> !"hoge".equals(str)) .forEach(System.out::println); } }
上記コードを実行すると、[fuga]、[foo]、[bar]が標準出力される。
ちょっと格好悪いというのと、複雑な条件式になってくると全部を否定するのは間違いを生みそうである。
そこで、以下の様なメソッドを作成する。
例: nagate
@SuppressWarnings("unchecked") public static <T extends Predicate<?>> T nagate(T predicate) { return (T) predicate.negate(); }
これを先ほどのプログラムに組み込むことで、メソッド参照を生かしたまま条件に一致しなかった物だけをフィルタリングできる。
完成したプログラムは以下の通り。
例: Demo3.java
package test; import java.util.Arrays; import java.util.function.Predicate; public class Demo { public static void main(String[] args) { Arrays.asList("hoge", "fuga", "foo", "bar") .stream() .filter(nagate("hoge"::equals)) .forEach(System.out::println); } @SuppressWarnings("unchecked") public static <T extends Predicate<?>> T nagate(T predicate) { return (T) predicate.negate(); } }
上記コードを実行すると、[fuga]、[foo]、[bar]が標準出力される。
ちなみに使用した[Predicate.nagate()]は条件を否定するためのメソッドとして、Java8ではあらかじめ用意されている。
今回作成した[nagate()]の関数はUtil化するなどして、どこからでも使用できる様にしておくと良い。
ちなみにそのクラスを[static import]すると、本当にサンプルプログラムの様にnagate()と書くだけで利用できる様になる。
……ちなみに調べたところ、Java11には[Predicate.not()]というメソッドが追加されている様だ。
これは今回作成した[nagate()]のメソッドと同じ動きをする。