Java 8では、メソッド参照を使用してストリームをフィルタリングできます。次に例を示します。
Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();
既存のものの否定である、すなわち次のようなものであるメソッド参照を作成する方法はありますか?
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
私は以下のようにnot
メソッドを作成することができましたが、JDKが似たようなものを提供してくれるかどうか疑問に思いました。
static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }
メソッド参照をインラインで使用できるように、以下を静的インポートすることを計画しています。
public static <T> Predicate<T> not(Predicate<T> t) {
return t.negate();
}
例えば.
Stream<String> s = ...;
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
アップデート: - JDK/11は 同様の解決策を提供している可能性があります も同様です。
現在のメソッド参照とは反対のメソッド参照を作成する方法があります。以下の@ vlasecの回答を参照してください。これは、メソッド参照をPredicate
に明示的にキャストしてから、negate
関数を使用して変換する方法を示しています。それは、他のいくつかの方法の中の1つですが、それを実行するのは面倒なことではありません。
これの反対:
Stream<String> s = ...;
int emptyStrings = s.filter(String::isEmpty).count();
これは:
Stream<String> s = ...;
int notEmptyStrings = s.filter(((Predicate<String>) String::isEmpty).negate()).count()
またはこれ:
Stream<String> s = ...;
int notEmptyStrings = s.filter( it -> !it.isEmpty() ).count();
個人的には、長い冗長な明示的キャストよりit -> !it.isEmpty()
を読んだ後に否定するほうが明確であると思うので、私は後者の手法を好みます。
述語を作り、それを再利用することもできます。
Predicate<String> notEmpty = (String it) -> !it.isEmpty();
Stream<String> s = ...;
int notEmptyStrings = s.filter(notEmpty).count();
あるいは、コレクションや配列を持っている場合は、単純で、オーバーヘッドが少なく、*高速**のようにforループを使用するだけです。
int notEmpty = 0;
for(String s : list) if(!s.isEmpty()) notEmpty++;
*何が速いのか知りたい場合は、JMH http://openjdk.Java.net/projects/code-tools/jmh を使用してください。すべてのJVM最適化を回避しない限り、手動のベンチマークコードは避けてください。 Java 8:Streams vs Collectionsのパフォーマンスを参照してください
** for-loopテクニックが速いことを示唆したことで、私は気まぐれになっています。それはストリームの作成を排除し、それは別のメソッド呼び出し(述語に対する負の関数)の使用を排除し、そしてそれは一時的なアキュムレータリスト/カウンタを排除する。そのため、最後の構成要素によって節約されるいくつかの点で、速度が上がる可能性があります。
私はそれがもっと速くなくても、もっとシンプルでより良いと思います。仕事がハンマーと釘を要求するならば、チェーンソーを持って来て、接着剤を使わないでください!私はあなたの何人かがそれを問題にしているのを知っています。
wish-list:Javaユーザーが慣れ親しんだ今、JavaのStream
関数が少し進化するのを見たいです。たとえば、Streamの 'count'メソッドはPredicate
を受け取ることができるので、これは次のように直接実行できます。
Stream<String> s = ...;
int notEmptyStrings = s.count(it -> !it.isEmpty());
or
List<String> list = ...;
int notEmptyStrings = lists.count(it -> !it.isEmpty());
Predicate
には、メソッドand
、or
、およびnegate
があります。
しかし、String::isEmpty
はPredicate
ではなく、単なるString -> Boolean
ラムダであり、それでも何かになる可能性があります。 Function<String, Boolean>
。型推論が最初に起こる必要があるものです。 filter
メソッドは型を暗黙的にと推測します。しかし、引数として渡す前にそれを否定すると、それは起こりません。 @axtavtが述べたように、explicit推論は醜い方法として使用できます。
s.filter(((Predicate<String>) String::isEmpty).negate()).count()
他の答えでは他にもアドバイスがありますが、静的not
メソッドとラムダが最も良い考えです。 これでtl; drセクションが終わります。
しかし、ラムダ型推論についてもっと深く理解したいのであれば、例を使ってもう少し詳しく説明したいと思います。これらを見て、何が起こるのか把握しよう。
Object obj1 = String::isEmpty;
Predicate<String> p1 = s -> s.isEmpty();
Function<String, Boolean> f1 = String::isEmpty;
Object obj2 = p1;
Function<String, Boolean> f2 = (Function<String, Boolean>) obj2;
Function<String, Boolean> f3 = p1::test;
Predicate<Integer> p2 = s -> s.isEmpty();
Predicate<Integer> p3 = String::isEmpty;
Predicate
をObject
にキャストします - ばかげているが有効Predicate
をFunction
にキャストすることはできませんtest
を呼び出しますInteger
はisEmpty
メソッドを持っていませんInteger
引数を持つString::isEmpty
静的メソッドはありませんこれが型推論がどのように機能するのかについてのさらなる洞察を得るのに役立つことを願っています。
他人の答えと個人的な経験に基づいて構築する:
Predicate<String> blank = String::isEmpty;
content.stream()
.filter(blank.negate())
もう1つの選択肢は、あいまいでないコンテキストで1つのクラスにラムダキャストを利用することです。
public static class Lambdas {
public static <T> Predicate<T> as(Predicate<T> predicate){
return predicate;
}
public static <T> Consumer<T> as(Consumer<T> consumer){
return consumer;
}
public static <T> Supplier<T> as(Supplier<T> supplier){
return supplier;
}
public static <T, R> Function<T, R> as(Function<T, R> function){
return function;
}
}
...その後、ユーティリティクラスを静的にインポートします。
stream.filter(as(String::isEmpty).negate())
Predicate#negate
はあなたが探しているものではないはずですか?
この場合、uはorg.Apache.commons.lang3.StringUtils
を使用できます。
int nonEmptyStrings = s.filter(StringUtils::isNotEmpty).count();
Eclipseコレクション から 述語 を使用できます。
MutableList<String> strings = Lists.mutable.empty();
int nonEmptyStrings = strings.count(Predicates.not(String::isEmpty));
List
から文字列を変更できない場合:
List<String> strings = new ArrayList<>();
int nonEmptyStrings = ListAdapter.adapt(strings).count(Predicates.not(String::isEmpty));
String.isEmpty()
の否定だけが必要な場合は、StringPredicates.notEmpty()
を使うこともできます。
注:私はEclipseコレクションの寄稿者です。
私は(Askarの提案に触発された)完全なユーティリティクラスを書きました。それはJava 8ラムダ式を取り(もしあれば)パッケージJava.util.function
で定義された任意の型付き標準Java 8ラムダに変換できます。あなたは例えばすることができます:
asPredicate(String::isEmpty).negate()
asBiPredicate(String::equals).negate()
すべての静的メソッドにas()
という名前を付けると、あいまいさが非常に多くなるため、「as」に続けて返される型を呼び出すことにしました。これにより、ラムダ解釈を完全に制御できます。以下は、使用されているパターンを明らかにした(多少大きい)ユーティリティクラスの最初の部分です。
ここで 完全なクラスを見てください (要点)。
public class FunctionCastUtil {
public static <T, U> BiConsumer<T, U> asBiConsumer(BiConsumer<T, U> biConsumer) {
return biConsumer;
}
public static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> biFunction) {
return biFunction;
}
public static <T> BinaryOperator<T> asBinaryOperator(BinaryOperator<T> binaryOperator) {
return binaryOperator;
}
... and so on...
}
あなたは長いemptyStrings = s.filter(s->!s.isEmpty()).count();
としてこれを達成することができます
Spring Boot(2.0.0+)を使っているのなら、
import org.springframework.util.StringUtils;
...
.filter(StringUtils::hasLength)
...
それは:return (str != null && !str.isEmpty());
それでisEmpty
に必要な否定効果があります